Qu'est-ce qui définit fs: [0x28] (pile canari)?

11

De ce post, il est montré qu'il FS:[0x28]s'agit d'un empilement de canaris. Je génère ce même code en utilisant GCC sur cette fonction,

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

Plus précisément, je reçois cet assemblage ..

    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

À quoi sert la valeur de fs:[0x28]? Le noyau, ou GCC lance-t-il le code? Pouvez-vous afficher le code dans le noyau, ou compilé dans le binaire qui définit fs:[0x28]? Le canari est-il régénéré - au démarrage, ou le processus d'apparition? Où est-ce documenté?

Evan Carroll
la source

Réponses:

18

Il est facile de suivre cette initialisation, car (presque) chaque processus straceaffiche un appel système très suspect au tout début de l'exécution du processus:

arch_prctl(ARCH_SET_FS, 0x7fc189ed0740) = 0

Voilà ce qui man 2 arch_prctldit:

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

Oui, on dirait que c'est ce dont nous avons besoin. Pour trouver qui appelle arch_prctl, recherchons une trace:

(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 ?? ()

Ainsi, la base du segment FS est définie par le ld-linux, qui fait partie de glibc, pendant le chargement du programme (si le programme est lié statiquement, ce code est incorporé dans le binaire). C'est là que tout se passe.

Lors du démarrage, le chargeur initialise TLS . Cela inclut l'allocation de mémoire et la définition de la valeur de base FS pour pointer vers le début TLS. Cela se fait via arch_prctl syscall . Après l' appel de la security_init fonction d' initialisation TLS , qui génère la valeur de la protection de pile et l'écrit dans l'emplacement de mémoire, ce qui fs:[0x28]indique:

Et 0x28est le décalage du stack_guardchamp dans la structure qui se trouve au début du TLS.

Danila Kiver
la source
zomfg, vraiment une excellente réponse. J'essayais de démonter un binaire avec radare. cela a la forme et le contenu que je cherchais. Merci beaucoup.
Evan Carroll
Qu'est-ce qui initialise un processus avec arch_prctl(ARCH_SET_FS..)je ne vois pas cela dans l'exécutable? Est-ce du code noyau?
Evan Carroll
Voir le lien "syscall" dans le post. Il mène au site d'appel réel ( git.launchpad.net/glibc/tree/sysdeps/x86_64/nptl/tls.h#n153 ) où le syscall est exécuté. Il est exécuté par ld-linuxlors de l'initialisation TLS.
Danila Kiver
6

Ce que vous voyez s'appelle (dans GCC) le Stack Smashing Protector (SSP) , qui est une forme de protection contre le débordement de tampon générée par le compilateur. La valeur est un nombre aléatoire généré par le programme au démarrage et, comme le mentionne l'article Wikipédia, est placé dans Thread Local Storage (TLS) . D'autres compilateurs peuvent utiliser différentes stratégies pour implémenter ce type de protection.

Pourquoi stocker la valeur dans TLS? Comme la valeur s'y trouve, son adresse n'est pas accessible par les registres CS, DS et SS, ce qui rend la devinette de la valeur stockée très difficile si vous essayez de modifier la pile à partir d'un code malveillant.

ErikF
la source
Ce n'est pas ce que je recherche, j'ai donc clarifié un peu pour être clair. "nombre aléatoire généré par le programme au démarrage" pouvez-vous montrer où dans un exécutable il est généré, et qu'est-ce qui met le code pour le générer?
Evan Carroll