用MD5实现hash长度扩展攻击 By Assassin

2023-11-17

今天心血来潮,看到了扩展攻击,猛然想到了之前看的扩展攻击的原理还没有弄懂,这里补充一下,hash长度扩展攻击到底是怎么实现的。

题目

首先从实验吧上面见到的经典的题目,下面给出源码

<?php 

$flag = "flag{flag is here}";
$secret = "aaaaabbbbbccccc"; // 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
    }
}
?>

然后观察代码我们首先发现一些规律:

1.首先$secret变量我们不知道,但是我们知道它的长度
2.从下面setcookie函数我们可以通过sample-hash这个变量拿到md5($secret+”admin”+”admin”)的md5值
3.我们登陆成功的条件,username==admin&&password!=admin 并且我们要cookie getmein的值等于md5($secret+username+password)

下面讲一下何为扩展攻击

MD5扩展攻击介绍

要说MD5的扩展攻击,首先要了解一定MD5加密算法的过程,其中我们不需要了解太多,我们需要知道如下几点


1.MD5加密过程中512比特(64字节)为一组,属于分组加密,而且在运算的过程中,将512比特分为32bit*16块,分块运算
2.我们关键利用的是MD5的填充,对加密的字符串进行填充(比特第一位为1其余比特为0),使之(二进制)补到448模512同余,即长度为512的倍数减64,最后的64位在补充为原来字符串的长度,这样刚好补满512位的倍数,如果当前明文正好是512bit倍数则再加上一个512bit的一组。
3.MD5不管怎么加密,每一块加密得到的密文作为下一次加密的初始向量IV,这一点很关键!!!

有点绕,下面讲一个例子讲一下如何填充
比如计算字符串“admin”
十六进制0x61646d696e
这里与448模512不同余,补位后的数据如下

0x61646d696e8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000

注意!下图中8是怎么来的!比特第一位补位1,其余为0,那么admin后面(二进制补位1000…000)

这里写图片描述

注意!下图中框框中是啥!是全部要加密明文的长度!这里长度不包含填充的长度!而且注意是比特数!而且我们需要注意一点

这里写图片描述

MD5中存储的都是小端方式!
MD5中存储的都是小端方式!
MD5中存储的都是小端方式!
重要的事情说三遍,举个例子:假如我们这一块值为0x12345678
那么在MD5运算时候存储的顺序是 0x78563412
这也是之所以后8字节为长度,而第1字节先有数据的原因

admin长度为40比特,所以长度为0x28=40bits

在讲如何利用填充扩展攻击?首先直观看一下上面讲的第三点

这里写图片描述

假如我们知道了,md5(“secret”)我们不需要知道secret是什么,只要知道长度,人为将secret填充完,在新加一块假设为add,之前得到的MD5值作为最后一块加密的初始向量IV,最后加密得到的结果和MD5(secret+add)结果是一样的!重点看下面的题目分析吧!

MD5扩展攻击实现

那么再分析从题目中得到的条件,虽然我们不知道$secret是什么,但是我们是否已经知道md5($secret+”admin”+”admin”)的值了?(将其MD5值假设为key)这个时候假设我们主动将$secret+”admin”+”admin”+第一组MD5填充 作为第一组明文,第二组明文自己设定的某值,同时我们利用已经知道的key作为我们构造的明文最后一块加密的初始向量IV,那么加密出来的结果应该和$secret+”admin”+”admin”+第一组MD5填充+第二块铭文的MD5值一样吧。

我们通过sample-hash得到$secret+”admin”+”admin”的加密值
,假如我们构造第一块如

xxxxxxxxxxxxxxxadminadmin+'\x80'+'\x00'*30+'\xc8'+'\x00'*7

这个时候是xxxxxxxxxxxxxxxadminadmin加密填充后的内容,假设得到的MD5值为m,假设$a=xxxxxxxxxxxxxxxadminadmin,我们构造$b=admn
n让m作为加密$b时候的IV初始向量,那么就能得到的MD5($a+$b)的!!
是注意一点,刚刚说的小端存储,所以IV值设置的时候需要注意!
比如我们得到key值为e2c25a7f 7fd42f0f 03194d72 58fbcb6
那么我们构造的初始IV应为
A=0x7f5ac2e2
B=0x0f2fd47f
C=0x724d1903
D=0xb6c8fb58

利用脚本可以得到我们需要的cookie值

MD5加密一块函数的实现,可以构造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, c, d, x, s, ac):  
    a = (a+G ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;  
    a = RL ((a), (s))&0xffffffff;  
    a = (a+b)&0xffffffff  
    return a  
def HH(a, b, c, d, x, s, ac):  
    a = (a+H ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;  
    a = RL ((a), (s))&0xffffffff;  
    a = (a+b)&0xffffffff  
    return a  
def II(a, b, c, d, x, s, ac):  
    a = (a+I ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;  
    a = RL ((a), (s))&0xffffffff;  
    a = (a+b)&0xffffffff  
    return a      

def show_md5(A,B,C,D):
    return "".join( [  "".join(__import__("re").findall(r"..","%08x"%i)[::-1]) for i in (A,B,C,D)  ]  )

def run_md5(A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476,readyMsg=""):

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

    for i in xrange(0,len(readyMsg)/128):
        M = getM16(readyMsg,i+1)
        for i in xrange(16):
            exec "M"+str(i)+"=M["+str(i)+"]"
        #First round
        a=FF(a,b,c,d,M0,7,0xd76aa478L)
        d=FF(d,a,b,c,M1,12,0xe8c7b756L)
        c=FF(c,d,a,b,M2,17,0x242070dbL)
        b=FF(b,c,d,a,M3,22,0xc1bdceeeL)
        a=FF(a,b,c,d,M4,7,0xf57c0fafL)
        d=FF(d,a,b,c,M5,12,0x4787c62aL)
        c=FF(c,d,a,b,M6,17,0xa8304613L)
        b=FF(b,c,d,a,M7,22,0xfd469501L)
        a=FF(a,b,c,d,M8,7,0x698098d8L)
        d=FF(d,a,b,c,M9,12,0x8b44f7afL)
        c=FF(c,d,a,b,M10,17,0xffff5bb1L)
        b=FF(b,c,d,a,M11,22,0x895cd7beL)
        a=FF(a,b,c,d,M12,7,0x6b901122L)
        d=FF(d,a,b,c,M13,12,0xfd987193L)
        c=FF(c,d,a,b,M14,17,0xa679438eL)
        b=FF(b,c,d,a,M15,22,0x49b40821L)
        #Second round
        a=GG(a,b,c,d,M1,5,0xf61e2562L)
        d=GG(d,a,b,c,M6,9,0xc040b340L)
        c=GG(c,d,a,b,M11,14,0x265e5a51L)
        b=GG(b,c,d,a,M0,20,0xe9b6c7aaL)
        a=GG(a,b,c,d,M5,5,0xd62f105dL)
        d=GG(d,a,b,c,M10,9,0x02441453L)
        c=GG(c,d,a,b,M15,14,0xd8a1e681L)
        b=GG(b,c,d,a,M4,20,0xe7d3fbc8L)
        a=GG(a,b,c,d,M9,5,0x21e1cde6L)
        d=GG(d,a,b,c,M14,9,0xc33707d6L)
        c=GG(c,d,a,b,M3,14,0xf4d50d87L)
        b=GG(b,c,d,a,M8,20,0x455a14edL)
        a=GG(a,b,c,d,M13,5,0xa9e3e905L)
        d=GG(d,a,b,c,M2,9,0xfcefa3f8L)
        c=GG(c,d,a,b,M7,14,0x676f02d9L)
        b=GG(b,c,d,a,M12,20,0x8d2a4c8aL)
        #Third round
        a=HH(a,b,c,d,M5,4,0xfffa3942L)
        d=HH(d,a,b,c,M8,11,0x8771f681L)
        c=HH(c,d,a,b,M11,16,0x6d9d6122L)
        b=HH(b,c,d,a,M14,23,0xfde5380c)
        a=HH(a,b,c,d,M1,4,0xa4beea44L)
        d=HH(d,a,b,c,M4,11,0x4bdecfa9L)
        c=HH(c,d,a,b,M7,16,0xf6bb4b60L)
        b=HH(b,c,d,a,M10,23,0xbebfbc70L)
        a=HH(a,b,c,d,M13,4,0x289b7ec6L)
        d=HH(d,a,b,c,M0,11,0xeaa127faL)
        c=HH(c,d,a,b,M3,16,0xd4ef3085L)
        b=HH(b,c,d,a,M6,23,0x04881d05L)
        a=HH(a,b,c,d,M9,4,0xd9d4d039L)
        d=HH(d,a,b,c,M12,11,0xe6db99e5L)
        c=HH(c,d,a,b,M15,16,0x1fa27cf8L)
        b=HH(b,c,d,a,M2,23,0xc4ac5665L)
        #Fourth round
        a=II(a,b,c,d,M0,6,0xf4292244L)
        d=II(d,a,b,c,M7,10,0x432aff97L)
        c=II(c,d,a,b,M14,15,0xab9423a7L)
        b=II(b,c,d,a,M5,21,0xfc93a039L)
        a=II(a,b,c,d,M12,6,0x655b59c3L)
        d=II(d,a,b,c,M3,10,0x8f0ccc92L)
        c=II(c,d,a,b,M10,15,0xffeff47dL)
        b=II(b,c,d,a,M1,21,0x85845dd1L)
        a=II(a,b,c,d,M8,6,0x6fa87e4fL)
        d=II(d,a,b,c,M15,10,0xfe2ce6e0L)
        c=II(c,d,a,b,M6,15,0xa3014314L)
        b=II(b,c,d,a,M13,21,0x4e0811a1L)
        a=II(a,b,c,d,M4,6,0xf7537e82L)
        d=II(d,a,b,c,M11,10,0xbd3af235L)
        c=II(c,d,a,b,M2,15,0x2ad7d2bbL)
        b=II(b,c,d,a,M9,21,0xeb86d391L)


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

        A = A&0xffffffff
        B = B&0xffffffff
        C = C&0xffffffff
        D = D&0xffffffff

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

    return show_md5(a,b,c,d)
利用代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author:DshtAnger
import my_md5
import hashlib
import urllib
#reference:
#   http://www.freebuf.com/articles/web/69264.html
#problem link:
#   http://ctf4.shiyanbar.com/web/kzhan.php
samplehash="e2c25a7f 7fd42f0f 03194d72 58fbcdb6"
#将哈希值分为四段,并反转该四字节为小端序,作为64第二次循环的输入幻书
s1=0x7f5ac2e2
s2=0x0f2fd47f
s3=0x724d1903
s4=0xb6cdfb58
#exp
secret = "a"*15
secret_admin="aaaaabbbbbcccccadminadmin"+'\x80'+'\x00'*30+'\xc8'+'\x00'*7+"admin"
r = my_md5.deal_rawInputMsg(secret_admin)
inp = r[len(r)/2:]      #我们需要截断的地方,也是我们需要控制的地方
#print r
#print inp
print "getmein:"+my_md5.run_md5(s1,s2,s3,s4,inp)
print "getmein:"+hashlib.md5(secret_admin).hexdigest()

而且我们可以发现我们构造IV得出的结果和直接MD5加密的结果是一样的!这时候我们只需要将username和password转换成url格式的提交、同时构造getmein的cookie变量提交即可!

这里写图片描述

讲的不是很清楚,如果还有不太明白的,请参考如下博文

MD5长度扩展攻击

不愧是鸡哥,在这里再次补充一个神乎其神得工具hash_extender
https://github.com/iagox86/hash_extender

利用方法也相当得方便

-d 被扩展的明文
-a 附加的到原来hash的padding
-l 盐的长度
-f 加密方式
-s 带盐加密的hash值
--out-data-format 输出格式
--quiet 仅输出必要的值

利用代码如下

# -*- coding:utf-8 -*-
from urlparse import urlparse
from httplib import HTTPConnection
from urllib import urlencode
import json
import time
import os
import urllib

def gao(x, y):
        #print x
        #print y
    url = "http://120.26.131.152:32778/"
    cookie = "role=" + x + "; hsh=" + y
        #print cookie
    build_header = {
            'Cookie': cookie,
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:44.0) Gecko/20100101 Firefox/44.0',
            'Host': 'web.phrack.top:32785',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    }
    urlparts = urlparse(url)
    conn = HTTPConnection(urlparts.hostname, urlparts.port or 80)
    conn.request("GET", urlparts.path, '', build_header)
    resp = conn.getresponse()
    body = resp.read()
    return body

for i in xrange(1000):
    print i
    #secret len = ???
    find_hash = "../hash_extender/hash_extender -d ';\"tseug\":5:s' -s 3a4727d57463f122833d9e732f94e4e0 -f md5  -a ';\"nimda\":5:s' --out-data-format=html -l " + str(i) + " --quiet"
    #print find_hash
    calc_res = os.popen(find_hash).readlines()
    print calc_res
    hash_value = calc_res[0][:32]
    attack_padding = calc_res[0][32:]
    attack_padding = urllib.quote(urllib.unquote(attack_padding)[::-1])
    ret = gao(attack_padding, hash_value)
    if "Welcome" in ret:
        print ret
        break

我们就只要修改find_hash得值就可以了!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用MD5实现hash长度扩展攻击 By Assassin 的相关文章

随机推荐

  • UIKeyboard键盘相关知识点-IOS开发

    一 键盘风格 UIKit框架支持8种风格键盘 java view plain copy print typedef enum UIKeyboardTypeDefault 默认键盘 支持所有字符 UIKeyboardTypeASCIICapa
  • 08.animation-----05.旋转

    1 旋转是将元素沿着x y z轴以指定的角度旋转 旋转方向为顺时针 单位可以为deg也可为turn 2 旋转也是使用transform标签 使用以下函数 rotatex 使元素沿着x轴旋转 rotatey 使元素沿着y轴旋转 rotatez
  • 微信小程序-天气预报案例之和风天气API-云开发版

    小程序 天气预报 在现实生活中是非常常用的 我们平时都可以通过自己的手机上面或网上进行查看天气等等 鉴于有些小伙伴对云开发不熟悉 学习请移步到我的另外一篇文章 天气预报之和风天气 简易版 这个demo可以应用到自己的小程序模块上 前期准备
  • 面试华为软件测试岗,收到offer后我却毫不犹豫拒绝了....

    我大学学的是计算机专业 毕业的时候 对于找工作比较迷茫 也不知道当时怎么想的 一头就扎进了一家外包公司 一干就是2年 我想说的是 但凡有点机会 千万别去外包 在深思熟虑过后 决定要提升自己 也发现自己身边的人都是在大厂上班 也听他们说了大厂
  • 第十章 os.path模块

    1 os path模块介绍 os 模块是Python 内置的与操作系统功能和文件系统相关的模块 该模块的子模块os path 是专门用于进行路径操作的模块 常用的路径操作主要有判断目录是否存在 创建目录 删除目录和遍历目录等 说明 在使用o
  • 腾讯视频url获取方法

    总公式 url fn vkey 第一步 复制视频地址 步骤如下 点击复制通用页面地址 第二布 http vv video qq com getinfo vid m00253deqqo platform 101001 charge 0 oty
  • [激光原理与应用-34]:《光电检测技术-1》- 光学测量基础 - 光电检测、光学测量、作用、应用、发展趋势

    目录 第1章 光学测量概述 1 1 什么是光学检测 1 2 光学检测的重要作用 1 3 计量 1 4 测量 1 5 光学测量的特点与优点 第2章 光的测量范围与相应技术手段 2 1 光的辐射度量与光度量的测量 2 2 非光物理量的光学测量
  • PAT Basic Level 1075 链表元素分类(静态链表)

    题目链接 点击查看 题目描述 给定一个单链表 请编写程序将链表元素进行分类排列 使得所有负值元素都排在非负值元素的前面 而 0 K 区间内的元素都排在大于 K 的元素前面 但每一类内部元素的顺序是不能改变的 例如 给定链表为 18 7 4
  • 机器学习岗位面试问题汇总 之 深度学习

    自己结合网络内容总结 欢迎指正欢迎补充 最新更新 20170624 版本2 增加22 28 1 模式识别 机器学习 深度学习的区别与联系 模式识别 过去 程序 机器做智能的事 决策树等 机器学习 热点领域 给数据 学习数据 深度学习 前言领
  • C++类声明和成员函数定义

    C 类声明和成员函数定义的分离 在C 中 一般做法是将类的声明放在指定的头文件中 程序员如果想用该类 只要把有关的头文件包含进来即可 不必在程序中重复书写类的声明 以减少工 作量 提高编程的效率 由于在头文件中包含了类的声明 因此在程序中就
  • SAP BAPI_ACC_DOCUMENT_POST记账码问题

    今天遇见一个问题 使用BAPI ACC DOCUMENT POST过账 或BAPI ACC DOCUMENT CHECK检查数据 时 报错 借 贷标记不一致 刚开始以为是数据的问题 调试后发现数据的借贷平衡 金额也没有问题 联想到记账码是通
  • 互联网“香饽饽”?数据挖掘或成热门行业

    何为 数据挖掘 信息化社会的高速发展下 大数据 云计算 物联网等技术应运而生 海量的数据资源逐渐在人们的生产生活中高速地产生 积累 带动全社会迈入了大数据时代 这些代表信息的数据就好像大海 而要在广阔的大海里面找到想要的某一条信息或知识 也
  • Sqlserver2019对应驱动版本+完美解决sqlserver驱动版本问题

    我使用的是Sqlserver2019 mssql jdbc 7 4 1 jre8 jdk1 8 有时候不知道自己电脑上sqlserver对应的驱动版本 可以在idea中查看 idea会自动查找对应驱动版本的 首先 打开IDEA 点开右面的D
  • maven配置华为云镜像

    第一步 在maven的目录中找到配置文件 D softwaretools apache maven 3 5 4 conf settings xml 第二步 配置华为云服务器 在server标签下粘贴
  • springboot常用注解详解

    在springboot中 经常会用到一些注解 它们各自代表着什么呢 在这个属于我们的节日里 快来了解一下吧 1 SpringBootApplication 一般不会主动去使用它 但是要知道它是一个组合注解 Configuration Ena
  • java-php-python-ssm校园统一网络授课平台系统计算机毕业设计

    java php python ssm校园统一网络授课平台系统计算机毕业设计 java php python ssm校园统一网络授课平台系统计算机毕业设计 本源码技术栈 项目架构 B S架构 开发语言 Java语言 开发软件 idea ec
  • benchmarking graph neural networks 翻译

    摘要 图神经网络 GNN 已成为分析和学习图数据的标准工具包 随着领域的发展 确定关键架构并验证可推广到更大 更复杂的数据集的新思路变得至关重要 不幸的是 在缺乏具有一致实验设置的标准化基准的情况下 评估新模型的有效性变得越来越困难 在本文
  • 【DLL】【一文搞懂】【学习笔记】(四)GetProcAddress函数

    官方文档 GetProcAddress 函数用于获取DLL中导出函数的地址 显式链接时使用 GetProcAddress将 DLL 模块处理 由LoadLibrary 或 GetModuleHandle 返回的参数 并采用要调用的函数的名称
  • 第四章 Verilog 逻辑设计介绍

    第四章 Verilog 逻辑设计介绍 4 1 组合逻辑的结构化模型 介绍了verilog 原语 即一些基本的逻辑门 例化时不必写例华名 介绍了verilog module 的结构 4 2 逻辑系统的验证和测试方法 四值逻辑 0 1 x z
  • 用MD5实现hash长度扩展攻击 By Assassin

    今天心血来潮 看到了扩展攻击 猛然想到了之前看的扩展攻击的原理还没有弄懂 这里补充一下 hash长度扩展攻击到底是怎么实现的 题目 首先从实验吧上面见到的经典的题目 下面给出源码