CTF:PHP MD5绕过和序列化漏洞
作者:高玉涵
博客:blog.csdn.net/cg_i
时间:2021.6.25 9:51
题目复现Docker环境:
https://github.com/glzjin/buusec_2019_code_review_1
生命因为有限所以宝贵;因为有限,所以才要不懈努力。
——名侦探柯南
源码
第一关:MD5绕过漏洞
CTF就是一个“套娃”游戏。首先我们把注意力集中到if(md5($_POST[‘md51’]) == md5($_POST[‘md52’]))…这行语句,也就是逻辑&&运算符前半部分,它获取用户提交的值,分别存放在名为md51和md52,经MD5函数加密后做相等比较。而语句&&运算符后半部分$_POST[‘md51’] != $_POST[‘md52’]要求提交的值不相同(不能简单提交两个同样的值,从而产生两个相同的MD5值)当同时满足这两个条件整行语句为真,进入到unserialize($_POST[‘obj’]);这部份(获取flag的关键,让我们暂时忽略它)如何突破这前后互斥无解的语句。
如果你看过我写的《PHP MD5函数0E绕过漏洞》一文,就不难看出这里存在MD5绕过漏洞,我们只需要找到这样两个值,它们生成以0e 开头且后面全部为数字的MD5值。有没有两个这样的值呢?不仅有且还有很多!这里只给出解题需要的两个值:
md51:QNKCDZO
MD5:0e830400451993494058024219903391
md52: 240610708
MD5: 0e462097431906509019562988736854
这两个值经MD5加密后,在“==”运算符结果都是0,在“!=”运算付结果都为真。整行语句为真,成功突破!
第二关:反序列化漏洞
我们终于来到本关。但你不要高兴的太早,骄傲是只拦路虎,常挡在成功的道路中间。离拿到flag还远着呢!开始解题之前,让我们回顾代码起始定义的BUU类。类里定义了名为_destruct()函数,观察得知if($this->correct === $this->input)…为真时可拿到flag(注意这里用到的是全等运算符)。
PHP的魔法函数(析构函数)
PHP中有一些函数可以在脚本的任何地方执行,且不需要声明就可以调用,但是存在触发条件__destruct()就属于这类魔法函数,当对象被销毁时自动触发。
由于序列化不会传递函数中定义的操作,只传值,但是魔法函数是可以自动执行的,当类中定义了魔法函数时,且对象中存在触发条件,我们就有机可乘。而这个触发条件就是unserialize($_POST[‘obj’]);这行语句。我们通过构造“序列化字符串”随后在对像销毁时触发__destruct()函数。
那这个字符串应该是什么样子的呢?
$this->correct = base64_encode(uniqid());怎样才能让$input和它一模一样呢?uniqid()是不是也存在类式绕过的漏洞?我劝你善良并确定的告诉你没有。其实“===”已经出卖了它,世上根本不存在有一模一样的人(不知道克隆人会不会是个例外),有的话那一定是一个“引用”。
通关:Python代码
import requests
if __name__ == '__main__':
'''
BUU CODE REVIEW 1
MD5绕过和序列化漏洞
buusec_2019_code_review_1-master
https://github.com/glzjin/buusec_2019_code_review_1
'''
payload = {
'pleasepost': '2',
'md52': 'QNKCDZO',
'md51': '240610708',
'obj': 'O:3:"BUU":2:{s:7:"correct";s:0:"";s:5:"input";R:2;}'
}
r = requests.post("http://11605b67-a0a7-4c22-9478-501ff712c10a.node3.buuoj.cn/?pleaseget=1", data=payload)
print(r.text)
成功拿到flag。