.dtors sembra scrivibile, ma tenta di scrivere segfault


9

Questo è Ubuntu 9.04, 2.6.28-11-server, 32 bit x86


$ cat test.c
main() { int *dt = (int *)0x08049f18; *dt = 1; }
$ readelf -S ./test
...
  [18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
...
$ ./test
Segmentation fault
$

Per chi non lo sapesse: gcc crea un segmento di distruttore .dtors, nell'eseguibile elfo, che viene chiamato dopo le main()uscite. Questa tabella è stata a lungo scrivibile, e sembra che dovrebbe essere nel mio caso (vedi l' readelfoutput). Ma tentare di scrivere sul tavolo provoca un segfault.

Mi rendo conto che ultimamente c'è stato un movimento verso .dtors .dtors, plt, ma quello che non capisco è la discrepanza tra readelfe segfault.


La vera domanda è: perché vuoi che sia scrivibile?
alex,

1
Sto insegnando un corso di sicurezza che prevede la rottura di una serie di programmi vulnerabili, ma un esercizio prevede la scrittura a .dtors per eseguire shellcode. Non funziona più e sto cercando di rintracciare il problema.
Fixee,

La mancata corrispondenza è perché probabilmente ci sono alcuni trasferimenti di dati (che devono essere corretti prima di contrassegnare la sola lettura e non possono essere pigri, quindi saranno costanti una volta risolti) lì.
ninjalj,

Risposte:


5

Queste sezioni sono contrassegnate come GNU_RELRO (rilocazioni di sola lettura), il che significa che non appena il caricatore dinamico si è risolto (al momento del caricamento, non ci sono rilocazioni pigre lì) tutte le ricollocazioni, segna quelle sezioni di sola lettura. Si noti che la maggior parte .got.pltè su un'altra pagina, quindi non ottiene il trattamento.

Puoi vedere lo script del linker con ld --verbose, se cerchi RELRO troverai qualcosa di simile a:

.got            : { *(.got) }
. = DATA_SEGMENT_RELRO_END (12, .);
.got.plt        : { *(.got.plt) }

il che significa che le sezioni RELRO terminano con 12 byte in .got.plt(i puntatori alle funzioni del linker dinamico sono già stati risolti, quindi possono essere contrassegnati in sola lettura).

Il progetto Gentoo rafforzato ha una documentazione su RELRO all'indirizzo http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO .


5

Posso dire perché sta fallendo, anche se in realtà non so quale parte del sistema sia responsabile. Mentre .dtorsè contrassegnato come scrivibile nel file binario, sembra che (insieme a .ctors, GOT e poche altre cose) vengano mappati in una pagina separata, non scrivibile in memoria. Sul mio sistema, .dtorsviene messo a 0x8049f14:

$ readelf -S test
  [17] .ctors            PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4
  [18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [19] .jcr              PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4
  [20] .dynamic          DYNAMIC         08049f20 000f20 0000d0 08  WA  6   0  4
  [21] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [22] .got.plt          PROGBITS        08049ff4 000ff4 00001c 04  WA  0   0  4
  [23] .data             PROGBITS        0804a010 001010 000008 00  WA  0   0  4
  [24] .bss              NOBITS          0804a018 001018 000008 00  WA  0   0  4

Se eseguo il file eseguibile e controllo /proc/PID/maps, vedo:

08048000-08049000 r-xp 00000000 08:02 163678     /tmp/test
08049000-0804a000 r--p 00000000 08:02 163678     /tmp/test
0804a000-0804b000 rw-p 00001000 08:02 163678     /tmp/test

.data/ .bsssono ancora scrivibili nella propria pagina, ma gli altri 0x8049000-0x804a000non lo sono. Presumo che questa sia una funzionalità di sicurezza nel kernel (come hai detto, "c'è stato un movimento verso di sola lettura .dtors, plt, got ultimamente"), ma non so esattamente come si chiama (OpenBSD ha qualcosa di molto simile chiamato W ^ X ; Linux ha PaX , ma non è integrato nella maggior parte dei kernel)

Puoi aggirarlo con mprotect, che ti consente di modificare gli attributi in memoria di una pagina:

mprotect((void*)0x8049000, 4096, PROT_WRITE);

Con ciò, il mio programma di test non si arresta in modo anomalo, ma se provo a sovrascrivere la sentinella di fine di .dtors( 0x8049f18) con l'indirizzo di un'altra funzione, quella funzione non viene ancora eseguita; quella parte che non riesco a capire.

Spero che qualcun altro sappia qual è il responsabile della lettura della pagina in modo semplice e perché la modifica .dtorsnon sembra fare nulla sul mio sistema


3
Se l'OP Linux con PaX mprotectnon può rendere scrivibile una pagina eseguibile o rendere eseguibile una pagina che era precedentemente scrivibile a meno che tale funzionalità non sia disabilitata con paxctl -m.
stribika,

@stribika Ah, buono a sapersi
Michael Mrozek
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.