第二张图那里填充有点问题应该是22*8的16进制,不好意思
起因
一道ctf题
$flag = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!
$username = $_POST["username"];
$password = $_POST["password"];
if (!empty($_COOKIE["getmein"])) {
if (urldecode($username) === "admin" && urldecode($password) != "admin") {
if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
echo "Congratulations! You are a registered user.\n";
die ("The flag is ". $flag);
}
else {
die ("Your cookies don't match up! STOP HACKING THIS SITE.");
}
}
else {
die ("You are not an admin! LEAVE.");
}
}
setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));
if (empty($_COOKIE["source"])) {
setcookie("source", 0, time() + (60 * 60 * 24 * 7));
}
else {
if ($_COOKIE["source"] != 0) {
echo ""; // This source code is outputted here
}
}
这里的关键绕过是这一句:
if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password)))
要
cookie['getmein']===$secret . urldecode($username . $password)
的md5加密,而这里的secret是不可知的,但却知道他的长度,这里我们就涉及到hash扩展攻击。
MD5加密原理
MD5会把原数据分成512
为一块的许多块,最后一块加上64字节来表示他的长度,一共构成512*n个字节然后再对这N个512数据块进行N次加密计算(因为过程较复杂,此处不做详解,下文称为复杂计算),虽然此处加密过程很复杂,但是整个加密过程很容易理解,如下:
加密过程
现在我们知道的是
secretusernamepassword
这个数据,那么我们怎么进行攻击呢,我们看一下这个数据的16进制
算一下,22个字符,512/8=64,64/16=4,我们需要4排数据然后最后给一个整个数据长度,22=0x14,然后md5计算是小端存储,所以我们修改如下图
secretusernamepassword转16进制
0x736563726574757365726e616d657617373776f7264
然后填充成
0x736563726574757365726e616d6570617373776f726480000000000000000000000000000000000000000000000000000000000000000000b000000000000000
md5('secretusernamepassword')==3105ff5f8723abe628d54387f2de5641
可以倒推出这个时候的ABCD1:
A=5fff0531
B=e6ab2387
C=8743d528
D=4156def2
现在如果我们继续加数据
0x736563726574757365726e616d6570617373776f726480000000000000000000000000000000000000000000000000000000000000000000b00000000000000072747576
现在我们已知前面512位计算出来的ABCD1,现在我们去掉前面直接用运算出来的ABCD1运算后面0x72747576
得到的结果应该和加密全部的结果是一样的
0X72747576
会被自动填充为
0x72747576800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002002000000000000
'secretusernamepassword'+'\x80'+'\x00'*33+'\xb0'+'\x00'*7+'\x72\x74\x75\x76'
直接md5加密结果为8e847c325fb05c60d437b23dc38ea6da
使用ABCD1手动加密0X72747576
A=327c848e,B=605cb05f,C=3db237d4,D=daa68ec3
md5:8e847c325fb05c60d437b23dc38ea6da
可以看到相同
攻击流程
既然如初,我们只要知道一个hash值,知道原来数据的数据长度,那么我们就可以算出
原数据+填充数据到512+任意内容
的hash值
那么我们来看代码
他是直接用secret+username+password
输入的是username和password,那么我们直接得出cookie里面的hash值,拿出这个hash值,倒推出这个ABCD1,然后用这个ABCD1对任意值加密,得出来hash值就是这个任意值附加在
secret+username+password+填充字节+任意值
的hash
like this:
加密代码(引用现成代码)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author:DshtAnger
# theory reference:
# blog:
# http://blog.csdn.net/adidala/article/details/28677393
# http://blog.csdn.net/forgotaboutgirl/article/details/7258109
# http://blog.sina.com.cn/s/blog_6fe0eb1901014cpl.html
# RFC1321:
# https://www.rfc-editor.org/rfc/pdfrfc/rfc1321.txt.pdf
##############################################################################
import sys
def genMsgLengthDescriptor(msg_bitsLenth):
'''
---args:
msg_bitsLenth : the bits length of raw message