.dtors sieht beschreibbar aus, versucht jedoch, segfault zu schreiben

9

Dies ist Ubuntu 9.04, 2.6.28-11-Server, 32bit 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
$

Für den Uneingeweihten: gcc erstellt .dtorsin der ausführbaren Datei von elf ein Destruktorsegment , das nach dem main()Beenden aufgerufen wird . Diese Tabelle ist seit langem beschreibbar und es sieht so aus, als ob es in meinem Fall sein sollte (siehe readelfAusgabe). Der Versuch, in die Tabelle zu schreiben, führt jedoch zu einem Segfault.

Mir ist klar, dass es in letzter Zeit eine Bewegung in Richtung schreibgeschützter .dtors, plt, gegeben hat, aber was ich nicht verstehe, ist readelfdie Nichtübereinstimmung zwischen und dem Segfault.

Fixee
quelle
Die eigentliche Frage ist, warum Sie möchten, dass es beschreibbar ist.
alex
1
Ich unterrichte eine Sicherheitsklasse, bei der eine Reihe anfälliger Programme beschädigt werden. In einer Übung wird jedoch an .dtors geschrieben, um Shellcode auszuführen. Es funktioniert nicht mehr und ich versuche, das Problem aufzuspüren.
Fixee
Die Nichtübereinstimmung ist darauf zurückzuführen, dass es dort wahrscheinlich einige Datenverschiebungen gibt (die vor dem Markieren als schreibgeschützt behoben werden müssen und ohnehin nicht faul sein können und daher nach dem Einrichten konstant bleiben).
Ninjalj

Antworten:

5

Diese Abschnitte sind mit GNU_RELRO (schreibgeschützte Verschiebungen) gekennzeichnet. Dies bedeutet, dass diese Abschnitte schreibgeschützt sind, sobald der dynamische Lader alle Verschiebungen behoben hat (zum Ladezeitpunkt gibt es dort keine verzögerten Verschiebungen). Beachten Sie, dass sich der größte Teil .got.pltauf einer anderen Seite befindet und daher nicht behandelt wird.

Sie können das Linker-Skript mit sehen ld --verbose, wenn Sie nach RELRO suchen, finden Sie etwas Ähnliches wie:

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

Dies bedeutet, dass die RELRO-Abschnitte 12 Byte lang enden .got.plt(Zeiger auf dynamische Linkerfunktionen sind bereits aufgelöst und können daher als schreibgeschützt markiert werden).

Das gehärtete Gentoo-Projekt enthält einige Dokumentationen zu RELRO unter http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO .

Ninjalj
quelle
5

Ich kann sagen, warum es fehlschlägt, obwohl ich nicht weiß, welcher Teil des Systems dafür verantwortlich ist. Während .dtorses in der Binärdatei als beschreibbar markiert ist, sieht es so aus, als würde es (zusammen mit .ctorsdem GOT und einigen anderen Dingen) einer separaten, nicht beschreibbaren Seite im Speicher zugeordnet. Auf meinem System .dtorswird gesetzt bei 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

Wenn ich die ausführbare Datei ausführe und überprüfe /proc/PID/maps, sehe ich:

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/ .bssSind noch beschreibbar in ihrer eigenen Seite, aber die andere in 0x8049000-0x804a000nicht sind. Ich gehe davon aus, dass dies ein Sicherheitsmerkmal im Kernel ist (wie Sie sagten, "es hat in letzter Zeit eine Bewegung in Richtung schreibgeschützter .dtors, plt, got" gegeben), aber ich weiß nicht genau, wie es heißt (OpenBSD hat etwas sehr Ähnliches namens W ^ X ; Linux hat PaX , ist aber in den meisten Kerneln nicht eingebaut)

Sie können es umgehen mprotect, indem Sie die speicherinternen Attribute einer Seite ändern:

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

Damit stürzt mein Testprogramm nicht ab, aber wenn ich versuche, den End-Sentinel von .dtors( 0x8049f18) mit der Adresse einer anderen Funktion zu überschreiben , wird diese Funktion immer noch nicht ausgeführt. diesen Teil kann ich nicht herausfinden.

Hoffentlich weiß jemand anderes, was dafür verantwortlich ist, dass die Seite schreibgeschützt ist, und warum das Ändern .dtorsauf meinem System nichts zu bewirken scheint

Michael Mrozek
quelle
3
Wenn das OP Linux mit PaX mprotecteine ausführbare Seite nicht beschreibbar machen oder eine Seite ausführbar machen kann, die zuvor beschreibbar war, es sei denn, diese Funktion ist mit deaktiviert paxctl -m.
Stribika
@ Stribika Ah, gut zu wissen
Michael Mrozek