<summary><strong>Naucz się hakować AWS od zera do bohatera z</strong><ahref="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* Pracujesz w **firmie z branży cyberbezpieczeństwa**? Chcesz zobaczyć, jak Twoja **firma jest reklamowana na HackTricks**? lub chcesz mieć dostęp do **najnowszej wersji PEASS lub pobrać HackTricks w formacie PDF**? Sprawdź [**PLANY SUBSKRYPCYJNE**](https://github.com/sponsors/carlospolop)!
* **Dołącz do** [**💬**](https://emojipedia.org/speech-balloon/) [**grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** mnie na **Twitterze** 🐦[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
W języku C **`printf`** to funkcja, która może być używana do **wyświetlania** ciągu znaków. **Pierwszym parametrem**, którego oczekuje ta funkcja, jest **surowy tekst z formatami**. **Następne parametry** oczekiwane są jako **wartości** do **podstawienia** za **formatery** z surowego tekstu.
Podatność pojawia się, gdy **tekst atakującego jest używany jako pierwszy argument** tej funkcji. Atakujący będzie w stanie stworzyć **specjalne dane wykorzystując** możliwości **ciągu formatującego printf**, aby odczytać i **zapisać dowolne dane pod dowolnym adresem (do odczytu/zapisu)**. Dzięki temu będzie mógł **wykonać dowolny kod**.
Format **`%<n>$x`**, gdzie `n` to liczba, pozwala wskazać funkcji printf, aby wybrała n-ty parametr (ze stosu). Jeśli chcesz odczytać 4. parametr ze stosu za pomocą printf, możesz to zrobić w następujący sposób:
Zauważ, że atakujący kontroluje parametr `pr`**`intf`, co oznacza, że** jego dane wejściowe znajdą się na stosie podczas wywołania `printf`, co oznacza, że może wpisać konkretne adresy pamięci na stosie.
Atakujący kontrolujący to wejście, będzie mógł **dodać dowolny adres na stosie i sprawić, że `printf` będzie mógł się do nich odwołać**. W następnej sekcji zostanie wyjaśnione, jak wykorzystać to zachowanie.
Możliwe jest użycie formatownika **`$n%s`** aby sprawić, że **`printf`** pobierze **adres** znajdujący się na **pozycji n**, a następnie **wyświetli go jakby był to łańcuch znaków** (wyświetli do momentu znalezienia 0x00). Dlatego jeśli bazowy adres binarny to **`0x8048000`**, a wiemy, że dane użytkownika zaczynają się na 4. pozycji na stosie, możliwe jest wyświetlenie początku binarnego za pomocą:
Formatter **`$<num>%n`** zapisuje **liczbę zapisanych bajtów** pod wskazanym adresem w parametrze \<num> na stosie. Jeśli atakujący może zapisać tyle znaków, ile chce za pomocą printf, będzie mógł spowodować, że **`$<num>%n`** zapisze dowolną liczbę pod dowolnym adresem.
Na szczęście, aby zapisać liczbę 9999, nie trzeba dodawać 9999 "A" do wejścia, można użyć formatera **`%.<num-write>%<num>$n`** do zapisania liczby **`<num-write>`** w **adresie wskazywanym przez pozycję `num`**.
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
Jednakże zauważ, że zazwyczaj aby zapisać adres tak jak `0x08049724` (co jest OGROMną liczbą do zapisania naraz), **używa się `$hn`** zamiast `$n`. Pozwala to **zapisać tylko 2 bajty**. Dlatego ta operacja jest wykonywana dwukrotnie, raz dla najstarszych 2B adresu i drugi raz dla młodszych.
W tym przykładzie celem będzie **nadpisanie****adresu****funkcji** w tabeli **GOT**, która zostanie później wywołana. Chociaż można to wykorzystać do innych technik zapisu arbitralnego do wykonania:
Jak wspomniano, aby zapisać adres, zazwyczaj potrzebne są 2 kroki: Najpierw **zapisujesz 2 bajty** adresu, a następnie pozostałe 2. Do tego używa się **`$hn`**.
Możliwe jest nadużycie działań zapisu podatności na formatowanie łańcuchów do **zapisywania adresów ze stosu** i wykorzystanie podatności typu **przepełnienie bufora**.
* 32 bity, brak relro, brak canary, nx, brak pie, podstawowe użycie formatowania łańcuchów do wycieku flagi ze stosu (nie trzeba zmieniać przepływu wykonania)
* 32 bity, relro, brak canary, nx, brak pie, formatowanie łańcuchów do zapisania adresu wewnątrz funkcji main w `.fini_array` (aby przepływ znowu się zapętlił) i zapisania adresu `system` w tabeli GOT wskazującej na `strlen`. Gdy przepływ wraca do funkcji main, `strlen` jest wykonywane z wejściem użytkownika i wskazując na `system`, wykonuje przekazane polecenia.