前言 命令执行漏洞的原理:在操作系统中, &  、&& 、|  、 ||   都可以作为命令连接符使用,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令
Low 核心代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?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>"; } ?> 
可以看到,low级别的代码接收了用户输入的ip,然后根据服务器是否是Windows NT系统,对目标ip进行不同的ping测试。但是这里对用户输入的ip并没有进行任何的过滤,所以我们可以进行命令执行漏洞。
我们ping一下百度的ip地址看看,可以看到能ping通

我们尝试输入 61.135.169.125 & ipconfig  ,在操作系统中,”  &  、&& 、|  、 ||   “都可以作为命令连接符使用,我们在ping完后再执行ipconfig 命令查看ip信息
可以看到,成功执行。然后我们就可以继续执行我们的命令了。把ipconfig换成其他的系统命令
Medium 核心代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php   if( isset( $_POST[ 'Submit' ]  ) ) {     // Get input     $target = $_REQUEST[ 'ip' ];     // Set blacklist     $substitutions = array(         '&&' => '',         ';'  => '',     );     // Remove any of the charactars 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级别的代码在low级别的代码上增加量了对 && 和 ;的过滤,但是这并没有什么软用。
我们根本就不用 && ,我们直接用 &
&&和&的区别在于,&&是执行完前面的命令然后执行后面的命令,&是不管前面的命令是否值执行,后面的都执行
可以看到,我们直接按照low级别的命令就可以绕过执行。
由于使用的是str_replace把”&&”、”;”替换为空字符,因此可以采用以下方式绕过:
61.135.169.125&;&ipconfig

High 核心代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?php if( isset( $_POST[ 'Submit' ]  ) ) {     // Get input     $target = trim($_REQUEST[ 'ip' ]);     // Set blacklist     $substitutions = array(         '&'  => '',         ';'  => '',         '| ' => '',         '-'  => '',         '$'  => '',         '('  => '',         ')'  => '',         '`'  => '',         '||' => '',     );     // Remove any of the charactars 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级别的代码进行了黑名单过滤,把一些常见的命令连接符给过滤了。黑名单过滤看似安全,但是如果黑名单不全是话,是很容易进行绕过的。我们仔细看黑名单过滤中的|,|后面还有一个空格,所以我们可以进行绕过,输入下面命令。
61.135.169.125|ipconfig

|是管道符,表示将Command 1的输出作为Command 2的输入,并且只打印Command 2执行的结果。
Impossible 核心代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <?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 int's 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 '<pre>ERROR: You have entered an invalid IP.</pre>';     } } // Generate Anti-CSRF token generateSessionToken(); ?> 
stripslashes(string): 该函数会删除字符串string中的反斜杠,返回已剥离反斜杠的字符串。
explode(separator,string,limit): 该函数把字符串打散为数组,返回字符串的数组。参数separator规定在哪里分割字符串,参数string是要分割的字符串,可选参数limit规定所返回的数组元素的数目。
is_numeric(string): 该检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE。
可以看到,Impossible级别的代码加入了Anti-CSRF token,同时对参数ip进行了严格的限制,只有诸如“数字.数字.数字.数字”的输入才会被接收执行,因此不存在命令注入漏洞。