web-dev-qa-db-ja.com

ASLRはlibcエントリポイントをどのように保護しますか?

ASLRは、プロセスの実行可能コード、スタック、ヒープ、およびライブラリのアドレスをランダム化します。これは、複数のインスタンス化にわたってコード内のアドレスをハードコードできないため、攻撃者の生活を困難にするためです。

しかし、これはシステムライブラリにどのように役立ちますか?それらは決して荷を下されません。たとえば、すべてのプロセスはlibcを使用するため、prinfのアドレスは変更されません。 printfのアドレスをハードコーディングしている場合、これはどのように役立ちますか?マシンが再起動しない限り、これは変わりません。

ASLRを有効にしています-

# cat /proc/sys/kernel/randomize_va_space 
2

ここにいくつかのサンプルコードがあります-

unsigned long getEBP ( void )
{
    asm("movl %ebp, %eax");
}

int main(void)
{
    int (*p)(const char*, ...) = &printf;
    printf("printf address = %p \n", p);
    (*p)("printf address = %p\n", &printf);
    printf ("EBP:%x\n" ,getEBP ());
}

そして、複数の実行にわたる出力-

# ./a.out 
  printf address = 0x4003c0 
  printf address = 0x4003c0 
  EBP:6a71d300

# ./a.out 
  printf address = 0x4003c0 
  printf address = 0x4003c0 
  EBP:93e5c100

EBPは変更されているはずですが、printfのアドレスは変更されていません。

何が欠けていますか?

編集:-fPICを使用したコンパイルは、RHEL VMでは役に立ちませんでした。

# ./a.out 
  printf address = 0x3047a4f0f0 
  printf address = 0x3047a4f0f0 
  EBP:7aaac900

# ./a.out 
  printf address = 0x3047a4f0f0 
  printf address = 0x3047a4f0f0
  EBP:632eca20

Libc呼び出しが実際にランダム化され、応答が以下のようになっている場合、どのように実装されますか? libc自体はリロードされないため、printfの実際のアドレスは変更されません。どうすればランダム化できますか?

3
stflow

更新:

参照 https://stackoverflow.com/questions/24984955/why-arent-glibcs​​-function-addresses-randomized-when-aslr-is-enabled

を使用してバイナリをコンパイルします -fPIEまたは-fPIC-pie -fPIE

https://stackoverflow.com/questions/2463150/fpie-position-independent-executable-option-gcc-ld

デフォルトのフラグでコンパイルされたバイナリ:

user01@user01 ~/test $ ./test_ASLR 
printf address = 0x400420 
printf address = 0x400420
EBP:9af703c0
user01@user01 ~/test $ ./test_ASLR 
printf address = 0x400420 
printf address = 0x400420
EBP:8411e900
user01@user01 ~/test $ ./test_ASLR 
printf address = 0x400420 
printf address = 0x400420
EBP:28f8e50

-pie -fPIEフラグでコンパイルされたバイナリ:

user01@user01 ~/test $ ./test_ASLR 
printf address = 0x7f8227963340 
printf address = 0x7f8227963340
EBP:19e01ad0
user01@user01 ~/test $ ./test_ASLR 
printf address = 0x7fecb2baa340 
printf address = 0x7fecb2baa340
EBP:9c8148e0
user01@user01 ~/test $ ./test_ASLR 
printf address = 0x7f5d00edb340 
printf address = 0x7f5d00edb340
EBP:32b3c6d0
2
julian

デフォルトのフラグを使用してコンパイルする場合、ほとんどの場合、.textセグメントは定数アドレスに留まり、GOTはプログラムで使用される関数のポインターのリストで満たされます。これらのポインターは、遭遇したときに解決されます。この場合、GOTは一定の場所にあったため、コンパイラによってcallに直接配置されます。例 :

0x8048446 <main+35>    call   printf@plt                    <0x80482f0>

これは、printfの実際の場所がランダム化されなかったことを意味しません。これがプログラムの最初のprintfの呼び出しだった場合、_dl_runtime_resolveは適切な値を入力します。それ以外の場合は、次のようになります。

pwndbg> x/xi 0x80482f0
0x80482f0 <printf@plt>: jmp    DWORD PTR ds:0x804a00c
pwndbg> telescope 0x804a00c
00:0000│   0x804a00c (_GLOBAL_OFFSET_TABLE_+12) —▸ 0xf7e38670 (printf) ◂— call   0xf7f0eb09

これはlibc内のprintfの実際の場所です。通常の場合、&printfは実際にはprintf@pltを指します。これはlibc内の実際のprintfの単なるジャンプテーブルです。

-pie -fPIEの場合、&printfはlibcの実際のprintfを指します。このフラグは、以前は一定であったセクションにASLRを追加するだけです。どちらの場合も、ライブラリはランダムなオフセットでロードされました。

0
sudhackar