Salı, Mart 10

Shellcode Linux - 1

Evet sevgili blok okurlarımız bugün şu shellcode mevzusuna biraz değineceğiz hafif bir assembly hafif bir C hafif birazda beyinle bu mevzu hallolacaktır diye düşünüyorum. 

Neymiş bu Shellcode önce onu öğrenelim;

Shellcode hattı zatında bu gördüğümüz "x/" "x45" bilmem ne gibi hex codelerin makine dilinden okunarak bug olan application üstüne enjekte edilmesiyle çağırılan kodlar silsilesidir desek oturaklı bir tabir olur sanırım. Gerekli olan malzemeleri yukarıda verdik ama yinede küçük bir liste yapalım;

  • Birazcıcık Linux
  • Assembly
  • C < (Arada Derede)
  • Beyin
Gerekli olan malzemeleri listelediğimize göre şimdi bu mevzuda içli dışlı olacağımız assembly için Genel Register Listelerine bir bakalım isterseniz çünkü bu adresler üzerinden Linux System Call Number ile hareket edeceğiz.


Evet ASM için kayıt adresleri yukarıda listelenmiş gözüküyor isterseniz kısaca bunuda açalım diyecekken aklıma Türkçe olarak gördüğüm ve müthiş derecede başarılı bulduğum bir arkadaşın bu konuda makalesi geldi ben burayı kısadan yine açıklayıp geçeceğim lakin kesinlikle bunu seriyi sabırla okumanızı tavsiye ediyorum.

Velhasıl kelam bizde gelelim işi özüne;

EAX, EBX,ECX,EDX bu ifadelerin hepsi ASM x86(32 BIT) işlemciler için genel amaçlı kayıt adresleridir. 
AX,BX,CX,DX bu ifadelerin hepsi yukarıda ki ifadelerle çelişik olarak 16 Bit kayıt adresleri olarak karşımıza çıkarlar.(anlayacaksınız)
AH,BH,CH,DH ifadeleri ise High etiketiyle karşımıza çıkar ki bu yüksek önem taşıyan registerlar anlamına gelir ikilik 8 Bit regiterlarda öncelik olduğunu gösterir bu registerlar 8 Bit grubuna dahildir
AL,BL,CL,DL ifadeleri ise Lower etiketiyle karşımızadalar bunlarda düşük önceliği olan registerlardır.

Şimdi yukarıdakilerle beraber bir örnek verelim;

0x80706050

Görülen adreste Little Endian sistemini kullanacağız yani adresi sağdan sola doğru okuyacağız ki bunun birde Big Endian sistemi vardır ordada soldan sağa doğru bir okuma terimi vardır yukarıda belirttiğim kaynakta arakadaş detaylı olarak girmiş bu konulara incelerseniz göreceksiniz. Velhasıl kelam;

0x50 < Bu değer bizim yukarıda bahsettiğimiz AL değerimizdir yani Lower düşük öncelikli değerdir ki ilk 8 Bitlik olan ilk Bytemizi cebimize koyduk
0x60 < Bu değerimiz ise yukarıda bahsedilne AH yani High registerda önceliği olan kaydedicinin aldığı değerdir. -Little Endian sistemiyle gidiyoruz sağdan sola gördüğünüz üzere-
0x8070 < Bu değeri inceleyecek olursak eğer bu değerimiz 16 Bit değerinde ki alt registerlardan ikili olan AX aittir.
0x80706050 < Total değere zaten baktığımızda EAX registerını görmüş oluyoruz 4 Byte değerinde bir register 1 Byte = 8 Bit eşit olarak düşünürsek mevzu tamamdır karşimm.

Kısaca bahsettiğimize göre asıl mevzumuza artık geçebiliriz şimdi ikinci adımda gerekli olan malzemeleri görelim isterseniz;
  • gcc - C - C++ Kod derleyici
  • ld – Bağlayıcı Toolumuz, Derlenen ASM Kodu Bağlamaya yarar kendileri.
  • nasm - Netwide Assembler Tercihe Göre.
  • objdump – Objdump reverse encinerink yapan arkadaşların dostu, obje bilgileri, hex vs.
  • strace –  Sistem hareketleri ve iz takibi.


Shellcode Vakti




Aslında yapmak istediğimiz her ne olursa olsun illa ki bir assembly uğruyoruz burda assembly ile ürettiğimiz kodları açık olan yazılıma enjekte ederek elde edilen sonuçla yürüyeceğiz -ki zaten shellcode teriminin amacı assembly ile yazılmış satırları shellcode vasıtasıyla makineye okutmak ve ondan dönen sonuçla bilitibar hareket etmektir. Örneğin; Ben application bir yerinde açık bulduysam ordan bir "sh" almak istiyorsam oraya /bin/sh yazamam makine bu dilden anlamaz bu makinenin syntax başka çok başka. O sadece sayılardan anlar ve atanan değerlerden bu sayede shellcode çevirerek programların içine enjekte ediyoruz ve dönen sonuçla hareket ediyoruz diyebiliriz.

Shell.c
#include <stdio.h>
const char shellc[]="x/shellcode";
main(){
int (*shell)();
shell=shellc;
shell();
}


Evet yukarıda ki C kodumuz üstünden yürüyeceğiz, lakin bunu yapmadan önce shellcode generate için burda ve dahi sürekli kullamacağımız "system call number" yani çağıracağımız fonksiyonun numaraları lazım diyebiliriz. 

Peki bunlar nelerdir diye soracak olursanız;

http://asm.sourceforge.net/syscall.html 

Local'de görmek isterseniz ? 

Yukarıda gördüğünüz adreste belirtilen fonksiyonlar ile sistemde hareket edeceğiz write, exit, pause, reboot bla bla bla diye devam ediyor. Peki nasıl kullanacağız görelim isterseniz, küçük bir asm dizisi yazalım.


Shello.asm
;shello.asm
;s3f4 / / / TG
[SECTION .text] ;kod girişi yapıcam ben
global _start ;dizin adı
_start: ;bu dizine kod girişi
  mov eax, 29 :sys_pause çağırın bana
  int 80h  ;Kernel Hazırlansın(80h kerneli çağırır)

Evet yukarıda belirttiğimiz üzere küçük bir ASM dizesi yazdık peki yazmakla mevzu bitiyormu elbette hayır devamını görsel olarak inceleyelim;


Nasm ile dosyasımızı derledikten sonra sırada ki komutumuz yukarıda da belirttiğimiz gibi "ld" komutu olacak;

Evet şimdi dizinimize bir adet shells adında dosya çıkacak isterseniz bunu çalıştırdığımızda neler olduğunu bir görelim;




Evet nolduğunu anlamak için aslında sistem çağrı numaralarını kontrol etmemiz yetecektir en nihayetinde "29" sadece Gümüşhane'nin plakası değil yani bakalım neymiş bu;

29. sys_pause

Syntax: int sys_pause(void)
Source: arch/i386/kernel/sys_i386.c
Action: wait for signal
Details:



Evet ne olduğunu anladık pause hepimizin bildiği pause işlemi askıya alıp hazırda bekletiyor bunu ASM kodu ile çağırarak bir pause işlemi yapmış olduk. Yukarıda da dediğimiz gibi bu makineler kodlar arasında pause anlamaz resume anlamaz exit anlamaz bu kodlar sayı anlar register adresi anlar sistem çağrı numarası anlar hücre anlar burda kelime odaklı çalışma mevzusunu askıya alalım burda ki mevzu tamamen makine mimarisinin dili tağam mı?



Peki başlığımızla mütevellit şimdi bu kodları bir shell kodu olarka çalıştırmak istersek ne yapmamız gerekecek ? Evet devam edelim;



Yukarıda ki imajda görüldüğü üzere shellcode değerleri için objdump kullanıyoruz ki bu Linux platformdada reverse engineering için vazgeçilmez araçlardan biridir, çıkan kodları incelediğimizde;

  b8 1d 00 00  00
  cd 80

Gibi değerler görüyoruz asıl iş burda kardeşim bize lazım olanlar bunlar, objdump ile bu değerler bize shellcode üreterecek asli değerleri verecek lakin burda bir problem var biraz fazla sıfır var sanırım değil mi? Shellcode içinde ismine yabancı olmadığımız bir terim var null byte, bunu lfi injection'da görürsünüz, login form geçişlerinde görürsünüz, crash exploitlerde görürsünüz ki yaygındır programcının hatalarını istismar etmekte kullanılır neyse kafa karıştırmayalım burda hiç bir türlü işimize yaramayan null byte yerine farklı bir sistem uygulamalıyız. Bunu yazmadan önce isterseniz yukarıda gördüğümüz değerleri işe yaramasada bir shellcode stiline çevirelim;

              Shellcode:“\xb8\x1d\x00\x00\x00\xcd\x80
  

Yukarıda görülen çıktının shellcode olarak çıktısı bu şekilde olmalıydı lakin null byte shellcode içinde çalıştırmayacağımız ve bu değerin hiç bir manası olmadığı için cpu içinde dönmeyeceğinden dolayı alternatif bir işlem yapacağız bu işlemin adı "xor" işlemi ki bu işlem belirtilen register adresinin içini sıfırlar yani ben şimdi şöyle bir şey yapmak yerine;

mov eax, 0

Eax'ın değerine sıfır kaynağını okut demek yerine xor işlemini kullanacağım ki bu matematiksel bir işlemdir bizi null byte değerlerinden kurtaracaktır görelim;

Kodumuzu gördük xor işlemi yaptık gelen sonuçları önce derleyip sonra objdump ile görelim bakalım neler çıkmış bir anlayalım;

Evet sofiler xor ile null byte mevzusundan kurtulduk şimdi bu kodumuzu açık olduğunu bildiğimiz bir C kod içinde derleyip çalıştırmayı deneyelim ve çıkan sonuçları buraya kaydedelim.
const char pausecode[]="\x31\xc0\xb0\x1d\xcd\x80";
main(){
int (*shell)();
shell=pausecode;shell();
}

Şu şekilde C kodumuzun içine shellcode gömdük hani demiştik ya kardeşim biz kod içinde yav bi dur pause yapayım yav bi dur print ettireyimf felan diyemeyiz bu dilden anlamaz makine söylemiştik hangi dilden anladığını bu kodu bir derleyelim bakalım ne çıkacak;

root@tgseclnx:~/Desktop/reverse# gcc asmpau.c -o pauses
root@tgseclnx:~/Desktop/reverse# ./pauses

Evet çıkan sonucuda görmek istersek waiting signal gösterecek çünkü bu system call number yani çağrı numarasına baktığımızda açıklamasıyla beraber(-ki kendileri 29 numarada koşuyor) sistemde açıklanan görevi yerine getirdiğini göreceğiz.

(Evet aşağıda ki screenle beraber derlenen shellcode'nin çalıştığınıda görmüş olduk.)


Şimdi işleri biraz daha büyütelim ekrana bişeyler yazdıralım ne yazdıralım örneğin "Hello World" ki bizim offical cümlemizdir onu bir yazdıralım bakalım ne yapmamız gerekiyor hee demeyin ki yav sefa biz bunu pythonla'da yazdırırız ekrana perl ilede felanda filanda tamam yazdırırsınız ama sadece yazdırmış olursunuz o hazırlar halleder yazar siz burda hem pişirip hem yemeyi öğreniyorsunuz daha doğrusu hep beraber öğreniyoruz diyelim şuna. ---Devamı 2. Seriye--

Aslında 1. Seriyi Bu kadar kısa tutma niyetim yoktu ama 1. Seri şimdilik bu kadarla sonlansın diyelim yazının devamını ise 2. seriye aktaracağım takip edebilirsiniz.

Sevgiyle.


/**

Allahu Teala Hazretleri Buyuruyor ki;
"İlmi İsteyene, Rızkı ise İstediğime Veririm..."

*/







3 yorum:

  1. hikaye tadında okudum eline sağlık çok iyi

    YanıtlaSil
  2. Eline sağlık paylaşımın için teşekkür ederim. Yazını şu http://kali-linuxtr.net/ adreste paylaşmak istiyorum müsaden olursa

    YanıtlaSil
    Yanıtlar
    1. merhabalar, elbette paylaşmanızda bir beis yok blog üstünde ki her içerik kaynak gösterilmek suretiyle paylaşılabilir.

      Sil

Blogger tarafından desteklenmektedir.