You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/binary-exploitation/stack-overflow/pointer-redirecting.md
+55-2Lines changed: 55 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,6 +8,22 @@ If a function call is going to use an address of a string that is located in the
8
8
9
9
If for example a **`system`** function call is going to **use the address of a string to execute a command**, an attacker could place the **address of a different string in the stack**, **`export PATH=.:$PATH`** and create in the current directory an **script with the name of the first letter of the new string** as this will be executed by the binary.
10
10
11
+
In real targets, **repointing a stack string pointer is usually more interesting than just changing the printed text**:
12
+
13
+
- Redirect a later **`system`/`popen`/`execl*`** argument to an existing `"/bin/sh"` or attacker-controlled command string already present in memory.
14
+
- Redirect a later **read** sink such as **`puts("%s", ptr)`** or **`write(fd, ptr, len)`** to leak stack, heap or binary data.
15
+
- Redirect a later **write** sink such as **`strcpy(dst, ...)`**, **`memcpy(dst, src, len)`**, or a structure field assignment through `ptr->field = value` to turn the stack overflow into a **second-stage arbitrary write**.
16
+
17
+
When auditing, prioritise stack locals such as **`char *cmd`**, **`char *path`**, **`char *buf`**, **`FILE *fp`**, or **pointers inside temporary request/response structs** that are used **after** the overflow but **before** the function returns. This is especially useful when the overflow cannot safely reach the saved return address because of a canary or because corrupting a nearby pointer is enough.
18
+
19
+
If the corruption is limited to a **partial overwrite** (for example because the bug appends a `0x00`), try to redirect the pointer to:
20
+
21
+
- A nearby string in the **same stack frame**
22
+
- Another object in the **same module / non-PIE image**
23
+
- A controlled region whose **high bytes stay unchanged**
24
+
25
+
For the related ASLR-oriented case where a trailing NUL modifies an **existing stack pointer** instead of a dedicated local variable, check [Ret2ret & Reo2pop](../common-binary-protections-and-bypasses/aslr/ret2ret.md).
@@ -18,15 +34,52 @@ You can find an **example** of this in:
18
34
19
35
Same as string pointer but applying to functions, if the **stack contains the address of a function** that will be called, it's possible to **change it** (e.g. to call **`system`**).
20
36
37
+
Useful targets are not only explicit callback variables such as `void (*fp)()`. In practice, look for:
38
+
39
+
-**Callbacks stored in local structs** passed later to helper functions
40
+
-**Destructor / cleanup handlers** invoked on error paths
41
+
-**Parser dispatch tables** or **state-machine handlers** copied to the stack
42
+
-**Local structs / objects** that later dispatch through an indirect call
43
+
44
+
In modern exploitation, **pointer redirection is often the last primitive available before touching the canary**. A 2024 exploitation writeup for CVE-2024-20017 shows the typical pattern: the overflow reaches several local variables before the stack canary, the attacker corrupts a **stack pointer plus its associated length/value**, and a later assignment through that pointer becomes an **arbitrary write** without ever needing to return through the corrupted frame.
45
+
46
+
### Pointer corruption to second-stage primitives
47
+
48
+
If a nearby pointer is later dereferenced for a store, the goal is usually not to jump directly with the first overflow, but to **upgrade the primitive**:
49
+
50
+
1. Overflow a local buffer and corrupt a **pointer** plus any associated **length / integer / index**.
51
+
2. Wait for the function to perform a **post-overflow dereference** such as `ptr->len = x`, `memcpy(ptr, src, n)` or `*ptr = value`.
52
+
3. Use that resulting **write-what-where** to overwrite a GOT slot, callback, config pointer, or another indirect callsite.
53
+
54
+
This is a good option when:
55
+
56
+
- The bug stops at the canary
57
+
- The function pointer itself is not directly reachable
58
+
- A 4-byte or 8-byte **data write** is easier to get than an immediate control-flow hijack
59
+
60
+
The same idea also works for **read** primitives if the corrupted pointer is later passed to logging, printing, or network send helpers.
61
+
62
+
### Modern AArch64 note: PAC / BTI
63
+
64
+
On current AArch64 targets, a classic **saved return address overwrite** may fail because the epilogue authenticates `x30` with PAC. In those cases, **non-return hijacks** such as corrupted local function pointers or callback pointers become more attractive.
65
+
66
+
However, if **BTI** is enabled, the overwritten indirect-call target must still land on a **valid landing pad** (typically a function entry with **`bti c`**, or in PAC-enabled code a prologue starting with **`paciasp`/`pacibsp`**). Therefore, when redirecting a stack function pointer on AArch64, prefer:
67
+
68
+
- Real function entries instead of mid-function gadgets
69
+
- Targets whose prologue already satisfies BTI
70
+
- Targets where the indirect-call pointer is not additionally authenticated before use
71
+
72
+
For a related AArch64 stack-overflow context, check [ret2win-arm64](ret2win/ret2win-arm64.md).
0 commit comments