Hash length extension attacks 分析

本文深入探讨了Hash长度扩展攻击,从MD5加密原理开始,详细解释了字节填充、分组加密的过程,并通过实例演示了攻击原理。文章提供了Python实现的攻击脚本,以及在 JarvisOJ 平台上的具体应用,分析了解题步骤,包括如何利用hash_extender工具和手动解密方法。
摘要由CSDN通过智能技术生成

最近突然想把以前做的哈希拓展长度攻击的原理给梳理一下,前一段时间梳理了 padding oracle attack的相关知识,打算从原理到题目都详细的讲一讲,使用条件比较苛刻需要攻击者明密文都可控,所以在平时这种漏洞很少见,后面主要介绍一下工具的使用方法以及,jarvis平台上的一道题目,以及2017年陕西省信息安全竞赛的最后一道题目admin

哈希拓展可以伪造任意一对明密文,前提是有一对明密文,且伪造的明文前512比特是固定的···

0x00 MD5加密原理

一些dalao的博客这一点已经说得很清楚了,例如 Assassin师傅的博文

0x1 字节填充

MD5在进行运算时,需要将bit位数填充到指定位数,使其长度在对 512bit 取模后的值为 448bit,留下的64bit用来填写未填充的明文长度

0x2 分组加密

把填充过的(注意如果明文大于512bit,将分成多个组进行加密)明文按512bit一组进行下述加密

这里写图片描述

我们可以看到初始向量IV为128bit,每组加密过之后当做下一组的向量进行运算。最后输出的128bit就是md5值

0x3 实例演示

前面MD5的加密逻辑说得很清楚,这里利用一个实例模拟一下加密过程

加密数据 Value
十六进制 0x61646d696e
填充之后 0x61646d696e+0x80+50*0x00+0x28+0x00*7

首先字节填充,比特第一位补位1,其余位为0所以为0x80
后面全是0字节填充一直到448bit截止,剩下的8byte按照小端方式存储。admin占位5字节所以40bit=0x28bit。
这就是基本的MD5加密算法的流程,有没有看懂??如果看懂了有没有发现攻击者的可乘之机??

0x01 攻击原理

上篇稍微讲了一下,MD5加密的原理,这里主要讲解攻击方法
假设我们已经知道md5($secret+”admin”+”admin”)的值hash1
其实就是iv 与 $secret+”admin”+”admin”的填充值(这里填充了512bit)的hash值
现在假设我们有自己的hash算法可以构造任意的初始iv可以填充任意参与计算的明文
现在有以下结论
如果我要md5($secret+”admin”+”admin”+第一组MD5填充+padding)这里的第一组md5分组就是md5($secret+”admin”+”admin”)时的填充之后的512bit块
那么此值应该在逻辑上等于我利用hash1当做初始向量加密我构造的padding+填充字节(注意这里的填充是算上第一块的长度的即512bit)的第二块生成的md5值

简单的将就是

md5($secret+”admin”+”admin”+第一组MD5填充+padding)=(hash1)md5(padding+填充字节)

0x02 攻击脚本

这里引用别人写的脚本

0x1 md5 python 实现

可以自定义iv值

#!/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
    --return:
            16 hex-encoded string , i.e.64bits,8bytes which used to describe the bits length of raw message added after padding
    '''
    return __import__("struct").pack(">Q",msg_bitsLenth).encode("hex")

def reverse_hex_8bytes(hex_str):
    '''
    --args:
            hex_str: a hex-encoded string with length 16 , i.e.8bytes
    --return:
            transform raw message descriptor to little-endian 
    '''
    hex_str = "%016x"%int(hex_str,16)
    assert len(hex_str)==16    
    return __import__("struct").pack("<Q",int(hex_str,16)).encode("hex")

def reverse_hex_4bytes(hex_str):
    '''
    --args:
            hex_str: a hex-encoded string with length 8 , i.e.4bytes
    --return:
            transform 4 bytes message block to little-endian
    '''    
    hex_str = "%08x"%int(hex_str,16)
    assert len(hex_str)==8    
    return __import__("struct").pack("<L",int(hex_str,16)).encode("hex")

def deal_rawInputMsg(input_msg):
    '''
    --args:
            input_msg : inputed a ascii-encoded string
    --return:
            a hex-encoded string which can be inputed to mathematical transformation function.
    '''
    ascii_list = [x.encode("hex") for x in input_msg]
    length_msg_bytes = len(ascii_list)
    length_msg_bits = len(ascii_list)*8
    #padding
    ascii_list.append('80')  
    while (len(ascii_list)*8+64)%512 != 0:  
        ascii_list.append('00')
    #add Descriptor
    ascii_list.append(reverse_hex_8bytes(genMsgLengthDescriptor(length_msg_bits)))
    return "".join(ascii_list)



def getM16(hex_str,operatingBlockNum):
    '''
    --args:
            hex_str : a hex-encoded string with length in integral multiple of 512bits
            operatingBlockNum : message block number which is being operated , greater than 1
    --return:
            M : result of splited 64bytes into 4*16 message blocks with little-endian

    '''
    M = [int(reverse_hex_4bytes(hex_str[i:(i+8)]),16) for i in xrange(128*(operatingBlockNum-1),128*operatingBlockNum,8)]
    return M

#定义函数,用来产生常数T[i],常数有可能超过32位,同样需要&0xffffffff操作。注意返回的是十进制的数
def T(i):
    result = (int(4294967296*abs(__import__("math").sin(i))))&0xffffffff
    return result   

#定义每轮中用到的函数
#RL为循环左移,注意左移之后可能会超过32位,所以要和0xffffffff做与运算,确保结果为32位
F = lambda x,y,z:((x&y)|((~x)&z))
G = lambda x,y,z:((x&z)|(y&(~z)))
H = lambda x,y,z:(x^y^z)
I = lambda x,y,z:(y^(x|(~z)))
RL = L = lambda x,n:(((x<<n)|(x>>(32-n)))&(0xffffffff))

def FF(a, b, c, d, x, s, ac):  
    a = (a+F ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;  
    a = RL ((a), (s))&0xffffffff;  
    a = (a+b)&0xffffffff  
    return a  
def GG(a, b,
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值