-
-
[原创]gdb在逆向爆破中的应用
-
发表于:
2024-6-10 16:56
3123
-
配套视频:https://www.bilibili.com/video/BV1gc411k7Bm/
1.概述
一般题目的抽象如下
一般来说,数据处理的过程有分为3种
- 输入的字符整体为一块,明文中任何一个字符改变都会改变密文。
- 非对称加密:RSA,ECC,抗量子算法,SM2,SM9
- 哈希算法:MD5,SHA,SM3,校验算法
- 其他:整除(base58),VM
- 输入的字符分块,明文中一个字符改变只会改变一块密文
- 分组加密:DES,AES,TEA,SM1,SM4,SM7
- 其他:传统base类(base64,32,16,85,),VM
- 逐字节加密,明文中改变一个字符只会改变密文的一个字符
- 古典密码:替换
- 流密码:RC4,ZUC,SSF46
- 其他:VM
综上所述,我们可以将所有的加密都看成块加密,只是有的块包含所有字符、有的块是固定长度、有的块只有一个字符。一般来说,块越大,算法解密难度越大,同样算法的理论依据也越深奥,实现也越复杂。能够在ctf
中使用爆破解决的原因主要有以下两点。
- 一组加密字数越少,算法能力需要越低,算法理论知识需求越少,题目越容易控制。
- 逆向师傅大都不具备自定义可逆块加密的能力。
2.基本思路
对于逐字节加密的算法爆破思路如下
- 输入flag,控制第一个字符
- 执行到判断处
- 将加密后的数据与密文判断,当与密文第一个字符一样时,则可以确定明文的第一个字符。
- 从第一步重复执行。
3.工具
1.工具的选择
- 真实执行:
gdb windbg(最新版脚本可以自动补全) ida frida radare2 ghidra
- 模拟执行:
angr unidbg unicorn
本人使用过的一些工具对比如下表
<span style="display:inline-block;width: 40px"> 工具</span> |
<span style="display:inline-block;width: 200px">优点</span> |
<span style="display:inline-block;width: 200px"> 缺点</span> |
gdb |
速度快,文档详细 |
windows 配置复杂,需要对C语言调用方式非常了解 |
windbg |
windows 亲儿子, |
不支持linux ,terminal 下的题目速度慢 |
ida |
不解释 |
linux 需要远程调试,terminal 下的题目速度慢,文档垃圾 |
frida |
速度快,对程序的抽象层与C语言一致 |
大部分情况需要patch 程序,文档垃圾 |
radare2 |
功能非常全面,丰富的API |
ASLR 、输入重定向等2个问题目前没找到解决方案 |
angr |
所有内存都方便操作 |
模拟执行的问题它都有,只能做备用方案 |
就本人的使用经验推荐工具排序如下
- gdb:地表最强动态调试器不解释。缺点就是相对
frida
复杂很多,需要对内存布局比较熟练才可以。
- frida:对于与C语言抽象层一样的程序块,非常推荐,代码编写速度很快。在
android
等不方便使用gdb
的环境下,frida
非常优秀。不过我必须要吐槽一下,frida
文档写的真是垃圾。
- ida/windbg:这两个是图形化的工具,由于需要爆破的题目大都是
terminal
下的,爆破内存还好,如果从输入端开始爆破,则每次都要启一个terminal
,爆破过程非常缓慢。
- radare2:这个工具也非常推荐,有着丰富的API,只是由于
ASLR
、输入重定向等2个问题目前没找到解决方案,所以没有使用,下一步还要认真研究。
- angr:模拟执行是爆破中最不推荐的,模拟执行的问题它都有,只能做备用方案。
2.windows
下的gdb
使用
需要下载minggw
:https://www.mingw-w64.org/
。
3.亟需解决的困难
- 地址随机化问题
- linux:gdb 会关闭 ASLR
- windows:修改
dynamic-base
标识位
- 输入重定向问题
- bash:<
- cmd:<
- powershell:
Get-Content .\aaa.txt | a.exe
4.举个栗子(2023年安洵杯_ez_cpp)
1.题目分析
题目的对比流程非常符合爆破特征,所以先爆为敬
2.关闭地址随机化
取消选择 dynamic-base
3.获取相关信息
1.动调出密文
使用movsx
指令进行带符号扩展,所以密文只是最后一个字节即可。
1 | enc = [ 0x22 , 0xA2 , 0x72 , 0xE6 , 0x52 , 0x8C , 0xF2 , 0xD4 , 0xA6 , 0x0A , 0x3C , 0x24 , 0xA6 , 0x9C , 0x86 , 0x24 , 0x42 , 0xD4 , 0x22 , 0xB6 , 0x14 , 0x42 , 0xCE , 0xAC , 0x14 , 0x6A , 0x2C , 0x7C , 0xE4 , 0xE4 , 0xE4 , 0x1E ]
|
2.加密后的明文地址
3.比较处的地址
4.爆破
1.存在的问题
在爆破过程中发现问题如下
打开保存的文件查看存在2个问题
- 第2个字符是
?
,显然不正确
- 第4个字符是
a
,程序崩溃
修改相应代码后继续爆破
2.问题分析
爆破结果如下,比赛时我就提交了这个SYC{Y3S-_E5-_0[-S0Ve-Th3-C9P!!!}
但是不对,后来经师傅提示后,[ _
显然不是flag
内容,所以重新修改脚本。
再次爆破后得到真正flag
5.对抗
- 反调试
- 增加程序分支,尤其是加密后的程序分支。
- 循环进行加密对比,而非加密后一起对比
- 增加加密块的大小,加密块>3个字符则不具备可爆破性。
主要应对题型:2字节以内,加密算法非常复杂。
6.算法复杂度分析及提速方法
经测试,40个字符的flag,单字节爆破96*40
大约需要5分钟,双字节爆破 96 * 96 * 20
大约3个小时,linux
下更快一些。提速方法如下。
- 实体机
windows
下虚拟硬盘(10M),linux
下/dev/shm
- 优化算法
- 缩小字符串范围
- 确认提前结束循环的条件
- 采用分布式计算方式
7.其他
1.爆破任意代码段
本文中主要讲的的是如何从输入处开始爆破,实际情况是我可以爆破任意一段代码,并且在我的脚本中已经实现。具体思路如下。
- 定义起始点与结束点
- 起始点设置好上下文
- 结束点取出上下文进行对比
- 重复以上内容
在长时间的爆破过程中,我发现从输入端爆破在做题的时候更快、需要考虑的东西更少,所以大部分情况都是从输入开始爆破。只有个别情况想了解某一段代码的作用时才需要爆破任意代码段,而此时使用frida
更为方便。
2.有待完善
对于下面的程序流程需要完善脚本(2023上海磐石大赛_flag在哪里?)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)