小生归一(五)md5扩展长度攻击
此文章为原创连载文章,关注公众号,持续更新。
欢迎投稿及转载,标明来源作者即可。
1、md5加密原理
原python与安全系列续
又到了小生归一 的笔记分享~有人期待嘛~
1、MD5加密过程中512比特(64字节)为一组,属于分组加密,而且在运算的过程中,将512比特分为32bit*16块,分块运算。(先把需要加密的进行ASCII16进制编码)
2、我们关键利用的是MD5的填充,对加密的字符串进行填充(比特第一位为1其余比特为0),使之(二进制)补到448模512同余,即长度为512的倍数减64,最后的64位再补充为原来字符串的长度,这样刚好补满512位的倍数,如果当前明文正好是512bit倍数则再加上一个512bit的一组。
3、这里每一个512位称为一个分组,又将每一个512位分为16个32位,称为一个子分组(M0~M15)。之后进行4轮运算,每一轮进行16次操作,分别针对这16个子分组。原消息有几个分组就进行几次循环。
MD5不管怎么加密,每一次循环加密得到的密文作为下一次加密的初始向量IV,这一点很关键!!!第一次循环是128位序列初始向量位4个32(十六进制)位向量:A=01234567h;B=89abcdefh;C=fedcba98h;D=76543210h。注意这些变量在内存中的顺序是低值存放低字节,所以在程序中应该是:A=0x67452301;B=0xefcdab89;C=0x98badcfe;D=0x10325476.最后结果再次反转到正常顺序后输出即可。
2、一次循环运算过程
这四轮运算需要用到一个常数表,这些常数T[i](i=1~64)等于4294967296*abs(sin(i))所得结果的整数部分,其中i用弧度表示。这样做是为了通过正弦函数和幂函数来进一步消除变换中的线性。
首先我们保存A,B,C,D。
INPUT_A=A
INPUT_B=B
INPUT_C=C
INPUT_D=D
第一轮
(注:公式中的<<<表示循环左移)
用到的函数:F(X,Y,Z)=(X&Y)|((~X)&Z)
A= B+((A+F(B,C,D)+M[0]+T[1])<<<7)
D= A+((D+F(A,B,C)+M[1]+T[2])<<<12)
C= D+((C+F(D,A,B)+M[2]+T[3])<<<17)
B= C+((B+F(C,D,A)+M[3]+T[4])<<<22)
A= B+((A+F(B,C,D)+M[4]+T[5])<<<7)
D= A+((D+F(A,B,C)+M[5]+T[6])<<<12)
C= D+((C+F(D,A,B)+M[6]+T[7])<<<17)
B= C+((B+F(C,D,A)+M[7]+T[8])<<<22)
A= B+((A+F(B,C,D)+M[8]+T[9])<<<7)
D= A+((D+F(A,B,C)+M[9]+T[10])<<<12)
C= D+((C+F(D,A,B)+M[10]+T[11])<<<17)
B= C+((B+F(C,D,A)+M[11]+T[12])<<<22)
A= B+((A+F(B,C,D)+M[12]+T[13])<<<7)
D= A+((D+F(A,B,C)+M[13]+T[14])<<<12)
C= D+((C+F(D,A,B)+M[14]+T[15])<<<17)
B= C+((B+F(C,D,A)+M[15]+T[16])<<<22)
第二轮
用到的函数:G(X,Y,Z)=(X&Z)|(Y&(~Z))
A= B+((A+G(B,C,D)+M[1]+T[17])<<<5)
D= A+((D+G(A,B,C)+M[6]+T[18])<<<9)
C= D+((C+G(D,A,B)+M[11]+T[19])<<<14)
B= C+((B+G(C,D,A)+M[0]+T[20])<<<20)
A= B+((A+G(B,C,D)+M[5]+T[21])<<<5)
D= A+((D+G(A,B,C)+M[10]+T[22])<<<9)
C= D+((C+G(D,A,B)+M[15]+T[23])<<<14)
B= C+((B+G(C,D,A)+M[4]+T[24])<<<20)
A= B+((A+G(B,C,D)+M[9]+T[25])<<<5)
D= A+((D+G(A,B,C)+M[14]+T[26])<<<9)
C= D+((C+G(D,A,B)+M[3]+T[27])<<<14)
B= C+((B+G(C,D,A)+M[8]+T[28])<<<20)
A= B+((A+G(B,C,D)+M[13]+T[29])<<<5)
D= A+((D+G(A,B,C)+M[2]+T[30])<<<9)
C= D+((C+G(D,A,B)+M[7]+T[31])<<<14)
B= C+((B+G(C,D,A)+M[12]+T[32])<<<20)
第三轮
用到的函数:H(X,Y,Z)=X^Y^Z
A= B+((A+H(B,C,D)+M[5]+T[33])<<<4)
D= A+((D+H(A,B,C)+M[8]+T[34])<<<11)
C= D+((C+H(D,A,B)+M[11]+T[35])<<<16)
B= C+((B+H(C,D,A)+M[14]+T[36])<<<23)
A= B+((A+H(B,C,D)+M[1]+T[37])<<<4)
D= A+((D+H(A,B,C)+M[4]+T[38])<<<11)
C= D+((C+H(D,A,B)+M[7]+T[39])<<<16)
B= C+((B+H(C,D,A)+M[10]+T[40])<<<23)
A= B+((A+H(B,C,D)+M[13]+T[41])<<<4)
D= A+((D+H(A,B,C)+M[0]+T[42])<<<11)
C= D+((C+H(D,A,B)+M[3]+T[43])<<<16)
B= C+((B+H(C,D,A)+M[6]+T[44])<<<23)
A= B+((A+H(B,C,D)+M[9]+T[45])<<<4)
D= A+((D+H(A,B,C)+M[12]+T[46])<<<11)
C= D+((C+H(D,A,B)+M[15]+T[47])<<<16)
B= C+((B+H(C,D,A)+M[2]+T[48])<<<23)
第四轮
用到的函数:I(X,Y,Z)=Y^(X|(~Z))
A= B+((A+I(B,C,D)+M[0]+T[33])<<<6)
D= A+((D+I(A,B,C)+M[7]+T[34])<<<10)
C= D+((C+I(D,A,B)+M[14]+T[35])<<<15)
B= C+((B+I(C,D,A)+M[5]+T[36])<<<21)
A= B+((A+I(B,C,D)+M[12]+T[37])<<<6)
D= A+((D+I(A,B,C)+M[3]+T[38])<<<10)
C= D+((C+I(D,A,B)+M[10]+T[39])<<<15)
B= C+((B+I(C,D,A)+M[1]+T[40])<<<21)
A= B+((A+I(B,C,D)+M[8]+T[41])<<<6)
D= A+((D+I(A,B,C)+M[15]+T[42])<<<10)
C= D+((C+I(D,A,B)+M[6]+T[43])<<<15)
B= C+((B+I(C,D,A)+M[13]+T[44])<<<21)
A= B+((A+I(B,C,D)+M[4]+T[45])<<<6)
D= A+((D+I(A,B,C)+M[11]+T[46])<<<10)
C= D+((C+I(D,A,B)+M[2]+T[47])<<<15)
B= C+((B+I(C,D,A)+M[9]+T[48])<<<21)
四轮运算完成后,将此时的ABCD与原始输入分别相加。
a= A + INPUT_A
b= B + INPUT_B
c= C + INPUT_C
d= D + INPUT_D
最终得到的a,b,c,d以为下次循环运算的初始向量或最终输出的雏形。
这里
(https://github.com/shrewdnoob/webCTF/blob/master/md5encode.py)是自己写的
python3版的md5加密脚本,可以更好的理解md5加密过程。由于太长了,就没有贴出来。
3、攻击原理
假如我们有md5($key+$data)==md5(‘secrettest’)的值:
cb08e6781ef34c8ecb06e1be269a6bdc
$key=secret
$data=test
‘secrettest’分组填充后为
x73x65x63x72x65x74x74x65x73x74x80x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x50x00x00x00x00x00x00x00
我们可以得到填充的
$padding=’x80x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x50x00x00x00x00x00x00x00’
md5加密后得到的最后四个向量为
['0x78e608cb','0x8e4cf31e', '0xbee106cb', '0xdc6b9a26']
我们知道所有的md5加密初始向量为
A=0x67452301;B=0xefcdab89;C=0x98badcfe;D=0x10325476
假设我们需要扩展添加的字符串为$add=’aadd’
实现md5扩展长度攻击就是把初始向量改成md5(key+data)得到的最后四个向量:
A=0x78e608cb;B=0x8e4cf31e;C=0xbee106cb;D=0xdc6b9a26
用我前面给的脚本,把ABCD改成上面的,
不过最后64位填充字符串长度时候,字符串的长度不是len($add),而是len($key+$data+$padding+$add)。
所以在我们不知道$key的时候,但是知道
加密结果’cb08e6781ef34c8ecb06e1be269a6bdc’
$key长度和$data
我们就可以进行md5扩展长度攻击
4.攻击利用
我不知道如果你是第一次是否和我一样,看着别人的教程还是很糊涂。
其实上面的过程很简单的理解就是,初始向量不变,还是:
A=0x67452301;B=0xefcdab89;C=0x98badcfe;D=0x10325476
key+data==‘secrettest’分组填充后为
‘x73x65x63x72x65x74x74x65x73x74x80x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x50x00x00x00x00x00x00x00’
直接在后面加个$add=’aadd’就是
‘x73x65x63x72x65x74x74x65x73x74x80x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x50x00x00x00x00x00x00x00aadd’
然后我们就可以用上面的MD5加密得到扩展后的值。
f7172bfd605a88cf9fc6580b1bad03b9
注意:如果你直接拿上面的用python的hashlib.md5()函数加密和我得到结果是不一样的,我觉得是编码问题,对于我这个菜鸡,具体还不知道为什么。你可以用我给你脚本,改脚本里的,是可以得到上面结果的。
5、工具推荐
HashPump(https://github.com/bwall/HashPump)
这个是可以直接下载python模块的,具体可以参考链接。最好是在Linux环境下载。
pipinstall hashpumpy
6、总结
弄明白了md5扩展长度攻击原理,可以帮我学到更多,学习像CBC字节翻转攻击原理会有帮助。题目练习可以找BUUCTF的[De1CTF2019]SSRF Me。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 猿思考系列4——一文学会java的斗转星移动
- 猿思考系列5——一文明白java和微商那点儿事儿
- 猿思考系列8——缓存的套路也就这些
- 猿思考系列9——一文获取隐藏逻辑挖掘办法
- 猿蜕变系列1——春天的故事
- 猿蜕变系列2——一文搞懂spring的花式DI
- 猿蜕变系列3——SpringMVC之初体验
- 猿蜕变4——一文获取web框架正确学习套路
- 猿蜕变系列5——一文搞懂Controller的花式编写
- 猿蜕变系列6——一文掌握springMVC必会技巧
- ModuleNotFoundError: No module named ‘__main__.XX‘;
- 猿蜕变系列7——也说说springMVC上传姿势
- 猿蜕变系列8——一文搞懂Interceptor操纵姿势
- 猿蜕变9——一文搞定SpringMVC的RESTFul套路
- 猿蜕变10——一文学会ORM的正确打开姿势