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/common-exploiting-problems.md
+133-1Lines changed: 133 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,7 +35,139 @@ In order to bypass this the **escape character `\x16` must be prepended to any `
35
35
36
36
**Here you can**[**find an example of this behaviour**](https://ir0nstone.gitbook.io/hackthebox/challenges/pwn/dream-diary-chapter-1/unlink-exploit)**.**
When an Android app ships only a stripped AArch64 `.so`, you can still fuzz exported logic directly on-device without rebuilding the APK. A practical workflow:
41
+
42
+
1.**Locate callable entry points.**`objdump -T libvalidate.so | grep -E "validate"` quickly lists exported functions. Decompilers (Ghidra, IDA, BN) reveal the real signature, e.g. `int validate(const uint8_t *buf, uint64_t len)`.
43
+
2.**Write a standalone harness.** Load a file, keep the buffer alive, and call the exported symbol exactly as the app would. Cross-compile with the NDK (e.g. `aarch64-linux-android21-clang harness.c -L. -lvalidate -fPIE -pie`).
3. **Reconstruct the expected structure.** Error strings and comparisons in Ghidra showed the function parsed strict JSON with constant keys (`magic`, `version`, nested `root.children.*`) and arithmetic checks (e.g., `value * 2 == 84` ⇒ `value` must be `42`). Feeding syntactically valid JSON that progressively satisfies each branch lets you map the schema without instrumentation.
76
+
4. **Bypass anti-debug to leak secrets.** Because the `.so` imports `snprintf`, override it with `LD_PRELOAD` to dump sensitive format strings even when breakpoints are blocked:
77
+
78
+
<details>
79
+
<summary>Minimal snprintf leak hook</summary>
80
+
81
+
```c
82
+
#define _GNU_SOURCE
83
+
#include <dlfcn.h>
84
+
#include <stdarg.h>
85
+
#include <stdio.h>
86
+
#include <string.h>
87
+
88
+
typedef int (*vsnprintf_t)(char *, size_t, const char *, va_list);
89
+
90
+
int snprintf(char *str, size_t size, const char *fmt, ...) {
int ret = real_vsnprintf(str, size, fmt, args_copy);
105
+
va_end(args_copy);
106
+
va_end(args);
107
+
return ret;
108
+
}
109
+
```
110
+
111
+
112
+
</details>
113
+
114
+
`LD_PRELOAD=./hook.so ./validate_harness payload.json` exfiltrates the internal flag and confirms the crash oracle without patching the binary.
115
+
5.**Shrink the fuzz space.** Disassembly exposed an XOR key reused across the flag comparison, meaning the first seven bytes of `flag` were known. Only fuzz the nine unknown bytes.
116
+
6.**Embed fuzz bytes inside a valid JSON envelope.** The AFL harness reads exactly nine bytes from `stdin`, copies them into the flag suffix, and hard-codes every other field (constants, tree depths, arithmetic preimage). Any malformed read simply exits, so AFL spends cycles on meaningful testcases.
117
+
118
+
<details>
119
+
<summary>AFL-friendly harness for structured JSON</summary>
if (len <= 0 || (size_t)len >= sizeof(json)) return 0;
146
+
validate((unsigned char *)json, len);
147
+
return 0;
148
+
}
149
+
```
39
150
151
+
</details>
40
152
153
+
7. **Run AFL with the crash-as-success oracle.** Any input that satisfies every semantic check and guesses the correct nine-byte suffix triggers the deliberate crash; those files land in `output/crashes` and can be replayed through the simple harness to recover the secret.
41
154
155
+
This workflow lets you triage anti-debug-protected JNI validators quickly, leak secrets when needed, then fuzz only the meaningful bytes, all without touching the original APK.
0 commit comments