Questo bug è diffusissimo, la vulnerabilita è causata da un errore nel utilizzare una funzione che usa stringhe formattate, in C la più nota è naturalmente printf.

Chi ha fatto anche un semplice Hello World in questo linguaggio sa che ci sono due parametri in printf(nel secondo anche di più dato che usa ...) nel primo parametro si inserisce la stringa da scrivere con la possibilità  di inserire caratteri speciali di formattazione, i soliti %s,
%d, %x, %n ecc.... ebbene printf si ferma appena trova triva % e converte i parametri associati a seconda della lettera sucessiva a %.
Questo bug scatta quando si passano in input parametri mai passati dato che la funzione visualizzerebbe valori sucessivi alla stringa, quindi... quindi... come il buffer overflow potremmo accedere e modificare ebp, eip e giocare sullo stack ottenendo gli indirizzo di ritorno delle CALL e iniettare magari una bella shellcode con un exploit, questo perchè i parametri che si passano a printf usando ... sono come puntatori quindi passando altri parametri printf farà :

printf(stringa_contiene_%x_, il parametro_sarà _il_primo_valore_dopo_la_stringa);

Prima di approfondire lo sfruttamento dell'errore ecco una funzione(sempre il C che è il linguaggio più bacabile)

//NOTA: il bug c'è solo su *nix, su windows a me il giochino non funziona
void formatString(char* str) {
char buffer[10];
bzero(&buffer, 10);
strncpy(buffer, str, 10);
printf(buffer);/*
errore, tanto per cominciare usare sempre esplicitamente %s o il formato da usare
*/
}

una volta compilato con

cc bug.c -o bug

prendendo la stringa da riga di comando potremmo stampare appunto parametri mai passati:

./bug %x

in questo modo vedremo 1 valore sucessivo al nostro buffer in esadecimale(%x vuol dire esadecimale)

Su mio linux ottengo:

fef59ac1

questo valore è la conversione a base 16 di quello contenuto nello stack subito dopo il nostro buffer, ogni volta che ripetiamo %x vedremo 1 valore dopo

./bug %x%x

mostrerebbe il secondo valore e così via, per vedere tipo 50 valori dopo senza scrivere tutti i simboli si usa una stringa come questa:

$numero_valori%formato

dove formato è x per %x d per %d ecc...
quindi per 50 dopo a base 16 avremo:

$50%x

sul mio sistema ad esempio ottengo:

0fef55ac0

come valore al 50-esimo posto

Però per sfruttare questa falla di sicurezza se non si può modificare la memoria a poco ci servirebbe, ecco che ci torna in aiuto %n, che serve per stampare il numero di caratteri stampati fino un indirizzo che gli passiamo a parametro, ecco un esempio, se volessimo scrivere 4 in 0x21222324h e il nostro buffer è il 5 parametro dovremmo prima di tutto invertire l'indirizzo in 24232221 se si usa il little-endiam(architettura dove il bit più basso è il meno importante e viceversa), quindi facendo una shellcode come questa:

char shellcode[] ="x24x23x22x21$5%n";

Quello che bisogna trovare è l'indirizzo da modificare, in questo caso facendo qualche ricerca si scopre che in linux lo stack va da 0xbffff000 a 0x08048000, quindi per trovare l'indirizzo di ritorno o li proviamo tutti oppure si usa il solito costrutto

$10%s

Quello mostra una stringa che parte dall'indirizzo che si trova al parametro 10... sapendo che ogni parametro occupa 4 bytes noi potremmo sapere "quanto più in su" è l'indirizzo di ritorno, se il risultato del costrutto sopra mostrasse il nostro input, il parametro 10 sarebbe l'indirizzo del primo carattere del buffer, quindi si potrebbe exploiare direttamente quel indirizzo, ma è più affidabile tentarli tutti visto che non sempre gli indirizzo sono li stessi.

Questo è tutto... cioè... tutto quello che sono riuscito a spiegare, ci sono sicuramente altri casi, trucchi ecc... se volete approfondimenti da parte di veri esperti di bug, exploit, shellcode e in particolare il format string bug cercare articoli del "team-teso", essenzialmente in inglese ma se siete fortunati pescate qualche traduzione.