From: Serdar Koylu (serdarkoylu@fisek.com.tr)
Date: Sat 31 May 2003 - 18:53:28 EEST
See Attachment:
-- Attached file included as plaintext by Ecartis --
-- Desc: reply.txt
Selamlar..
Uzun uzun ugrastiktan sonra tum kodu indirmeyi becerdim. Buffer doldurma ve ardindan tasirma olayi yasanmis bu kesin. Kaldi ki, NULL pointer ile cagrilan fclose cogu zaman EBADF errno ile EOF dondurur, SIGSEGV'e yol acmaz. En azindan benim bildigim libc'lerde boyleydi seklinde hatirliyorum..
Asil koda bir gozatinca, bir p bufferi olusturuluyor:
> char *p, gonder[1024];
if((p = (char *) malloc(1024)) == 0 ) {
printf("Yetersiz bellek...\n");
return 1;
}
Sonrada soyle bir ana loop var. recv ile data alinip, isleniyor:
> while(recv(soket, p, 1024, 0)) {
> ##p;
p bir artiriliyor. Arti isareti bazne kaybolabildigi icin yerine # koydum..
....
...
>
> if( (strstr(p, "PRIVMSG")) != 0 && (strchr(p, '@')) != 0 )
> islet(p, &soket);
....
....
> memset(p, '\0', 1023);
> }
Simdi buraya bakarsak, p yukarida bir artiyor, ilk pass'ta mesele yok. Ama ikinci pass'ta p = p arti 2 olacak. Bu durumda 1023 byte otesi 1025. Bayt edecekki, tipik bir buffer overflow. Bu data segmenti uzerinde oldugu icin cogu zaman kritik bir exploit olmaz cogunlukla.
Bu dongunun bir sekilde 8 kez calismis olmasi soyledigim gibi bir tesaduf olmus. Burada sadece biraz acemilik kokuyor. Hepimiz acemiydik. Yani, bunu bir tur kotuleme, kinama gibi algilamayin. Oncelikle bir pointere dinamik olarak bellek atamissaniz bunu hic bir zaman degismeyecek sekilde saklamaniz gerekir. Hatta realloc yaparken bile. Mesela:
ptr = malloc(1024);
.....
.....
ptr = realloc(ptr, 2048);
Bunu yapmak bile tipik bir acemiliktir. Soyleki, ya 2048 bayt bellek ayiramazsaniz ? Orijinal bellegin adresini nasil geri kazanacaksiniz ? Gerci Linux kolay kolay burada geriye NULL dondurmez. OOM killer, elinde baltasi cikar, bulabildigi ne kadar program varsa bir guzel budar. Size bellek saglamaya calisir. Ama bir programci asla OOM killer'e guvenmemek durumundadir.
Kaldiki burada bir sekilde p bufferi uzerinde bir referans tanimlamak gerekirken dogrudan p bufferi kullanilmis. Simdi, bu yazdiginiz 1024. otesi baytlarin, gene size ait olan ve uzerine yazsaniz bile SIGSEGV olusturmayan file handler bolgesi uzerine vs. gelmedigini nerden bileceksiniz ? Belki de oyle bir yere denk geliyor, 8 bayt daha sizin, ama sonrasina yazayim dedigi anda yiyorsunuz SIGSEGV'yi. Yani buradaki 8 konusu aslinda tamamen tesaduf. Yani oradaki kodla, open, fclose ile alakali degil buyuk ihtimalle. Koda bir kac degisken vs. ekleseniz, mesela, sorun bu kez baska bir yerde karsiniza cikabilecekti..
C sizin gercekten programci oldugunuzu, ne yaptiginizi bildiginizi farzeder. Eger oyle degilseniz ve C ile ugrasmaya devam ederseniz, bir sure sonra C galip gelir ve siz iyi bir programci olursunuz.
Programda baska sorunlar da var. Mesela, recv() ile aldiginiz verinin, karsidan gelen verinin ne kadari olduguna dair hic bir ongorude bulunamazsiniz. Oncelikle receive bufferinde gelen verileri toparlamali, tam satiri vs. elde ettikten sonra o satiri parse etmeye dalmalidir.
Saygi ve sevgiler.