命令注入(Command Injection):是指通过提交恶意构造的参数破坏命令语句结构,从而达到执行恶意命令的目的。
前面的基础课程中,我们提到命令注入需要三个条件:
1. 是否调用系统命令?
2. 函数/参数是否可控?
3. 是否拼接输入?
具体怎么应用,我们在接下去的实战中学习和体会。
DVWA实战:
1. 打开phpStudy或xampp,运行Apach和MySQL;
2. 浏览器进入DVWA主界面,在左侧栏选择DVWA Security安全等级为Low,然后进入Command Injection;
3. 我们输入一个IP提交后,发现返回了对这个IP进行Ping的结果。
注:如果返回乱码,可以试试如下方法:
找到DVWA目录下/dvwa/includes里的dvwaPage.inc.php文件,把字符集utf-8改为gb2312 ,保存一下便可。
// Send Headers + main HTML code Header( 'Cache-Control: no-cache, must-revalidate'); // HTTP/1.1 //Header( 'Content-Type: text/html;charset=utf-8' ); // TODO- proper XHTML headers... Header( 'Content-Type: text/html;charset=gb2312' ); // TODO- proper XHTML headers... Header( 'Expires: Tue, 23 Jun 2009 12:00:00 GMT' ); // Date in the past
其实就跟我们自己进Windows的cmd里ping是一样的。因此,我们猜想后台肯定也是调用了系统的命令,并且将输入的参数进行拼接:
// 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 ); }
因此,这边的提交操作满足了命令注入的三个条件,存在命令注入漏洞。
4. 如果我们输入123.125.114.144 && net user,那么会得到如下信息:
一个简单的命令注入漏洞就这样被利用了,只需要常见的命令连接符(&,&&,|,||,;等)和系统命令,如果输入的命令更具威胁性,那么这个危害就更大了,例如在Linux下输入127.0.0.1&&cat /etc/shadow甚至可以读取shadow文件。
5. 接下去我们把安全等级调到medium,发现报错了:错误的参数 net。我们来看看后台的代码,发现对”&&” 、”;”进行过滤,本质上是黑名单的方式。
// Set blacklist $substitutions = array( '&&' => '', ';' => '', );
但是黑名单的过滤有限,我们可以利用&来攻击漏洞,输入123.125.114.144 & net user即可,另外,既然会把关键连接符过滤,何不反过来利用,构造&;&连接符,这样当;被过滤后,&&发挥了功效。
6. 接下去我们看看high等级的命令注入,发现上述方法也失效了,查看后台代码,发现对更多的命令连接符进行了过滤。
// Set blacklist $substitutions = array( '&' => '', ';' => '', '| ' => '', '-' => '', '$' => '', '(' => '', ')' => '', '`' => '', '||' => '', );
本质上仍然是黑名单的方式,所以仍然存在局限性。例如代码中的'| '后面有个空格,因此,我们直接输入123.125.114.144|net user即可。
另外,对于无回显的情况,可以使用延时命令查看响应速度(如Windows下的ping 127.0.0.1 -n 5 > nul或Linux下的sleep 5)或搭建服务器查看是否有接收到请求(Windows下的ping,telnet或者Linux下的wget,curl等)等方法;
7. 最后我们来看看impossible等级的命令注入,发现用上述的方法不可行,而且报错信息也更改了:ERROR: You have entered an invalid IP。查看后台代码,发现对参数ip进行了严格的限制,只有“数字.数字.数字.数字”的输入才会被接收执行,有效的修复了命令注入漏洞。
// 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 int's put the IP back together. $target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
实战心得:
使用白名单对用户输入的命令进行限制,尽量不要使用黑名单,最好是要遵守对一切输入不可信任的原则,对输入进行严格的校验。