Command Injection :
命令注入(Command Injection),对一些函数的参数没有做好过滤而导致用户可以控制输入的参数,使其恶意执行系统命令或这cmd、bash指令的一种注入攻击手段。php命令注入攻击漏洞是一种php应用程序常见的脚本漏洞。
流程:
1.判断是否可调用系统命令(权限问题)
2.函数或函数的参数是否可控
3.是否能拼接注入命令
下面解释关于4个命令连接符(&&,&,||,|)
1. &&:先执行command1,执行command1成功后可执行command2,否则不执行command2
例如:command1 && command2
2. &:先执行command1,不管是否成功都执行command2
例如:command1 & command2
3. ||:先执行command1,执行失败后执行command2
例如:command1 || command2
4. |:将command1的输出作为command2的输入,只打印command2执行结果
例如:command1 | command2
Low等级:
观察low级别源码:
Low Security Level <?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>"; } ?>
这里解释几个php函数:
1.isset()
isset函数是检测变量是否设置。
格式:bool isset( mixed var [, mixed var [, ...]] )
返回值:
若变量不存在则返回FALSE
若变量存在且其值为NULL,也返回FALSE
若变量存在且值不为NULL,则返回TURE
同时检查多个变量时,每个单项都符号上一条要求时才返回TRUE,否则结果为FALSE
如果已经使用unset()释放了一个变量之后,它将不再是isset()。若使用isset()测试一个被设置成NULL的变量,将返回FALSE。同时要注意的是一个NULL字节(" ")并不等同于PHP的NULL常数。
2.stristr(string,search,before_search)
(1):string参数,必需,规定被搜索的字符串
(2):search参数,必需,规定要搜索的字符串,如果是数字则会匹配该数字在ascii码表中对应的字符
(3):before_search参数,可选,默认值为false,如果设置为true则返回search参数第一次出现之前的部分
返回值:返回从匹配点开始字符串的剩余部分,如果没有搜索到字符串,则返回false
例如:返回值为 o world!,这里111对应的ascii字符为o,因为before_search为false所以返回的是匹配点开始之后的字符。
<?php echo stristr("Hello world!",111); ?>
例如:这次返回的就是hello,这里此函数不区分大小写。
<?php echo stristr("Hello world!","WORLD",true); ?>
3.php_uname()函数
string php_uname ([ string $mode = "a" ])
该函数会返回运行php的操作系统的相关描述,mode是单个字符,用于定义要返回什么信息。
'a':此为默认,包含s(操作系统名),n(主机名),r(版本名),v(版本信息),m(机器类型)里的所有模式
这里服务器通过判断操作系统执行不同的ping命令,但没对用户使用的参数做任何的过滤,严重的注入漏洞
例如输入:127.0.0.1 && net user 实现注入。
这里net user可以换成其他的命令,比如ipconfig(windows下)只要是在权限范围内的命令都可以使用
如果是Linux可以:127.0.0.1 && cat /etc/shadow
Medium等级:
观察源代码:
这里服务器对ip参数进行了过滤,即把&&和;删除,本质上采用的是黑名单机制,但依旧可以注入
<?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>"; } ?>
因为被过滤的只有&&和;所以可以使用&和|
例如:127.0.0.1 & net user
或者用&;&代替&& 即:
例如:127.0.0.1 &;& net user
Linux下可用cat /etc/shadow等等...
High级别:
观察源代码:
<?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>"; } ?>
相比Medium,进一步完善了黑名单,但依然可以绕过。
这里是把'| '转换为' ' (这里注意|后有空格),所以我们用|即可
输入:127.0.0.1|net user