美文网首页
CTF题库 - 让我进去之HASH长度扩展攻击

CTF题库 - 让我进去之HASH长度扩展攻击

作者: 北极_67e9 | 来源:发表于2019-08-08 19:41 被阅读0次

要点:

一、更改请求包中的cookie:source为1,则可显示源码,审计源码,可看出本题拿flag思路如下:

1、计算出md5($secret+$admin+ $password),并赋给cookie: getmein,重新发包则可显示flag

2、secret末知(只知长度为15字节),但已知md5($secret+'admin'+'admin'),即响应包中的sample-hash。

3、由于 password不允许赋值为admin  因此需要构造包中的admin和 password的值来绕过secret计算出正确的mac值

4.为达到第3步的要求,可利用hash长度扩展攻击

二、hash长度扩展攻击的原理(以下内容参考https://www.freebuf.com/articles/web/31756.html)

1.该攻击是利用不严谨的mac计算方法来绕过未知的key

2.基本原理知下:

        a、md5算法会首先将数据划分为长度为512位的分组,并对各个分组进行操作,对长度不到512位的分组,会首先补齐到512位。补齐规则是:先补齐到448位,补的数是首位为1,余均为0。其次,计算数据长度,并将该长度填充到最后64位,该64位的其余均补0。最终补齐后长度为448+64=512位

      b、md5在计算摘要时,会引入四个长度为32位的初始量(称为registers),计算过程为: 对每个512位的分组划分为长度为128位的四个子组。对首个分组,利用registers和预先设定的函数,对四个子组进行复杂的变换后得到128位长的序列。将该序列划分为四个长度为32位的子序列3,作为下一分组的registers,进行同样的操作。以此类推,直到最后一个分组操作完成,最后输出的128位序列即为摘要值

      c、由此可见,上一分组得到的摘要即为下一分组的输入

      d、长度扩展攻击的原理即是对已知的mac=md5(key,m),通过将key+m人为扩展到512位,后面再加上m1。则服务端计算md5 的过程为:

      key + m + 我们填充的扩展值 +

      m1 +真实扩展值.

正好与我们添加m1并覆盖registers初始值所计算出来的一样。这是因为攻击者的哈希计算过程,相当于从服务器计算过程的一半紧接着进行下去。

      e、为完成攻击,除了人为填充外,还需要对标准md5函数进行修改,将registers修改为我们自己的值,在本题中,即为sample-hash值。同时,由于真实扩展值长度为m1的长度+512,还要对标准函数中的数据长度加上512。最后利用修改过的函数对m1求摘要,该值即等于服务器计算出的摘要。

三、修改标准md5函数

    感谢https://blog.csdn.net/u011377996/article/details/86365533的博主提供的md5算法的python代码。修改如下:

1、将sample-hash划分为四个32位的分组,并将每分组按字节倒序(小端序),分别替换原代码中的四个register:A、B、C、D:

A=0xb2801557

B=0x06f3656c

C=0x644f6d37

D=0xc7b53ce5

2、将原代码中计算出的长度加上512:

原代码:length = struct.pack('<Q', len(message)*8)

修改后:length = struct.pack('<Q', len(message)*8+512)

3、运行修改代码,对abc求hash,值为7db18a2831cdab27425f299ca09f034e

四、拿flag

1、构造admin=admin,password=admin+扩展值+abc,由于secret为15字节长,再加上两个admin长度为25字节即200位(16进制的c8),因此到448位应该填充1个\x80、30个\x00,再填充长度为1个\xc8、最后再填充7个\x00

2、因此url转码后,password构造为admin%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%c8%00%00%00%00%00%00%00abc

3、再在请求包头部添加cookie:getmein为刚才计算的hash值7db18a2831cdab27425f299ca09f034e。

4、发送请求,即可返回flag。如图:

五、下面给出修改过的md5代码:

# -*- coding: utf-8 -*-

# Author:0verWatch

import struct

import math

import binascii

lrot = lambda x,n: (x << n)|(x >> 32- n)  #循环左移的骚操作

#初始向量

A, B, C, D = (0xb2801557, 0x06f3656c, 0x644f6d37, 0xc7b53ce5)

# A, B, C, D = (0x01234567, 0x89ABCDEF, 0xFEDCBA98, 0x76543210)

#循环左移的位移位数

r = [  7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,

        5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,

        4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,

        6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21

        ]

#使用正弦函数产生的位随机数,也就是书本上的T[i]

k =  [int(math.floor(abs(math.sin(i + 1)) * (2 ** 32))) for i in range(64)]

def init_mess(message):

    global A

    global B

    global C

    global D

    A, B, C, D = (0xb2801557, 0x06f3656c, 0x644f6d37, 0xc7b53ce5)

    # A, B, C, D = (0x01234567, 0x89ABCDEF, 0xFEDCBA98, 0x76543210)

    length = struct.pack('<Q', len(message)*8+512)  #原消息长度64位比特的添加格式,太骚额这种写法

    while len(message) > 64:

        solve(message[:64])

        message = message[64:]

    #长度不足64位消息自行填充

    message += '\x80'

    message += '\x00' * (56 - len(message) % 64)

    #print type(length)

    message += length

    # print binascii.b2a_hex(message)

    solve(message[:64])

def solve(chunk):

    global A

    global B

    global C

    global D

    w = list(struct.unpack('<' + 'I' * 16, chunk))  #分成16个组,I代表1组32位,tql,学到了

    a, b, c, d = A, B, C, D

    for i in range(64):  #64轮运算

        if i < 16:  #每一轮运算只用到了b,c,d三个

            f = ( b & c)|((~b) & d)

            flag  = i      #用于标识处于第几组信息

        elif i < 32:

            f = (b & d)|(c & (~d))

            flag = (5 * i +1) %16

        elif i < 48:

            f = (b ^ c ^ d)

            flag  = (3 * i + 5)% 16

        else:

            f = c ^(b |(~d))

            flag  = (7 * i ) % 16

        tmp = b + lrot((a + f + k[i] + w[flag])& 0xffffffff,r[i]) #&0xffffffff为了类型转换

        a, b, c, d = d, tmp & 0xffffffff, b, c

        #print(hex(a).replace("0x","").replace("L",""), hex(b).replace("0x","").replace("L","") , hex(c).replace("0x","").replace("L",""), hex(d).replace("0x","").replace("L",""))

    A = (A + a) & 0xffffffff

    B = (B + b) & 0xffffffff

    C = (C + c) & 0xffffffff

    D = (D + d) & 0xffffffff

def digest():

    global A

    global B

    global C

    global D

    return struct.pack('<IIII',A,B,C,D)

def hex_digest():

    return binascii.hexlify(digest()).decode()

if __name__ == '__main__':

    while True:

        mess = raw_input("请输入你的信息:")

        init_mess(mess)

        out_put = hex_digest()

        print out_put

相关文章

网友评论

      本文标题:CTF题库 - 让我进去之HASH长度扩展攻击

      本文链接:https://www.haomeiwen.com/subject/cmdfjctx.html