init_array与got劫持——[zer0pts 2020]easy strcmp

只是在顺思路,wp参考了2位大佬

文章列表 | NSSCTF

[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}
posted @ 2024-06-09 22:50  C4emc1oudy  阅读(16)  评论(0编辑  收藏  举报