mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/basic-stack-binary-exploitation-met
This commit is contained in:
parent
7b0cb09070
commit
e7a3e027a4
@ -37,30 +37,38 @@ Segment Sections...
|
||||
07
|
||||
08 .init_array .fini_array .dynamic .got
|
||||
```
|
||||
Das vorherige Programm hat **9 Programm-Header**, dann zeigt die **Segmentzuordnung**, in welchem Programm-Header (von 00 bis 08) **jeder Abschnitt sich befindet**.
|
||||
Die vorherige Programm hat **9 Programm-Header**, dann zeigt die **Segmentzuordnung**, in welchem Programm-Header (von 00 bis 08) **jeder Abschnitt lokalisiert ist**.
|
||||
|
||||
### PHDR - Programm-Header
|
||||
|
||||
Enthält die Programm-Header-Tabellen und die Metadaten selbst.
|
||||
Enthält die Programm-Header-Tabellen und Metadaten selbst.
|
||||
|
||||
### INTERP
|
||||
|
||||
Gibt den Pfad des Loaders an, der verwendet werden soll, um die Binärdatei in den Speicher zu laden.
|
||||
|
||||
> Tipp: Statisch verlinkte oder statische-PIE-Binärdateien haben keinen `INTERP`-Eintrag. In diesen Fällen ist kein dynamischer Loader beteiligt, was Techniken deaktiviert, die darauf angewiesen sind (z. B. `ret2dlresolve`).
|
||||
|
||||
### LOAD
|
||||
|
||||
Diese Header werden verwendet, um anzugeben, **wie eine Binärdatei in den Speicher geladen werden soll.**\
|
||||
Jeder **LOAD**-Header gibt einen Bereich des **Speichers** (Größe, Berechtigungen und Ausrichtung) an und zeigt die Bytes der ELF **Binärdatei an, die dort kopiert werden sollen**.
|
||||
Jeder **LOAD**-Header gibt einen Bereich des **Speichers** (Größe, Berechtigungen und Ausrichtung) an und zeigt die Bytes der ELF **Binärdatei, die dort kopiert werden sollen**.
|
||||
|
||||
Zum Beispiel hat der zweite eine Größe von 0x1190, sollte sich bei 0x1fc48 mit den Berechtigungen Lesen und Schreiben befinden und wird mit 0x528 vom Offset 0xfc48 gefüllt (es füllt nicht den gesamten reservierten Platz). Dieser Speicher wird die Abschnitte `.init_array .fini_array .dynamic .got .data .bss` enthalten.
|
||||
Zum Beispiel hat der zweite eine Größe von 0x1190, sollte sich bei 0x1fc48 mit den Berechtigungen Lesen und Schreiben befinden und wird mit 0x528 ab dem Offset 0xfc48 gefüllt (es füllt nicht den gesamten reservierten Platz). Dieser Speicher wird die Abschnitte `.init_array .fini_array .dynamic .got .data .bss` enthalten.
|
||||
|
||||
### DYNAMIC
|
||||
|
||||
Dieser Header hilft, Programme mit ihren Bibliotheksabhängigkeiten zu verlinken und Relokationen anzuwenden. Überprüfen Sie den **`.dynamic`** Abschnitt.
|
||||
Dieser Header hilft, Programme mit ihren Bibliotheksabhängigkeiten zu verknüpfen und Relokationen anzuwenden. Überprüfen Sie den **`.dynamic`** Abschnitt.
|
||||
|
||||
### NOTE
|
||||
|
||||
Dies speichert Metadateninformationen des Anbieters über die Binärdatei.
|
||||
Dies speichert Metainformationen des Anbieters über die Binärdatei.
|
||||
|
||||
- Auf x86-64 zeigt `readelf -n` `GNU_PROPERTY_X86_FEATURE_1_*`-Flags innerhalb von `.note.gnu.property`. Wenn Sie `IBT` und/oder `SHSTK` sehen, wurde die Binärdatei mit CET (Indirect Branch Tracking und/oder Shadow Stack) erstellt. Dies beeinflusst ROP/JOP, da indirekte Zielzweige mit einer `ENDBR64`-Anweisung beginnen müssen und Rückgaben gegen einen Schattenstapel überprüft werden. Siehe die CET-Seite für Details und Umgehungsnotizen.
|
||||
|
||||
{{#ref}}
|
||||
../common-binary-protections-and-bypasses/cet-and-shadow-stack.md
|
||||
{{#endref}}
|
||||
|
||||
### GNU_EH_FRAME
|
||||
|
||||
@ -70,21 +78,29 @@ Definiert den Standort der Stack-Unwind-Tabellen, die von Debuggern und C++-Ausn
|
||||
|
||||
Enthält die Konfiguration der Stack-Ausführungspräventionsverteidigung. Wenn aktiviert, kann die Binärdatei keinen Code vom Stack ausführen.
|
||||
|
||||
- Überprüfen Sie mit `readelf -l ./bin | grep GNU_STACK`. Um es während der Tests zwangsweise umzuschalten, können Sie `execstack -s|-c ./bin` verwenden.
|
||||
|
||||
### GNU_RELRO
|
||||
|
||||
Gibt die RELRO (Relocation Read-Only) Konfiguration der Binärdatei an. Dieser Schutz markiert bestimmte Abschnitte des Speichers (wie die `GOT` oder die `init` und `fini` Tabellen) nach dem Laden des Programms und bevor es zu laufen beginnt, als schreibgeschützt.
|
||||
Gibt die RELRO (Relocation Read-Only)-Konfiguration der Binärdatei an. Dieser Schutz markiert bestimmte Abschnitte des Speichers (wie die `GOT` oder die `init` und `fini`-Tabellen) nach dem Laden des Programms und bevor es ausgeführt wird, als schreibgeschützt.
|
||||
|
||||
Im vorherigen Beispiel werden 0x3b8 Bytes nach 0x1fc48 als schreibgeschützt kopiert, was die Abschnitte `.init_array .fini_array .dynamic .got .data .bss` betrifft.
|
||||
Im vorherigen Beispiel kopiert es 0x3b8 Bytes nach 0x1fc48 als schreibgeschützt, was die Abschnitte `.init_array .fini_array .dynamic .got .data .bss` betrifft.
|
||||
|
||||
Beachten Sie, dass RELRO teilweise oder vollständig sein kann, die partielle Version schützt den Abschnitt **`.plt.got`** nicht, der für **lazy binding** verwendet wird und diesen Speicherplatz benötigt, um **Schreibberechtigungen** zu haben, um die Adresse der Bibliotheken beim ersten Suchen ihres Standorts zu schreiben.
|
||||
|
||||
> Für Exploitationstechniken und aktuelle Umgehungsnotizen, überprüfen Sie die dedizierte Seite:
|
||||
|
||||
{{#ref}}
|
||||
../common-binary-protections-and-bypasses/relro.md
|
||||
{{#endref}}
|
||||
|
||||
### TLS
|
||||
|
||||
Definiert eine Tabelle von TLS-Einträgen, die Informationen über thread-lokale Variablen speichert.
|
||||
|
||||
## Abschnitts-Header
|
||||
|
||||
Abschnitts-Header geben einen detaillierteren Überblick über die ELF-Binärdatei.
|
||||
Abschnitts-Header geben eine detailliertere Ansicht der ELF-Binärdatei.
|
||||
```
|
||||
objdump lnstat -h
|
||||
|
||||
@ -157,7 +173,7 @@ Es zeigt auch den Standort, den Offset, die Berechtigungen, aber auch den **Date
|
||||
|
||||
- **`.text`**: Die Anweisung des Programms, die ausgeführt werden soll.
|
||||
- **`.data`**: Globale Variablen mit einem definierten Wert im Programm.
|
||||
- **`.bss`**: Globale Variablen, die nicht initialisiert sind (oder auf null initialisiert). Variablen hier werden automatisch auf null initialisiert, wodurch verhindert wird, dass unnötige Nullen zur Binärdatei hinzugefügt werden.
|
||||
- **`.bss`**: Globale Variablen, die nicht initialisiert sind (oder auf null gesetzt). Variablen hier werden automatisch auf null initialisiert, wodurch unnötige Nullen zum Binärformat verhindert werden.
|
||||
- **`.rodata`**: Konstante globale Variablen (schreibgeschützter Abschnitt).
|
||||
- **`.tdata`** und **`.tbss`**: Wie die .data und .bss, wenn thread-lokale Variablen verwendet werden (`__thread_local` in C++ oder `__thread` in C).
|
||||
- **`.dynamic`**: Siehe unten.
|
||||
@ -188,13 +204,17 @@ Num: Value Size Type Bind Vis Ndx Name
|
||||
Jeder Symbol-Eintrag enthält:
|
||||
|
||||
- **Name**
|
||||
- **Bindungsattribute** (schwach, lokal oder global): Ein lokales Symbol kann nur vom Programm selbst zugegriffen werden, während die globalen Symbole außerhalb des Programms geteilt werden. Ein schwaches Objekt ist zum Beispiel eine Funktion, die von einer anderen überschrieben werden kann.
|
||||
- **Bindungsattribute** (schwach, lokal oder global): Ein lokales Symbol kann nur vom Programm selbst zugegriffen werden, während globale Symbole außerhalb des Programms geteilt werden. Ein schwaches Objekt ist zum Beispiel eine Funktion, die von einer anderen überschrieben werden kann.
|
||||
- **Typ**: NOTYPE (kein Typ angegeben), OBJECT (globale Datenvariable), FUNC (Funktion), SECTION (Sektion), FILE (Quellcodedatei für Debugger), TLS (thread-lokale Variable), GNU_IFUNC (indirekte Funktion für Relokation)
|
||||
- **Abschnitt** Index, wo es sich befindet
|
||||
- **Sektion** Index, wo es sich befindet
|
||||
- **Wert** (Adresse im Speicher)
|
||||
- **Größe**
|
||||
|
||||
## Dynamischer Abschnitt
|
||||
#### GNU Symbolversionierung (dynsym/dynstr/gnu.version)
|
||||
|
||||
Moderne glibc verwendet Symbolversionen. Sie werden Einträge in `.gnu.version` und `.gnu.version_r` sowie Symbolnamen wie `strlen@GLIBC_2.17` sehen. Der dynamische Linker kann eine spezifische Version bei der Auflösung eines Symbols erfordern. Beim Erstellen manueller Relokationen (z. B. ret2dlresolve) müssen Sie den richtigen Versionsindex angeben, andernfalls schlägt die Auflösung fehl.
|
||||
|
||||
## Dynamische Sektion
|
||||
```
|
||||
readelf -d lnstat
|
||||
|
||||
@ -229,7 +249,24 @@ Tag Type Name/Value
|
||||
0x000000006ffffff9 (RELACOUNT) 15
|
||||
0x0000000000000000 (NULL) 0x0
|
||||
```
|
||||
Das NEEDED-Verzeichnis zeigt an, dass das Programm **die erwähnte Bibliothek laden muss**, um fortzufahren. Das NEEDED-Verzeichnis ist abgeschlossen, sobald die gemeinsame **Bibliothek vollständig betriebsbereit und bereit** zur Verwendung ist.
|
||||
Das NEEDED-Verzeichnis zeigt an, dass das Programm **die erwähnte Bibliothek laden muss**, um fortzufahren. Das NEEDED-Verzeichnis wird abgeschlossen, sobald die gemeinsame **Bibliothek vollständig betriebsbereit und einsatzbereit** ist.
|
||||
|
||||
### Suchreihenfolge des dynamischen Laders (RPATH/RUNPATH, $ORIGIN)
|
||||
|
||||
Die Einträge `DT_RPATH` (veraltet) und/oder `DT_RUNPATH` beeinflussen, wo der dynamische Loader nach Abhängigkeiten sucht. Grobe Reihenfolge:
|
||||
|
||||
- `LD_LIBRARY_PATH` (ignoriert für setuid/sgid oder anderweitig "sichere Ausführungs"-Programme)
|
||||
- `DT_RPATH` (nur wenn `DT_RUNPATH` fehlt)
|
||||
- `DT_RUNPATH`
|
||||
- `ld.so.cache`
|
||||
- Standardverzeichnisse wie `/lib64`, `/usr/lib64` usw.
|
||||
|
||||
`$ORIGIN` kann innerhalb von RPATH/RUNPATH verwendet werden, um auf das Verzeichnis des Hauptobjekts zu verweisen. Aus der Perspektive eines Angreifers ist dies wichtig, wenn Sie die Dateisystemanordnung oder die Umgebung kontrollieren. Für gehärtete Binärdateien (AT_SECURE) werden die meisten Umgebungsvariablen vom Loader ignoriert.
|
||||
|
||||
- Überprüfen mit: `readelf -d ./bin | egrep -i 'r(path|unpath)'`
|
||||
- Schneller Test: `LD_DEBUG=libs ./bin 2>&1 | grep -i find` (zeigt Entscheidungen über den Suchpfad)
|
||||
|
||||
> Priv-esc Tipp: Bevorzugen Sie das Ausnutzen von beschreibbaren RUNPATHs oder falsch konfigurierten `$ORIGIN`-relativen Pfaden, die Ihnen gehören. LD_PRELOAD/LD_AUDIT werden in sicheren Ausführungs-(setuid) Kontexten ignoriert.
|
||||
|
||||
## Relokationen
|
||||
|
||||
@ -274,7 +311,6 @@ Offset Info Type Sym. Value Sym. Name + Addend
|
||||
00000001fea0 000900000402 R_AARCH64_JUMP_SL 0000000000000000 perror@GLIBC_2.17 + 0
|
||||
00000001fea8 000b00000402 R_AARCH64_JUMP_SL 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0
|
||||
00000001feb0 000c00000402 R_AARCH64_JUMP_SL 0000000000000000 putc@GLIBC_2.17 + 0
|
||||
00000001feb8 000d00000402 R_AARCH64_JUMP_SL 0000000000000000 opendir@GLIBC_2.17 + 0
|
||||
00000001fec0 000e00000402 R_AARCH64_JUMP_SL 0000000000000000 fputc@GLIBC_2.17 + 0
|
||||
00000001fec8 001100000402 R_AARCH64_JUMP_SL 0000000000000000 snprintf@GLIBC_2.17 + 0
|
||||
00000001fed0 001200000402 R_AARCH64_JUMP_SL 0000000000000000 __snprintf_chk@GLIBC_2.17 + 0
|
||||
@ -308,23 +344,41 @@ Offset Info Type Sym. Value Sym. Name + Addend
|
||||
```
|
||||
### Statische Relokationen
|
||||
|
||||
Wenn das **Programm an einem anderen Ort geladen wird** als der bevorzugte Adresse (normalerweise 0x400000), weil die Adresse bereits verwendet wird oder wegen **ASLR** oder aus einem anderen Grund, korrigiert eine statische Relokation **Zeiger**, die Werte hatten, die erwarteten, dass das Binärprogramm an der bevorzugten Adresse geladen wird.
|
||||
Wenn das **Programm an einem anderen Ort geladen wird** als der bevorzugte Adresse (normalerweise 0x400000), weil die Adresse bereits verwendet wird oder wegen **ASLR** oder aus einem anderen Grund, korrigiert eine statische Relokation **Zeiger**, die Werte erwarteten, dass die Binärdatei an der bevorzugten Adresse geladen wird.
|
||||
|
||||
Zum Beispiel sollte jeder Abschnitt vom Typ `R_AARCH64_RELATIV` die Adresse am Relokationsbias plus den Addendwert modifizieren.
|
||||
|
||||
### Dynamische Relokationen und GOT
|
||||
|
||||
Die Relokation könnte auch auf ein externes Symbol verweisen (wie eine Funktion aus einer Abhängigkeit). Wie die Funktion malloc aus libC. Dann wird der Loader beim Laden von libC an einer Adresse überprüfen, wo die malloc-Funktion geladen ist, und diese Adresse in die GOT (Global Offset Table) Tabelle (angegeben in der Relokationstabelle) schreiben, wo die Adresse von malloc angegeben werden sollte.
|
||||
Die Relokation könnte auch auf ein externes Symbol verweisen (wie eine Funktion aus einer Abhängigkeit). Wie die Funktion malloc aus libC. Dann wird der Loader beim Laden von libC an einer Adresse, an der die malloc-Funktion geladen ist, diese Adresse in die GOT (Global Offset Table) Tabelle (angegeben in der Relokationstabelle) schreiben, wo die Adresse von malloc angegeben werden sollte.
|
||||
|
||||
### Prozedurenverknüpfungstabelle
|
||||
### Verfahren Linktabelle
|
||||
|
||||
Der PLT-Abschnitt ermöglicht eine verzögerte Bindung, was bedeutet, dass die Auflösung des Standorts einer Funktion beim ersten Zugriff durchgeführt wird.
|
||||
Der PLT-Bereich ermöglicht eine verzögerte Bindung, was bedeutet, dass die Auflösung des Standorts einer Funktion beim ersten Zugriff durchgeführt wird.
|
||||
|
||||
Wenn ein Programm also malloc aufruft, ruft es tatsächlich den entsprechenden Standort von `malloc` im PLT (`malloc@plt`) auf. Beim ersten Aufruf wird die Adresse von `malloc` aufgelöst und gespeichert, sodass beim nächsten Aufruf von `malloc` diese Adresse anstelle des PLT-Codes verwendet wird.
|
||||
|
||||
#### Moderne Verlinkungsverhalten, die die Ausnutzung beeinflussen
|
||||
|
||||
- `-z now` (Vollständiges RELRO) deaktiviert die verzögerte Bindung; PLT-Einträge existieren weiterhin, aber GOT/PLT ist schreibgeschützt gemappt, sodass Techniken wie **GOT-Überschreibung** und **ret2dlresolve** gegen die Haupt-Binärdatei nicht funktionieren (Bibliotheken können weiterhin teilweise RELRO sein). Siehe:
|
||||
|
||||
{{#ref}}
|
||||
../common-binary-protections-and-bypasses/relro.md
|
||||
{{#endref}}
|
||||
|
||||
- `-fno-plt` lässt den Compiler externe Funktionen über den **GOT-Eintrag direkt** aufrufen, anstatt über den PLT-Stubs zu gehen. Sie werden Aufrufsequenzen wie `mov reg, [got]; call reg` anstelle von `call func@plt` sehen. Dies reduziert den Missbrauch von spekulativer Ausführung und ändert leicht die ROP-Gadget-Suche rund um PLT-Stubs.
|
||||
|
||||
- PIE vs static-PIE: PIE (ET_DYN mit `INTERP`) benötigt den dynamischen Loader und unterstützt die übliche PLT/GOT-Mechanik. Static-PIE (ET_DYN ohne `INTERP`) hat Relokationen, die vom Kernel-Loader angewendet werden, und kein `ld.so`; erwarten Sie keine PLT-Auflösung zur Laufzeit.
|
||||
|
||||
> Wenn GOT/PLT keine Option ist, wechseln Sie zu anderen beschreibbaren Code-Zeigern oder verwenden Sie klassisches ROP/SROP in libc.
|
||||
|
||||
{{#ref}}
|
||||
../arbitrary-write-2-exec/aw2exec-got-plt.md
|
||||
{{#endref}}
|
||||
|
||||
## Programminitialisierung
|
||||
|
||||
Nachdem das Programm geladen wurde, ist es Zeit, dass es ausgeführt wird. Der erste Code, der ausgeführt wird, **ist jedoch nicht immer die `main`**-Funktion. Dies liegt daran, dass zum Beispiel in C++, wenn eine **globale Variable ein Objekt einer Klasse ist**, dieses Objekt **initialisiert** **werden muss**, **bevor** main ausgeführt wird, wie in:
|
||||
Nachdem das Programm geladen wurde, ist es Zeit, dass es ausgeführt wird. Der erste Code, der ausgeführt wird, ist jedoch **nicht immer die `main`**-Funktion. Dies liegt daran, dass zum Beispiel in C++, wenn eine **globale Variable ein Objekt einer Klasse ist**, dieses Objekt **vor** dem Ausführen von main **initialisiert** werden muss, wie in:
|
||||
```cpp
|
||||
#include <stdio.h>
|
||||
// g++ autoinit.cpp -o autoinit
|
||||
@ -345,38 +399,75 @@ printf("Main\n");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
Beachten Sie, dass sich diese globalen Variablen in `.data` oder `.bss` befinden, aber in den Listen `__CTOR_LIST__` und `__DTOR_LIST__` die Objekte zur Initialisierung und Zerstörung gespeichert sind, um den Überblick über sie zu behalten.
|
||||
Beachten Sie, dass sich diese globalen Variablen in `.data` oder `.bss` befinden, aber in den Listen `__CTOR_LIST__` und `__DTOR_LIST__` die Objekte zur Initialisierung und Zerstörung gespeichert sind, um sie im Auge zu behalten.
|
||||
|
||||
Aus C-Code ist es möglich, dasselbe Ergebnis mit den GNU-Erweiterungen zu erzielen:
|
||||
```c
|
||||
__attributte__((constructor)) //Add a constructor to execute before
|
||||
__attributte__((destructor)) //Add to the destructor list
|
||||
```
|
||||
Aus der Perspektive eines Compilers ist es möglich, eine `init`-Funktion und eine `fini`-Funktion zu erstellen, die in der dynamischen Sektion als **`INIT`** und **`FIN`** referenziert werden und in den `init`- und `fini`-Sektionen des ELF platziert sind, um diese Aktionen vor und nach der Ausführung der `main`-Funktion auszuführen.
|
||||
Aus der Perspektive eines Compilers ist es möglich, eine `init`-Funktion und eine `fini`-Funktion zu erstellen, um diese Aktionen vor und nach der Ausführung der `main`-Funktion auszuführen. Diese würden im dynamischen Abschnitt als **`INIT`** und **`FIN`** referenziert und befinden sich in den `init`- und `fini`-Sektionen des ELF.
|
||||
|
||||
Die andere Option, wie erwähnt, besteht darin, die Listen **`__CTOR_LIST__`** und **`__DTOR_LIST__`** in den **`INIT_ARRAY`**- und **`FINI_ARRAY`**-Einträgen in der dynamischen Sektion zu referenzieren, deren Länge durch **`INIT_ARRAYSZ`** und **`FINI_ARRAYSZ`** angegeben wird. Jeder Eintrag ist ein Funktionszeiger, der ohne Argumente aufgerufen wird.
|
||||
Die andere Option, wie erwähnt, besteht darin, die Listen **`__CTOR_LIST__`** und **`__DTOR_LIST__`** in den **`INIT_ARRAY`**- und **`FINI_ARRAY`**-Einträgen im dynamischen Abschnitt zu referenzieren, deren Länge durch **`INIT_ARRAYSZ`** und **`FINI_ARRAYSZ`** angegeben wird. Jeder Eintrag ist ein Funktionszeiger, der ohne Argumente aufgerufen wird.
|
||||
|
||||
Darüber hinaus ist es auch möglich, ein **`PREINIT_ARRAY`** mit **Zeigern** zu haben, die **vor** den **`INIT_ARRAY`**-Zeigern ausgeführt werden.
|
||||
|
||||
#### Ausnutzungsnotiz
|
||||
|
||||
- Unter Partial RELRO leben diese Arrays in Seiten, die vor dem Wechsel von `ld.so` von `PT_GNU_RELRO` auf schreibgeschützt noch beschreibbar sind. Wenn Sie früh genug einen beliebigen Schreibzugriff erhalten oder Sie die beschreibbaren Arrays einer Bibliothek anvisieren können, können Sie den Kontrollfluss übernehmen, indem Sie einen Eintrag mit einer Funktion Ihrer Wahl überschreiben. Unter Full RELRO sind sie zur Laufzeit schreibgeschützt.
|
||||
|
||||
- Für den Missbrauch der faulen Bindung des dynamischen Linkers zur Auflösung beliebiger Symbole zur Laufzeit siehe die spezielle Seite:
|
||||
|
||||
{{#ref}}
|
||||
../rop-return-oriented-programing/ret2dlresolve.md
|
||||
{{#endref}}
|
||||
|
||||
### Initialisierungsreihenfolge
|
||||
|
||||
1. Das Programm wird in den Speicher geladen, statische globale Variablen werden in **`.data`** initialisiert und nicht initialisierte werden in **`.bss`** auf Null gesetzt.
|
||||
2. Alle **Abhängigkeiten** für das Programm oder Bibliotheken werden **initialisiert** und das **dynamische Linking** wird ausgeführt.
|
||||
2. Alle **Abhängigkeiten** für das Programm oder Bibliotheken werden **initialisiert** und das **dynamische Verlinken** wird ausgeführt.
|
||||
3. **`PREINIT_ARRAY`**-Funktionen werden ausgeführt.
|
||||
4. **`INIT_ARRAY`**-Funktionen werden ausgeführt.
|
||||
5. Wenn es einen **`INIT`**-Eintrag gibt, wird dieser aufgerufen.
|
||||
6. Wenn es sich um eine Bibliothek handelt, endet dlopen hier, wenn es sich um ein Programm handelt, ist es Zeit, den **echten Einstiegspunkt** (Funktion `main`) aufzurufen.
|
||||
6. Wenn es sich um eine Bibliothek handelt, endet dlopen hier, wenn es sich um ein Programm handelt, ist es Zeit, den **tatsächlichen Einstiegspunkt** (Funktion `main`) aufzurufen.
|
||||
|
||||
## Thread-Local Storage (TLS)
|
||||
## Thread-lokaler Speicher (TLS)
|
||||
|
||||
Sie werden mit dem Schlüsselwort **`__thread_local`** in C++ oder der GNU-Erweiterung **`__thread`** definiert.
|
||||
Sie werden in C++ mit dem Schlüsselwort **`__thread_local`** oder der GNU-Erweiterung **`__thread`** definiert.
|
||||
|
||||
Jeder Thread wird einen einzigartigen Speicherort für diese Variable beibehalten, sodass nur der Thread auf seine Variable zugreifen kann.
|
||||
Jeder Thread hat einen einzigartigen Speicherort für diese Variable, sodass nur der Thread auf seine Variable zugreifen kann.
|
||||
|
||||
Wenn dies verwendet wird, werden die Sektionen **`.tdata`** und **`.tbss`** im ELF verwendet. Diese sind wie `.data` (initialisiert) und `.bss` (nicht initialisiert), jedoch für TLS.
|
||||
Wenn dies verwendet wird, werden die Abschnitte **`.tdata`** und **`.tbss`** im ELF verwendet. Diese sind wie `.data` (initialisiert) und `.bss` (nicht initialisiert), jedoch für TLS.
|
||||
|
||||
Jede Variable hat einen Eintrag im TLS-Header, der die Größe und den TLS-Offset angibt, der der Offset ist, den sie im lokalen Datenbereich des Threads verwenden wird.
|
||||
|
||||
Der `__TLS_MODULE_BASE` ist ein Symbol, das verwendet wird, um auf die Basisadresse des thread-local storage zu verweisen und auf den Bereich im Speicher zeigt, der alle thread-lokalen Daten eines Moduls enthält.
|
||||
Der `__TLS_MODULE_BASE` ist ein Symbol, das verwendet wird, um auf die Basisadresse des thread-lokalen Speichers zu verweisen und auf den Bereich im Speicher zeigt, der alle thread-lokalen Daten eines Moduls enthält.
|
||||
|
||||
## Hilfsvektor (auxv) und vDSO
|
||||
|
||||
Der Linux-Kernel übergibt einen Hilfsvektor an Prozesse, der nützliche Adressen und Flags für die Laufzeit enthält:
|
||||
|
||||
- `AT_RANDOM`: zeigt auf 16 zufällige Bytes, die von glibc für den Stack-Cookie und andere PRNG-Samen verwendet werden.
|
||||
- `AT_SYSINFO_EHDR`: Basisadresse der vDSO-Zuordnung (praktisch, um `__kernel_*`-Systemaufrufe und Gadgets zu finden).
|
||||
- `AT_EXECFN`, `AT_BASE`, `AT_PAGESZ` usw.
|
||||
|
||||
Als Angreifer, wenn Sie Speicher oder Dateien unter `/proc` lesen können, können Sie diese oft ohne einen Infoleak im Zielprozess leaken:
|
||||
```bash
|
||||
# Show the auxv of a running process
|
||||
cat /proc/$(pidof target)/auxv | xxd
|
||||
|
||||
# From your own process (helper snippet)
|
||||
#include <sys/auxv.h>
|
||||
#include <stdio.h>
|
||||
int main(){
|
||||
printf("AT_RANDOM=%p\n", (void*)getauxval(AT_RANDOM));
|
||||
printf("AT_SYSINFO_EHDR=%p\n", (void*)getauxval(AT_SYSINFO_EHDR));
|
||||
}
|
||||
```
|
||||
Leaking `AT_RANDOM` gibt Ihnen den Canary-Wert, wenn Sie diesen Zeiger dereferenzieren können; `AT_SYSINFO_EHDR` gibt Ihnen eine vDSO-Basis, um nach Gadgets zu suchen oder um direkt schnelle Syscalls aufzurufen.
|
||||
|
||||
## References
|
||||
|
||||
- ld.so(8) – Dynamic Loader search order, RPATH/RUNPATH, secure-execution rules (AT_SECURE): https://man7.org/linux/man-pages/man8/ld.so.8.html
|
||||
- getauxval(3) – Auxiliary vector and AT_* constants: https://man7.org/linux/man-pages/man3/getauxval.3.html
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user