记pwn萌新解题的辛酸历程,写的尽量详细,让和我一样的小菜鸡都能看的明白清楚。
参考前辈的文章
https://cq674350529.github.io/2018/06/05/asis-ctf-2016-pwn-b00ks/
https://bbs.pediy.com/thread-225611.htm
写的非常清楚明白
首先用checksec查看一下b00ks文件的保护,发现开启了PIE,Full RELRO。
为了调试的时候方便,暂时关闭系统的地址随机化功能 echo 0 > /proc/sys/kernel/randomize_va_space
然后用ida打开分析程序的具体功能。
b00ks是常见的图书管理系统,功能如下:
off_by_one的漏洞位于如下函数:
当输入author name的时候,如果输入的字符串长度为32时,会溢出一个字节‘\00’。实际想内存中写入了33个字符。
分析create函数中如下代码
可知book_struct的结构如下:
struct book_struct
{
int id;
void * book_name;
void *book_description;
int description_size;
}
大小为32个字节。
并且book_struct的同意存放在一个静态的数组中管理global_struct_array中,以及author存放的地址也是一个静态的地址。
可知offset_book_strcut - offset_author_name = 0x20,恰好和之前分析的author_name输入时的off_by_one漏洞所需的字符串长度吻合。
因此,我们可以知道当author_name的长度为32B时,结束符‘/00’会溢出到global_struct_array的第一个数组元素当中去,然后如果我们create一个book之后,'\00'结束符会被覆盖掉,因此打印author_name的时候可以将global_struct_array的第一个元素泄露出来,即泄露出addr_book1。
调试程序看一下具体效果,因为我们不知道程序加载的基址,所以调试的时候下断点不方便,因此通过如下办法获取程序加载的基址(因为我们调试的时候为了方便已经禁用了PIE,所以多次加载程序的基址不变):
首先gdb b00ks,然后r运行程序。
程序启动之后,通过 cat /proc/pid/maps获取程序的内存信息,可知程序加载的基址为0x555555554000。因此之后设置断点时 基址+ida地址 = 实际运行的地址。
当输入author_name = 'a'*32后,查看内存信息如下:
x/10xg 0x555555554000+0x202040
溢出的'\00'的位置如图中标注所示
在create一个book_struct之后,内存信息如下所示,可以看到author_name的结束符被覆盖,通过打印author_name的信息可以将addr_book1的信息泄露。
然后在继续create book2,通过查看内存地址信息,可以知道addr_book2-addr_book1=0x30。因此exp的时候可以通过泄露addr_book1来得到addr_book2的信息。
然后在运用change_author_name的功能,重新溢出一个字节‘\00',然后global_struct_array中的第一个元素的地址改变,我们可以通过为book1_description申请大一点的空间,来使的被修改后
global_struct_array中的第一个元素的地址指向book1_description内的地址,然后我们可以在相应的地址重新伪造一个book1_struct。因为有print description以及edit description的功能,所以我们通过伪造book1_struct的description使其指向任意地址,通过打印或者edit来实现任意地址的读写。
change_author_name来实现溢出'\00',可以看到global_struct_array中的第一个元素地址由0x0000555555758160被改为0x0000555555758100,即指向了我们伪造的book1_struct。然后我们伪造的struct结构如下:
{
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2019-10-30 22:55
被Seclusion编辑
,原因: