前言

最近在做CTF题的时候遇到这个考点,想起来自己之前在做实验吧的入门CTF题的时候遇到过这个点,当时觉得难如看天书一般,现在回头望去,仔细琢磨一番感觉也不是那么难,这里就写篇文章记录一下自己的学习的过程。

正文

何为HASH长度拓展攻击?

简单的说,由于HASH的生成机制原因,使得我们可以人为的在原先明文数据的基础上添加新的拓展字符,使得原本的加密链变长,进而控制加密链的最后一节,使得我们得以控制最终结果。

这里我们以MD5加密算法为例子。

MD5长度拓展攻击

下面是个简单的PHP例子。

<?php
include "flag.php";
$secretKey = 'xxxxxx'; #xxx为未知内容,但长度已知为6。
$v1 = $_GET['str'];
$sign = $_GET['sign'];
$token = md5($secretKey.$v1);
if($v1 === 'test') {
die($token); #token=2df51a84abc64a28740d6d2ae8cd7b16
} else {
if($token === $sign) {
die($flag);
}
}
?>

在这个例子中,我们需要使得变量$token与我们输入的sign参数满足一致才会输出flag。

而由于我们无法知道变量$secretKey的内容,所以无法得到$token的值,故而看似是没有办法获取到flag的死局,而这时便轮到我们的拓展攻击来大显身手了。

MD5算法流程

若想搞清楚原理,其算法的流程是必须了解的。不过我们无需去关心那些复杂的运算,只需要知道的大概的一个流程就OK了。

这里借一张神图:

摘自:哈希长度拓展攻击(Hash Length Extension Attacks)

看不懂也没关系,相信你看完我这篇文章后再返回来看这张图就很清晰明了了。

我们还是举个例子,对于字符串aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbb(64个a、3个b)。长度为19个字符,且根据ASCII表,字符a、b的十六进制分别为0x61、0x62。

而我们知道,1位十六进制相当于4位二进制表示(16=2^4)。所以对于64个字符a的长度来说,其二进制长度为:字符长度*二进制位数2*十六进制转二进制位数拓展4=64*2*4=512

对于MD5算法来说,我们需要将原数据进行分块处理,以512位个二进制数据为一块。”最后“一块的处理分为以下几种情况:

  • 明文数据的二进制数据长度<=448,填充padding(无意义占位)数据使其长度为448,再添加原始明文数据的二进制长度信息(64位)使其长度为512位即可。
  • 448<明文数据的二进制数据长度<=512,填充padding数据至下一块的448位,而后再添加原始明文数据的二进制长度信息(64位)使其长度为512位即可。

两种情况如下图:

注意:每块数据的长度均为512位二进制,图中的数据我没有全都用二进制来表示,将明文数据分块之后就可以与向量进行运算了。

对于padding数据(长度不定)来说:首位二进制位1,其余位为0.

对于长度信息位(长度8Byte=64bit)来说,从低位向高位数,如上图的长度信息:f0 03 00 00 00 00 00 00即代表0x03f0,其对应的十进制为1008,即为64+62=126个字符的二进制位数(一个字符1Byte即8bit)。

对于MD5算法来说,有一串初始向量如下:

A=0x67452301
B=0xefcdab89
C=0x98badcfe
D=0x10325476

这串初始向量的值是固定的,作为与第一块数据运算的原始向量。

当这串向量与第一块数据块运算之后,得到了一串新的向量值,这串新的向量值接着与第二块数据块参加运算,直到最后一块数据块。

如下图所示:

而最后的MD5值就是这最后的向量串经过如下转换的结果。

如向量串:

A=0xab45bc01
B=0x6a64bb53
C=0x23ba8afe
D=0x46847a62

先两两为一组进行组合,得到如下数据:

ab 45 bc 01
6a 64 bb 53
23 ba 8a fe
46 84 7a 62

再进行高低位互换,得到如下数据:

01 bc 45 ab
53 bb 64 6a
fe 8a ba 23
62 7a 84 46

最终拼接得到MD5值:01bc45ab53bb646afe8aba23627a8446

现在,让我们回到开始的那个例子。

对于MD5值:2df51a84abc64a28740d6d2ae8cd7b16。我们可以根据MD5与向量互转规则,将MD5转成md5($secretKey + "test")的最终向量值(A'、B'、C'、D'):

A'=0x841af52d
B'=0x284ac6ab
C'=0x2a6d0d74
D'=0x167bcde8

过程如图:

这时候我们修改$v1变量的内容为:

"test" + [0x80 + (0x0)*45] + [0x50 + 0x0*7] + "abc"
相当于:
"test" + padding数据 + 长度数据 + "abc"

则上述过程则被延续成下图所示:

而对于上述运算过程来说,我们知道了倒数第二个向量串的内容和最后一个数据块,这样一来,最终的MD5值我们也可以自己通过MD5算法计算出来了。

拓展

如同MD5算法那般分组后与向量运算的流程被统称为Merkle–Damgård结构。

而同样使用此结构的HASH算法还有:SHA1、SHA2等

hashpump

hashpump是一个专门生成MD5长度拓展攻击payload的工具。

Github仓库:https://github.com/bwall/HashPump

安装方法:

#Linux
git clone https://github.com/bwall/HashPump.git
apt-get install g++ libssl-dev
cd HashPump
make
make install

安装好之后在终端里输入hashpump,回车即可:

以之前的例子为例,使用hashpump生成payload:

故我们的EXP即为(\x%代替):

/?str=test%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%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00P%00%00%00%00%00%00%00abc&sign=bac6cb2d585d2de3f5f48f2759d2e5a7

成功读取FLAG:

CTF

相关CTF题可供练习:

  • [De1CTF2019]SSRFMe
  • 实验吧-让我进去

后记

其实这个知识点确实不难,但是回看两年前的自己,那时候是真的完完全全看不懂看不明白,但是现在只花了十几分钟就可以说是掌握这个知识点了。原来我们不知不觉间也对知识的认知又提升了一个台阶,原先难如天书的内容现在看来也不过尔尔,原先看不到、接触不到的知识,现在也有信心能够去尝试去学习、去理解并掌握。学习本该如此,如攀登高山一般,只有开始攀登,才有机会看得到山脚下看不到的风景,也唯有不断攀登,才能看到更多更多风景。

参考

最新文章

  1. windowsAPI遍历文件夹(速度高于递归)
  2. vue-新建项目出错情况分析
  3. AJAX,JSON搜索智能提示
  4. Android之访问下载文件
  5. 团体程序设计天梯赛-练习集L2-007. 家庭房产
  6. CentOS下防火墙的基本操作命令
  7. 第十一章、认识与学习 BASH 数据流重导向
  8. Dialog与FragmentDialog源代码分析
  9. 创建js对象和js类
  10. PHP实现插入排序算法
  11. Collection的迭代器Iterator
  12. oracle索引建立和删除
  13. javaweb web.xml文件详解
  14. QPointer,QSharedPointer,QWeakPointer的区别
  15. 深入探讨JavaScript如何实现深度复制(deep clone)
  16. android studio 3.0 集成ijkplayer
  17. FakeID签名漏洞分析及利用(一)
  18. 第三百八十三节,Django+Xadmin打造上线标准的在线教育平台—第三方模块django-simple-captcha验证码
  19. Web 通信 之 长连接、长轮询(转)
  20. linux -- 注销,关机,重启

热门文章

  1. windows 下部署 .netcore 到 windows service
  2. 19、Java 序列化
  3. Django中间件之实现Admin后台IP白名单
  4. Java 多态 接口继承等学习笔记
  5. 申请支付宝app支付签约综合评分不足,拒绝不通过快速强开通支付宝App支付强开,强开支付宝App支付产品权限!
  6. XCTF-WEB-新手练习区(5-8)笔记
  7. 企业级Gitlab-ci实践
  8. ReentrantLock与synchronized 源码解析
  9. menset与fill
  10. 树莓派 4B VNC Viewer 显示 cannot currently show the desktop 的解决方法 (图文)