Skip to content

Commit b4093f6

Browse files
authored
Merge pull request #1 from vrishabav/multiarch_2
Added writeup for multiarch-2
2 parents a3dd3f8 + 45bb90a commit b4093f6

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
## Summary of the Exploit
2+
3+
This challenge is built around exploiting a custom VM built with two separate instruction sets (stack‑based and register‑based)
4+
5+
Inside the register‑based instruction set, a key bug in the XOR instruction lets us write outside the space reserved for registers. This allows us to trick the VM so that a normal VM memory address (`0xA000`) actually points to the VM’s own internal state struct `masm_struct`. We can leak useful memory addresses from inside the VM, overwrite the VM function pointer `get_flag` to make it point to our shellcode and thereafter trigger that function pointer and get code execution
6+
7+
---
8+
9+
## VM Setup
10+
11+
When the VM runs, it loads a custom file format called `.masm`, each of which consists of several regions that get mapped when the VM starts:
12+
- **Code segment**: the instructions the VM runs
13+
- **Data segment**: attacker‑controlled, marked as rwx i.e. read, write, execute
14+
- **Stack segment**: where stack‑arch instructions operate
15+
- **Arch table**: tells the VM about whether each instruction runs in stack mode or register mode
16+
17+
This design means we can place custom shellcode directly into the data segment, then aim to transfer execution there
18+
19+
---
20+
21+
### VM State: `masm_struct`
22+
Internally, the VM maintains everything in a large structure `masm_struct`. It contains:
23+
- pointers to the code, data, and arch table in memory
24+
- four general registers, a stack pointer, and program counter
25+
- function pointer called **`get_flag`** at offset `0x28`, which we want to hijack
26+
- metadata about heap allocations (`heap_array`)
27+
28+
---
29+
30+
## Vulnerability: Out‑of‑Bounds XOR
31+
32+
Inside the register instruction set, there is an instruction
33+
```0x41 <idx> <imm32>` is supposed to do `registers[idx] ^= imm32```
34+
35+
The issue is that the VM never checks whether `idx` is a valid register index. By giving a large enough index, we can XOR into memory well beyond the register array, which overlaps with the `heap_array`. By crafting values, we can change one of the heap metadata pointers stored there
36+
37+
---
38+
39+
## Exploit
40+
41+
### Step 1 – Making Heap Allocation
42+
Using stack‑arch syscall `6`, we allocate a heap block. The VM maps it at virtual address `0xA000`, and internally records the mapping in `heap_array[0]` - `{ real_heap_ptr, 0xA000 }`
43+
44+
---
45+
46+
### Step 2 – Corrupting Heap Metadata
47+
We switch to register‑arch and use the buggy XOR on a big index so we land inside and overwrite `heap_array.real_ptr`. Instead of pointing to the real heap, we flip it so it points to the `masm_struct` itself. So now whenever we use `0xA000`, we are actually accessing the VM’s internal state struct
48+
49+
---
50+
51+
### Step 3 – Leaking Information
52+
We use stack‑arch syscall 2 (fwrite) to dump memory starting from `0xA000`. But `0xA000` maps `masm_struct`, so this gives us a leak of critical VM internals i.e. the real memory address of the **data segment** (`seg1`), which we control. This is the RWX memory where shellcode is already stored
53+
54+
---
55+
56+
### Step 4 – Overwriting the get_flag Pointer
57+
We now use register‑arch syscall 1 (fread) to write into VM memory (at `0xA000 + 0x28`, which resolves to `&masm_struct->get_flag` due to our corruption). We overwrite that with the leaked `seg1` address. Now whenever the VM tries to call `get_flag`, it will instead jump to our data segment where we've placed our shellcode
58+
59+
---
60+
61+
### Step 5 – Running Shellcode
62+
Finally, we use stack‑arch syscall 5, which usually calls `get_flag`. But it now points to our RWX data segment, so the syscall runs our injected shellcode
63+
64+
---
65+
66+
## Overall Exploit Flow
67+
1. Allocate heap chunk at `0xA000`
68+
2. Use buggy XOR to poison heap_array so `0xA000` maps to `masm_struct`
69+
3. Dump (`fwrite`) `masm_struct` and find seg1 address
70+
4. Overwrite `get_flag` with that address
71+
5. Call `syscall 5` → shellcode runs
72+
73+
**Credits**: 堇姬 Naup (https://naup.mygo.tw/2025/07/05/2025-Google-CTF-writeup/)

0 commit comments

Comments
 (0)