Skip to content
Kurisu
Go back

无字母数字 RCE:16 字符限制下的命令执行

0x01 题目模型:16 个字符怎么执行命令

经典 CTF 题:执行点只有 eval($_GET[1]) 之类,命令总长度限制在 16 字符以内(或禁用字母数字下划线),system('ls') 都塞不下。三条路按直接程度排序:

① 反引号执行:反引号就是 shell 的命令替换,16 字符够写短命令:

`ls`;`nl *`;      # 配合通配符缩短

② file_put_contents + 伪协议包含:先写一个新文件,再用包含类漏洞执行——把”一次短命令”拆成”写入 + 触发”两步:

file_put_contents('x.php','<?php eval($_GET[0]);');   # 拆成多次 GET 分批写

③ 临时文件 + 问号通配符:最优雅的一路,见 0x02。

0x02 通配符匹配临时文件:让 PHP 替你落地 webshell

PHP 处理文件上传时,无论业务代码写什么,文件都会先落到临时目录(/tmp/phpXXXXXX,6 位随机),请求结束才删除。

禁用字母数字下划线美元符时,用 ?(匹配任意单字符)构造 pattern 让 shell 找到它:

. /???/??????????>    # /tmp/phpXXXXXX = 8 个问号匹配 php+6位随机

两个技巧点:利用时间排序(ls -t 思路,最新的排最前)和通配符精准匹配(? 数量卡准 php + 6 位的位数,用 [@-[] 排除干扰文件)。请求后立刻用第二个连接执行,抢在 PHP 清理临时文件之前——“条件竞速”。

0x03 preg_replace /e:\1 分组即代码执行

PHP 7.3 之前,preg_replace 的 /e 会把替换串当 PHP 代码执行,其中的 \1 引用第一个捕获分组——分组可控时,\1 展开后执行的就是用户代码:

preg_replace('/(.*)/e', '\\1', $_GET['x']);   // x=<?php system('whoami')?> → RCE

payload 里的 \1 就是吃掉分组内容;7.3+ 已移除该修饰符,老系统仍会遇到。

0x04 冷知识:GET 参数里的点号会变成下划线

PHP 处理 GET 请求时,参数名里的 . 和空格会自动转成 _——?a.b=1 到后端是 $_GET['a_b']。写利用脚本时参数名带点、按原名传永远收不到,这是”参数没生效”的经典原因。

0x05 环境杂记

Ubuntu 长时间运行后 Docker/SSH 偶发失联,重启解决;测历史特性用 php -S 0.0.0.0:7788 起服务最快(没有 index 文件会 404)。

相关旧文


Share this post:

Previous Post
SQL 注入绕过手册:从空格逗号到雷池 WAF
Next Post
针对真实目标的 SQL 注入:打崩 WAF 正则