Un format string attack sfrutta le funzioni di formattazione della famiglia printf in C quando l’input dell’utente viene passato direttamente come argomento di formato, anziché come dato da formattare. Questa classe di vulnerabilità consente all’attaccante di leggere aree arbitrarie della memoria del processo e, attraverso il modificatore %n, di scrivere valori controllati in indirizzi arbitrari.
Il codice vulnerabile
Il pattern insicuro fondamentale è il seguente:
// VULNERABILE: l'input utente è la format string
printf(user_input);
// CORRETTO: l'input utente è il dato, non il formato
printf("%s", user_input);
Quando user_input contiene specificatori di formato come %x, %s o %n, la funzione li interpreta come istruzioni di lettura o scrittura sullo stack, indipendentemente dall’intenzione del programmatore.
Meccanismi di sfruttamento
Lettura della memoria con %x e %s
La funzione printf legge gli argomenti dallo stack nell’ordine in cui appaiono nella format string. Se non ci sono argomenti reali, legge comunque i valori presenti sullo stack:
Input: %x %x %x %x %x
Output: bffff5a0 0 bffff5c4 8049680 bffff5b8
Ogni %x consuma 4 byte dallo stack, rivelando indirizzi, variabili locali e, potenzialmente, canary di protezione.
Con %s, si dereferenzia il valore trovato sullo stack come puntatore a stringa, permettendo la lettura di aree di memoria arbitrarie — inclusi segreti, chiavi crittografiche o codice eseguibile.
Scrittura arbitraria con %n
Il modificatore %n scrive in un puntatore (prelevato dallo stack) il numero di caratteri stampati fino a quel punto:
int n;
printf("AAAA%n", &n); // n = 4
Combinando %n con padding (%100x%n) e accesso diretto al parametro (%10$n), un attaccante può scrivere valori arbitrari a indirizzi di memoria controllati — tipicamente per sovrascrivere voci della GOT (Global Offset Table) o il return address di una funzione.
Accesso diretto ai parametri (Direct Parameter Access)
La sintassi %k$x consente di accedere direttamente all’k-esimo argomento dello stack senza consumare i precedenti, rendendo l’exploit più preciso e compatto:
Input: %1$x → stampa il 1° valore sullo stack
Input: %7$n → scrive in &argv[7] sullo stack
Scenario di exploit tipico
- L’attaccante individua l’offset dello stack in cui si riflette il suo input (
%k$xfino a trovare il pattern inserito). - Inserisce nella stringa l’indirizzo di memoria target (es. una voce della GOT).
- Usa
%ncon padding calcolato per scrivere in quell’indirizzo l’indirizzo di una funzione arbitraria (es.system()). - La prossima chiamata alla funzione GOT compromessa esegue codice arbitrario.
Mitigazioni
| Contromisura | Descrizione |
|---|---|
| Eliminazione alla radice | Usare sempre printf("%s", input) invece di printf(input). Regola di Secure Coding. |
| Compiler warnings | GCC e Clang emettono -Wformat-security quando la format string non è un letterale. Abilitarla e trattarla come errore (-Werror=format-security). |
| Static analysis | Strumenti come Coverity, Clang Static Analyzer e flawfinder rilevano pattern printf(var) automaticamente. |
| FORTIFY_SOURCE | La macro _FORTIFY_SOURCE=2 aggiunge controlli runtime sulle funzioni di formato nelle libc moderne (glibc). |
| Stack canary | Mitiga parzialmente l’impatto di %n sullo stack, ma non previene la lettura di memoria. |
| RelRO + BIND_NOW | Rende la GOT di sola lettura dopo il linking, impedendo la sovrascrittura tramite %n. |
Rilevanza storica e moderna
Le format string vulnerability furono documentate sistematicamente alla fine degli anni ’90 da ricercatori come Pascal Bouchareine e hanno prodotto exploit di alto profilo su demoni Unix (wu-ftpd, rpc.statd, proftpd). Nei sistemi moderni sono rare nei software maturi ma compaiono ancora in:
- Codice embedded (firmware IoT, router) con toolchain legacy.
- Progetti C scritti senza linting di sicurezza.
- Codice generato automaticamente o portato da sistemi più vecchi.
La loro analisi rimane fondamentale nella formazione in sicurezza offensiva perché illustra in modo pulito come un’API mal usata apra canali di lettura e scrittura arbitraria della memoria.