Come viene applicata la protezione dello stack in un binario?

4

Su una macchina Linux con una CPU Intel, diciamo che sono stato compilato da binary con -fstack-protect-all.

  • Come è codificato nel file binario? (Posso vedere queste informazioni usando readelf?). È codificato in ogni pagina / segmento o è aggiunto al binario in un posto e il loader lo preleva?

  • In che modo il kernel / loader ottiene queste informazioni quando carica una pagina? Come lo usa?

  • Qual è l'istruzione x86 utilizzata per impostare la pagina in sola lettura?

posta SFlow 03.05.2017 - 00:52
fonte

2 risposte

6

On a linux box with an Intel CPU, lets say I compiled by binary with -fstack-protect-all.

Poiché non è esplicitamente dichiarato, si suppone che questo si riferisca ai binari ELF compilati usando GCC con l'argomento -fstack-protect o -all.

Meccanismi di protezione dello stack GCC

-fstack-protector-all è un'estensione di -fstack-protector :

-fstack-protector

Emit extra code to check for buffer overflows, such as stack smashing attacks. This is done by adding a guard variable to functions with vulnerable objects. This includes functions that call alloca, and functions with buffers larger than 8 bytes. The guards are initialized when a function is entered and then checked when the function exits. If a guard check fails, an error message is printed and the program exits.

-fstack-protector-all

Like -fstack-protector except that all functions are protected.

La summenzionata "variabile di guardia" è comunemente chiamata canarino :

The basic idea behind stack protection is to push a "canary" (a randomly chosen integer) on the stack just after the function return pointer has been pushed. The canary value is then checked before the function returns; if it has changed, the program will abort. Generally, stack buffer overflow (aka "stack smashing") attacks will have to change the value of the canary as they write beyond the end of the buffer before they can get to the return pointer. Since the value of the canary is unknown to the attacker, it cannot be replaced by the attack. Thus, the stack protection allows the program to abort when that happens rather than return to wherever the attacker wanted it to go.1

Ora alla prima serie di domande:

How is this encoded into the binary? (Can I see this info using readelf? ). Is it encoded into every page/segment or is it added to the binary in one place and the loader picks it up?

Il -fstack-protector-all fa sì che il compilatore generi codice in cui una variabile guard è spinto a tutte le funzioni e controllato prima del ritorno. In altre parole, vengono generate istruzioni aggiuntive per la macchina che hanno a che fare con la spinta, il controllo e l'apertura del paniere.

Questo può essere illustrato usando 2 file binari di esempio prodotti dalla stessa sorgente, in cui uno è stato compilato con l'argomento -fstack-protector-all e l'altro no.

Codice sorgente:

int test(int i) {
    return i;
}

int main(void) {
    int x;
    int i = 10;
    x = test(i);
    return x;
}

Funzione da binario compilato senza -fstack-protector-all :

$ objdump -dj .text test | grep -A7 "<test>:"
00000000004004ed <test>:
  4004ed:   55                      push   %rbp
  4004ee:   48 89 e5                mov    %rsp,%rbp
  4004f1:   89 7d fc                mov    %edi,-0x4(%rbp)
  4004f4:   8b 45 fc                mov    -0x4(%rbp),%eax
  4004f7:   5d                      pop    %rbp
  4004f8:   c3                      retq   

Funzione da binario compilato con -fstack-protector-all :

$ objdump -dj .text protected_test | grep -A20 "<test>:"
000000000040055d <test>:
  40055d:   55                      push   %rbp
  40055e:   48 89 e5                mov    %rsp,%rbp
  400561:   48 83 ec 20             sub    $0x20,%rsp
  400565:   89 7d ec                mov    %edi,-0x14(%rbp)
  400568:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax     <- get guard variable value
  40056f:   00 00 
  400571:   48 89 45 f8             mov    %rax,-0x8(%rbp)   <- save guard variable on stack
  400575:   31 c0                   xor    %eax,%eax
  400577:   8b 45 ec                mov    -0x14(%rbp),%eax
  40057a:   48 8b 55 f8             mov    -0x8(%rbp),%rdx   <- move it to register
  40057e:   64 48 33 14 25 28 00    xor    %fs:0x28,%rdx     <- check it against original
  400585:   00 00 
  400587:   74 05                   je     40058e <test+0x31>
  400589:   e8 b2 fe ff ff          callq  400440 <__stack_chk_fail@plt> 
  40058e:   c9                      leaveq 
  40058f:   c3                      retq   

Poiché la protezione dello stack viene implementata tramite codice assembly, i risultati della famiglia di flag -fstack-protector vengono esaminati al meglio utilizzando un disassembler come objdump . readelf mostra tecnicamente questa informazione, poiché l'argomento -x produce un dump esadecimale della sezione selezionata.

readelf dump esadecimale di binario compilato senza protezione dello stack:

$ readelf -x .text test

Hex dump of section '.text':
  0x00400400 31ed4989 d15e4889 e24883e4 f0505449 1.I..^H..H...PTI
  0x00400410 c7c09005 400048c7 c1200540 0048c7c7 [email protected].. [email protected]..
  0x00400420 f9044000 e8b7ffff fff4660f 1f440000 [email protected]..
  0x00400430 b83f1060 0055482d 38106000 4883f80e .?.'.UH-8.'.H...
  0x00400440 4889e577 025dc3b8 00000000 4885c074 H..w.]......H..t
  0x00400450 f45dbf38 106000ff e00f1f80 00000000 .].8.'..........
  0x00400460 b8381060 0055482d 38106000 48c1f803 .8.'.UH-8.'.H...
  0x00400470 4889e548 89c248c1 ea3f4801 d048d1f8 H..H..H..?H..H..
  0x00400480 75025dc3 ba000000 004885d2 74f45d48 u.]......H..t.]H
  0x00400490 89c6bf38 106000ff e20f1f80 00000000 ...8.'..........
  0x004004a0 803d910b 20000075 11554889 e5e87eff .=.. ..u.UH...~.
  0x004004b0 ffff5dc6 057e0b20 0001f3c3 0f1f4000 ..]..~. ......@.
  0x004004c0 48833d58 09200000 741eb800 00000048 H.=X. ..t......H
  0x004004d0 85c07414 55bf200e 60004889 e5ffd05d ..t.U. .'.H....]
  0x004004e0 e97bffff ff0f1f00 e973ffff ff554889 .{.......s...UH.
  0x004004f0 e5897dfc 8b45fc5d c3554889 e54883ec ..}..E.].UH..H..
  0x00400500 10c745f8 0a000000 8b45f889 c7e8dbff ..E......E......
  0x00400510 ffff8945 fc8b45fc c9c3660f 1f440000 ...E..E...f..D..
  0x00400520 41574189 ff415649 89f64155 4989d541 AWA..AVI..AUI..A
  0x00400530 544c8d25 d8082000 55488d2d d8082000 TL.%.. .UH.-.. .
  0x00400540 534c29e5 31db48c1 fd034883 ec08e855 SL).1.H...H....U
  0x00400550 feffff48 85ed741e 0f1f8400 00000000 ...H..t.........
  0x00400560 4c89ea4c 89f64489 ff41ff14 dc4883c3 L..L..D..A...H..
  0x00400570 014839eb 75ea4883 c4085b5d 415c415d .H9.u.H...[]A\A]
  0x00400580 415e415f c366662e 0f1f8400 00000000 A^A_.ff.........
  0x00400590 f3c3                                ..

readelf dump esadecimale di binario compilato con protezione dello stack:

$ readelf -x .text protected_test

Hex dump of section '.text':
  0x00400470 31ed4989 d15e4889 e24883e4 f0505449 1.I..^H..H...PTI
  0x00400480 c7c05006 400048c7 c1e00540 0048c7c7 [email protected][email protected]..
  0x00400490 90054000 e8b7ffff fff4660f 1f440000 [email protected]..
  0x004004a0 b8471060 0055482d 40106000 4883f80e .G.'.UH-@.'.H...
  0x004004b0 4889e577 025dc3b8 00000000 4885c074 H..w.]......H..t
  0x004004c0 f45dbf40 106000ff e00f1f80 00000000 .].@.'..........
  0x004004d0 b8401060 0055482d 40106000 48c1f803 .@.'.UH-@.'.H...
  0x004004e0 4889e548 89c248c1 ea3f4801 d048d1f8 H..H..H..?H..H..
  0x004004f0 75025dc3 ba000000 004885d2 74f45d48 u.]......H..t.]H
  0x00400500 89c6bf40 106000ff e20f1f80 00000000 ...@.'..........
  0x00400510 803d290b 20000075 11554889 e5e87eff .=). ..u.UH...~.
  0x00400520 ffff5dc6 05160b20 0001f3c3 0f1f4000 ..].... ......@.
  0x00400530 48833de8 08200000 741eb800 00000048 H.=.. ..t......H
  0x00400540 85c07414 55bf200e 60004889 e5ffd05d ..t.U. .'.H....]
  0x00400550 e97bffff ff0f1f00 e973ffff ff554889 .{.......s...UH.
  0x00400560 e54883ec 20897dec 64488b04 25280000 .H.. .}.dH..%(..
  0x00400570 00488945 f831c08b 45ec488b 55f86448 .H.E.1..E.H.U.dH
  0x00400580 33142528 00000074 05e8b2fe ffffc9c3 3.%(...t........
  0x00400590 554889e5 4883ec10 64488b04 25280000 UH..H...dH..%(..
  0x004005a0 00488945 f831c0c7 45f00a00 00008b45 .H.E.1..E......E
  0x004005b0 f089c7e8 a5ffffff 8945f48b 45f4488b .........E..E.H.
  0x004005c0 55f86448 33142528 00000074 05e86efe U.dH3.%(...t..n.
  0x004005d0 ffffc9c3 662e0f1f 84000000 00006690 ....f.........f.
  0x004005e0 41574189 ff415649 89f64155 4989d541 AWA..AVI..AUI..A
  0x004005f0 544c8d25 18082000 55488d2d 18082000 TL.%.. .UH.-.. .
  0x00400600 534c29e5 31db48c1 fd034883 ec08e8f5 SL).1.H...H.....
  0x00400610 fdffff48 85ed741e 0f1f8400 00000000 ...H..t.........
  0x00400620 4c89ea4c 89f64489 ff41ff14 dc4883c3 L..L..D..A...H..
  0x00400630 014839eb 75ea4883 c4085b5d 415c415d .H9.u.H...[]A\A]
  0x00400640 415e415f c366662e 0f1f8400 00000000 A^A_.ff.........
  0x00400650 f3c3                                ..

Ovviamente non è molto utile.

La discussione di pagine e segmenti non è rilevante poiché tutte le sezioni contrassegnate come eseguibili in un binario ELF vengono mappate nello stesso segmento (il segmento text ).

How does the kernel/loader get this information when loading a page? How does it use it?

L'uso di -fstack-protector-all non ha alcuna influenza sulle autorizzazioni di sezione o segmento.

Per informazioni sul programma di caricamento del kernel vedi:

What is the x86 instruction used to set the page to read-only?

Le autorizzazioni per segmento sono impostate dall'editor link: Permessi segmento

1. "strong" protezione dello stack per GCC
risposta data 03.05.2017 - 02:49
fonte
1

La protezione stack di GCC è basata su software e non è correlata alla protezione basata su hardware di DEP. Quando un sistema operativo abilita il DEP, tutti i programmi in esecuzione su di esso (o qualche sottoinsieme definito dall'utente) vengono automaticamente protetti tramite flag hardware, indipendentemente dai flag del compilatore utilizzati per compilare il file binario.

Quando i flag di protezione dello stack sono abilitati in GCC, fornisce protezione ponendo guardie e verifiche aggiuntive quando viene chiamata una funzione o restituisce per garantire che il programma si interrompa piuttosto che violare la sua integrità. Ciò aumenta leggermente la dimensione dell'eseguibile e causa un rallentamento del codice (richiede più tempo di CPU).

Il caricatore e il sistema operativo sono a conoscenza della protezione stack di GCC, né è necessario che lo sia. Per quanto riguarda il sistema operativo, questo è solo il codice eseguibile normale. Il sistema operativo può fornire DEP senza protezione dello stack abilitata e la protezione dello stack non richiede DEP.

Con DEP, se l'IP (puntatore istruzione) si trova all'esterno di un CS (segmento di codice), viene sollevata un'eccezione e il sistema operativo termina il programma. Con la protezione stack di GCC, lo stack viene bufferizzato con uno spazio aggiuntivo con determinati valori caricati e controllato per assicurarsi che le aree bufferizzate non vengano modificate. Se una funzione fallisce il controllo di guardia, il programma viene terminato per prevenire ulteriori danni.

    
risposta data 03.05.2017 - 01:40
fonte

Leggi altre domande sui tag