init_array与got劫持——[zer0pts 2020]easy strcmp
只是在顺思路,wp参考了2位大佬
[Zer0pts2020]easy strcmp 分析与加法-CSDN博客
题目
Die
虚拟机运行一下
没有输入,直接报错退出了
IDA
很奇怪啊,就是一个比较
从我们运行直接报错来看,我们运行时a1>1这个条件是不成立的
我的最初思路就是调试把a1改了或者把判断汇编指令改了,让我进入if里面看看
IDA动调
下好断点
改汇编
F8到strcmp,继续F8,出现一个弹窗
55BB41600714:得到 SIGSEGV 信号(分段违规)(exc.code b,tid 4929)
点击OK,跳到了一个地方
F5
这个函数进行了一个简单的每位相减操作,这里应该就是加密函数,加密后的数据要与zer0pts{********CENSORED********}相等
如果是解题的话,思路不是很难
真正让我思考的是NSSCTF师傅的几行字—— 这道题的考点与原理是什么?
知识点
1. init_array
- init_array 是一个段(section),在很多操作系统和编译器中,这个段会包含程序启动时需要执行的一些初始化函数。
- 当一个程序启动时,操作系统或运行时会依次调用这些函数。开发者可以把一些初始化代码放在这些函数中,以便在主程序(main函数)运行之前执行。
2. GOT劫持
- GOT 全称是 Global Offset Table(全局偏移表),它是用来实现动态链接库(DLL)的一种机制。
- 在程序运行时,函数的实际地址会被加载到 GOT 中。每次调用动态链接库中的函数时,程序会通过 GOT 找到函数的实际地址。
- GOT劫持 是一种常见的攻击技术,通过修改 GOT 中的函数地址,将其指向攻击者的代码,从而劫持函数的执行流。例如,将一个常用函数(如
strcmp
)的地址改为攻击者的代码地址。解题思路
1. 在init_array中hook了strcmp
- hook 是一种技术,允许开发者或攻击者拦截并替换函数的执行。在这个题目中,通过修改 init_array 段中的某个初始化函数,将
strcmp
函数进行 hook(拦截)。- 具体来说,可能是程序在初始化时,修改了 GOT 中
strcmp
的地址,将其指向一个自定义的函数。2. 分析hook代码,得到flag
-
需要找到并分析这个自定义的函数,看看它如何拦截
strcmp
的调用。 -
通常,这个自定义的函数会包含一些逻辑,用于检查输入或直接返回某个特定的值(如 flag)。
-
通过逆向分析这个自定义函数,理解它的行为,从而找出程序隐藏的 flag。
那看看init函数
发现for循环里面,将funcs_889地址作为指针,进行调用
这里刚好就是init_array
(题外话:我搜索了一下IDA中怎么找init_array,但是只找到安卓的教程,知道的师傅可以告诉我吗?)
第一个sub_6E0,追踪进去没什么东西,重点在第二个sub_795
它把strcmp的地址赋给了qword_201090
这个qword_201090有没有觉得很熟悉?
所以return中进行的才是真正的比较函数,这也再次坐实了a1就是加密后的数据,a2就是zer0pts{********CENSORED********}——加密后的数据与其比较
接下来看看strcmp在got表中的地址:00000000002010B0
接着红框里的代码,sub_6EA就是加密函数
off_201028在IDA中其实就等于00000000002010B0
不过不知道也没事,跟踪一下off_201028
off_201028在_got_plt中原本应该指向strcmp的地址,但是在sub_795被改成指向加密函数sub_6EA
到这里我才完全搞懂了大佬说的知识点与解题思路是什么意思——在初始化的时候,init_array中调用sub_795,将原本在got_plt中存放strcmp的地址改成sub_6EA,而真正的strcmp变成了qword_201090
EXP
cipher = bytearray(b"zer0pts{********CENSORED********}") key = [ 0, 4686632258374338882, 796841318371695088, 5695428477452625963, 0 ] # 将 cipher 视为 unsigned long long 的数组 for i in range(5): # 将前8个字节转换为 unsigned long long value = int.from_bytes(cipher[i*8:(i+1)*8], 'little') # 进行加法操作 value += key[i] # 将结果转换回字节并存入 cipher cipher[i*8:(i+1)*8] = value.to_bytes(8, 'little') print(cipher.decode())
flag
zer0pts{l3ts_m4k3_4_DETOUR_t0d4y}