2025.09.04-NullconCTFBerlin-Fotispy1
题目简介
赛题链接见:2025-09-04 NullconCTFBerlin fotispy1
漏洞点分析
题目给了一个ELF、一个.so和一个ld,所以首先用patchelf修改程序对应的libc和ld
1 | |
如图,替换成功后才能开始分析
之后运行程序,发现是一个菜单类型程序,提供了注册、登录、添加、显示四大功能,经过尝试发现必须注册、登录后才能添加歌曲
再checksec看一下,发现只开了NX:
然后拖进IDA看一下,首先观察main函数,这里先把main里一些重要函数和变量重命名成人类可读的形式,如图:
初步观察一下IDA左侧的plt表,不存在free函数,因此大概率和堆利用无关,是一个溢出题,所以要寻找溢出点
因此重点排查各个输入函数,看有没有溢出,首先看程序自制的读取输入函数get_input,如图:
第一眼看过去怀疑有off-by-one,但是代入程序中的maxSize参数=256计算一下,并结合deepseek分析,发现limit设置的没问题,没办法溢出
再回到main函数,分析reg和login函数,首先看注册函数:
注意到上图的17、18行username和passwd的存储位置,一个在qword_4040A0+v3,一个在它后面8个字节,分析得出username和passwd大概率是一个结构体类型
同时每一个结构体都存储在位于0x4040A0的一个数组类型的全局变量里
综合上述信息可以把reg函数变得更加可读一些,如图:
然而进一步分析发现并没有什么可用的溢出点,只是当username输入过长时会把后半部分当作passwd存起来,但好像对我们控rip并没什么用?
再看loging函数,如图:
发现calloc的大小完全超过了get_input设定的最大大小,因此这里也没有可用的溢出点
接着看add函数,如图:
结合之前运行程序的输出,以printf的交互信息作为线索,可以依次恢复v7、v8、v9的含义,并且结合猜出user结构体的经验,可以大胆猜测歌曲的title、who和album三个信息是存储在某个结构体里的
综上,得到可读的add函数如图:
但是,这个函数貌似也没有栈溢出?最有用的是泄露了一个printf函数的地址,现在我们因此有了关于libc的一切
最后只能看show函数了,有了分析add函数的经验,可以很容易恢复show函数的可读信息,如图:
但是,show函数里没有输入的交互点,看起来没有溢出?
不,注意到memcpy的拷贝大小实际是我们可控的,因为在add里面,我们输入的title、who和album三个成员的大小是由get_input返回的,最大可到256,但是dest距离返回地址只有0x15+0x8个字节,远远小于256,因此show函数里面存在溢出
综上,利用思路为:利用2号功能输入payload,调用3号功能劫持show函数的返回地址从而ret2libc
漏洞点利用
利用时还存在两个注意点:
第一,注意到show函数在走到ret指令之前会对rax解引用一次,而通过调试发现这个rax的值来自rbp-8,如图:
因此要控制rbp-8的值为可解析的地址,这里首先想到把printf的地址喂给rax,但这样会导致另一个问题:下面的jne指令会跳转从而到不了ret
因此第二个注意点即不仅要保证rbp-8有效,而且那个地址里的内容必须是0
这里通过vmmap查看程序区段,去bss段里面找0字节(因为程序的bss段一般会初始化=0),如图:
可以看到有很多地址里面有0字节,这里随便选择一个即可
综上,写出利用脚本如下:
1 | |