Apa yang membuat fs: [0x28] (stack canary)?

11

Dari posting ini ditunjukkan bahwa itu FS:[0x28]adalah stack-canary. Saya membuat kode yang sama menggunakan GCC pada fungsi ini,

void foo () {
    char a[500] = {};
    printf("%s", a);
}

Secara khusus, saya mendapatkan perakitan ini ..

    0x000006b5      64488b042528.  mov rax, qword fs:[0x28]                ; [0x28:8]=0x1978 ; '(' ; "x\x19"
    0x000006be      488945f8       mov qword [local_8h], rax
...stuff...
    0x00000700      488b45f8       mov rax, qword [local_8h]
    0x00000704      644833042528.  xor rax, qword fs:[0x28]
    0x0000070d      7405           je 0x714
    0x0000070f      e85cfeffff     call sym.imp.__stack_chk_fail           ; void __stack_chk_fail(void)
    ; CODE XREF from 0x0000070d (sym.foo)
    0x00000714      c9             leave
    0x00000715      c3             ret

Apa yang mengatur nilai fs:[0x28]? Kernel, atau apakah GCC memasukkan kode? Bisakah Anda menunjukkan kode di kernel, atau dikompilasi ke dalam biner yang ditetapkan fs:[0x28]? Apakah kenari dibuat ulang - saat boot, atau proses menelurkan? Di mana ini didokumentasikan?

Evan Carroll
sumber

Jawaban:

18

Sangat mudah untuk melacak inisialisasi ini, karena untuk (hampir) setiap proses stracemenunjukkan syscall yang sangat mencurigakan selama awal proses dijalankan:

arch_prctl(ARCH_SET_FS, 0x7fc189ed0740) = 0

Itu yang man 2 arch_prctldikatakan:

   ARCH_SET_FS
          Set the 64-bit base for the FS register to addr.

Yay, sepertinya itu yang kita butuhkan. Untuk menemukan, siapa yang menelepon arch_prctl, mari kita cari jejak balik:

(gdb) catch syscall arch_prctl
Catchpoint 1 (syscall 'arch_prctl' [158])
(gdb) r
Starting program: <program path>

Catchpoint 1 (call to syscall arch_prctl), 0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
(gdb) bt
#0  0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
#1  0x00007ffff7ddd3e3 in dl_main () from /lib64/ld-linux-x86-64.so.2
#2  0x00007ffff7df04c0 in _dl_sysdep_start () from /lib64/ld-linux-x86-64.so.2
#3  0x00007ffff7dda028 in _dl_start () from /lib64/ld-linux-x86-64.so.2
#4  0x00007ffff7dd8fb8 in _start () from /lib64/ld-linux-x86-64.so.2
#5  0x0000000000000001 in ?? ()
#6  0x00007fffffffecef in ?? ()
#7  0x0000000000000000 in ?? ()

Jadi, basis segmen FS diatur oleh ld-linux, yang merupakan bagian dari glibc, selama pemuatan program (jika program terhubung secara statis, kode ini tertanam ke dalam biner). Di sinilah semuanya terjadi.

Selama startup, loader menginisialisasi TLS . Ini termasuk alokasi memori dan pengaturan nilai dasar FS untuk menunjuk ke awal TLS. Ini dilakukan melalui arch_prctl syscall . Setelah security_init fungsi inisialisasi TLS dipanggil, yang menghasilkan nilai dari guard stack dan menuliskannya ke lokasi memori, yang fs:[0x28]menunjuk ke:

Dan 0x28merupakan offset stack_guardbidang dalam struktur yang terletak di awal TLS.

Danila Kiver
sumber
zomfg, jawaban yang sangat bagus. Saya mencoba membongkar sebuah biner dengan radare. ini memiliki bentuk dan konten yang saya cari. Terima kasih banyak.
Evan Carroll
Apa yang menginisialisasi proses dengan arch_prctl(ARCH_SET_FS..)saya tidak melihat itu di executable? Apakah itu kode kernel?
Evan Carroll
Lihat tautan "syscall" di pos. Ini mengarah ke situs panggilan aktual ( git.launchpad.net/glibc/tree/sysdeps/x86_64/nptl/tls.h#n153 ) di mana syscall dijalankan. Ini dijalankan oleh ld-linuxselama inisialisasi TLS.
Danila Kiver
6

Apa yang Anda lihat disebut (dalam GCC) Stack Smashing Protector (SSP) , yang merupakan bentuk perlindungan buffer overflow yang dihasilkan oleh kompiler. Nilainya adalah angka acak yang dihasilkan oleh program saat startup dan sebagaimana artikel Wikipedia menyebutkan, ditempatkan di Thread Local Storage (TLS) . Kompiler lain dapat menggunakan strategi yang berbeda untuk menerapkan jenis perlindungan ini.

Mengapa menyimpan nilai dalam TLS? Karena nilainya terletak di sana, alamatnya tidak dapat diakses oleh register CS, DS dan SS, membuat menebak nilai yang disimpan menjadi sangat sulit jika Anda mencoba mengubah tumpukan dari kode berbahaya.

ErikF
sumber
Ini bukan yang saya cari, jadi saya telah sedikit mengklarifikasi dalam upaya untuk menjadi jelas. "angka acak yang dihasilkan oleh program saat startup" dapatkah Anda menunjukkan di mana di executable itu dihasilkan, dan apa yang menempatkan kode untuk menghasilkannya?
Evan Carroll