Python ile Exploit Kodlama: Temelleri Anla!
Selamlar THT Ailesi!Bu konuda, siber güvenlik dünyasının en heyecan verici ve kritik alanlarından biri olan exploit geliştirmeye Python diliyle nasıl giriş yapabileceğimizi anlatacağım. Amacımız, temel komutları ve mantığı anlayarak kendi basit exploit'lerimizi yazabilecek seviyeye gelmek. Unutmayın, bu bilgiler eğitim amaçlıdır ve sadece yetkilendirilmiş test ortamlarında kullanılmalıdır. Yetkisiz kullanım yasa dışıdır ve ciddi sonuçları olabilir!
Neden Python?
Python, basit söz dizimi, hızlı prototipleme yeteneği ve geniş kütüphane desteği sayesinde exploit geliştirmek için harika bir dildir. Ağ işlemleri, veri manipülasyonu gibi ihtiyaç duyduğumuz birçok şeyi kolayca yapmamızı sağlar.
Python Exploit Geliştirmenin Temel Taşları
Bir exploit yazarken temel olarak iki şey yaparız: Hedef sistemle iletişim kurarız ve zafiyeti tetikleyecek özel veriyi (payload) ona göndeririz. İşte bu iki ana adımı gerçekleştirmek için kullanacağımız temel Python kütüphaneleri:1. Ağ Bağlantısı Kurmak: socket Kütüphanesi
socket kütüphanesi, Python'ın ağ iletişimini sağlamak için kullandığı temel araçtır. Bir hedef sunucuya bağlanmak, ona veri göndermek veya ondan veri almak için bunu kullanırız.
- Nasıl Bağlanırız?i
-
Python:
import socket HEDEF_IP = "192.168.1.10" # Exploit'i uygulayacağın sunucunun IP adresi HEDEF_PORT = 80 # Genellikle 80 (HTTP), 21 (FTP) veya zafiyetli servisin portu try: # Bir TCP soketi oluşturuyoruz (socket.AF_INET = IPv4, socket.SOCK_STREAM = TCP) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HEDEF_IP, HEDEF_PORT)) # Hedefe bağlanıyoruz print(f"[+] {HEDEF_IP}:{HEDEF_PORT} adresine başarıyla bağlandı!") except Exception as e: print(f"[-] Bağlantı hatası: {e}") exit() # Hata olursa programı sonlandır
- Ne İşe Yarar? Bu kod parçası, exploit'inin hedef sistemle ilk temasını kurmasını sağlar. Bir web sunucusu, FTP sunucusu veya özel bir uygulama fark etmez, hedefin dinlediği porta bağlanırız.
- Hedefe Veri Göndermek:
-
Python:
# Bağlantı kurulduktan sonra... mesaj = b"Merhaba, ben bir test mesajıyım!\r\n" # Göndereceğimiz mesaj (b"" ile byte formatında) s.send(mesaj) # Mesajı gönder print("[+] Mesaj gönderildi.")
- Ne İşe Yarar? Bu kod parçası, exploit'inin hedef sistemle ilk temasını kurmasını sağlar. Bir web sunucusu, FTP sunucusu veya özel bir uygulama fark etmez, hedefin dinlediği porta bağlanırız.
- Ne İşe Yarar? Zafiyeti tetikleyecek olan özel "payload"ımızı (yükümüzü) veya normal bir isteği bu komutla hedefe göndeririz. b"" kullanmak önemli çünkü ağ üzerinden her zaman ikili (byte) veri gönderilir.
Hedeften Cevap Almak:
Python:
# Bağlantı kurulduktan sonra...
cevap = s.recv(1024) # Hedeften 1024 byte'a kadar veri al
print(f"[+] Sunucudan gelen cevap: {cevap.decode('utf-8', errors='ignore')}") # Byte'ı okunur metne çeviriyoruz
- Ne İşe Yarar? Exploit'imizin başarılı olup olmadığını anlamak veya hedefin verdiği bir hata mesajını görmek için gelen cevabı okuruz.
Bağlantıyı Kapatmak:
Python:
s.close() # İşimiz bittikten sonra bağlantıyı kapatırız
print("[+] Bağlantı kapatıldı.")
Veri Paketleme: struct Kütüphanesi (Buffer Overflow için Kritik!)
Özellikle Buffer Overflow (Bellek Taşması) gibi zafiyetlerde, bellekteki belirli adreslerin üzerine yazmamız gerekir. Bu adresler veya diğer ikili veriler, hedef sistemin beklediği belirli bir formatta (örneğin, 4 baytlık küçük endian tamsayı) olmalıdır. struct kütüphanesi bu "paketleme" işlemini yapar.
Adresleri veya İkili Veriyi Hazırlamak:
Python:
import struct
# Bellek adresi (örneğin, bir fonksiyonun adresi)
return_adresi = 0xDEADBEEF # Bu, hedef sistemdeki bir bellek adresini temsil eder
# Adresi ikili formata paketle
# "<I" -> Küçük endian (little-endian) formatında 4 baytlık işaretsiz tam sayı
paketlenmis_adres = struct.pack("<I", return_adresi)
print(f"Paketlenmiş adres: {paketlenmis_adres}") # Çıktı: b'\xef\xbe\xad\xde'
- Ne İşe Yarar? Buffer overflow saldırılarında programın normal akışını değiştirmek için Instruction Pointer (EIP/RIP) üzerine kendi belirlediğimiz bir adresin yazılmasını sağlarız. struct.pack() tam olarak bu hedefi gerçekleştirmek için gerekli formatlamayı yapar.
pwntools, exploit yazmak için tasarlanmış harika bir Python kütüphanesidir. Yukarıdaki socket ve struct işlemlerini çok daha kolay ve hızlı yapmanı sağlar, ayrıca kabuk kodu (shellcode) oluşturma gibi gelişmiş özellikler de sunar.
- Kurulum:
pip install pwntools
pwntools ile Bağlantı ve Gönderme Örneği:
Python:
from pwn import * # pwntools kütüphanesini içe aktar
HEDEF_IP = "192.168.1.10"
HEDEF_PORT = 1337 # Örnek bir port
# Uzak bir sisteme bağlan
r = remote(HEDEF_IP, HEDEF_PORT)
print(f"[+] {HEDEF_IP}:{HEDEF_PORT} adresine pwntools ile bağlandı!")
# Payload'ımızı oluştur
payload = b"A" * 100 # Örnek 100 tane 'A' karakteri
payload += p32(0xDEADBEEF) # p32() = 4 baytlık küçük endian adres paketleme (struct.pack("<I", ...))
# p64() = 8 baytlık küçük endian adres paketleme (x64 sistemler için)
r.send(payload) # Payload'ı gönder
print("[+] Payload gönderildi.")
# Hedefle etkileşimli bir kabuk açmaya çalış (exploit başarılıysa)
# r.interactive()
r.close() # Bağlantıyı kapat
print("[+] Bağlantı kapatıldı.")
- Ne İşe Yarar? pwntools ile remote() komutuyla saniyeler içinde ağ bağlantısı kurabilir, p32() veya p64() gibi fonksiyonlarla adresleri kolayca paketleyebilirsin. r.interactive() ise exploit başarılı olduğunda doğrudan hedef sistemle etkileşimli bir kabuk (shell) oturumu açmanı sağlar. Bu kütüphane, ciddi exploit geliştirmeleri için vazgeçilmezdir.
Basit Bir Exploit Akışı (Kavramsal Örnek)
Bir exploit genellikle şu adımları takip eder:- Zafiyeti Anla: Hedef yazılımdaki hatanın (örneğin, sabit boyutlu bir değişkene kapasitesinden fazla veri girilmesi) nasıl çalıştığını ve neleri etkilediğini çöz.
- Payload Oluştur: Zafiyeti tetikleyecek ve istediğimiz sonucu (örneğin, bir kabuk çalıştırmak) doğuracak özel veriyi hazırla. Bu veri genellikle bir "padding" (belleği dolduracak gereksiz veri), bir "return adresi" (programın nereye atlamasını istediğimiz), ve bir "shellcode" (çalıştırılacak küçük kod) içerir.
- Bağlan ve Gönder: Python socket (veya pwntools) kullanarak hedef sisteme bağlan ve hazırladığın payload'ı gönder.
- Sonucu Gözlemle: Exploit başarılı olduysa, hedef sistemde istediğin eylemin gerçekleştiğini görürsün (örneğin, bir ters kabuk gelir, bir dosya oluşturulur).
TEMEL KOMUTLAR VE İŞLEVLERİ
1. Ağ İletişimi Komutları (socket Kütüphanesi)
socket kütüphanesi, hedef sistemle ağ bağlantısı kurmak, veri göndermek ve almak için temel Python aracıdır.- import socket
- İşlev: socket kütüphanesini Python koduna dahil eder. Bu kütüphanenin fonksiyonlarını kullanmak için ilk adımdır.
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- İşlev: Yeni bir soket (ağ bağlantı noktası) oluşturur.
- socket.AF_INET: IPv4 adres ailesini kullanacağımızı belirtir.
- socket.SOCK_STREAM: TCP (güvenilir, bağlantı tabanlı) protokolünü kullanacağımızı belirtir. UDP için socket.SOCK_DGRAM kullanılır.
- İşlev: Yeni bir soket (ağ bağlantı noktası) oluşturur.
- s.connect(("hedef_ip", hedef_port))
- İşlev: Oluşturulan soket ile belirtilen IP adresindeki ve porttaki hedef sisteme bağlantı kurar. Exploit'in hedefle iletişime geçmesini sağlar.
- Örnek: s.connect(("192.168.1.10", 80))
- İşlev: Oluşturulan soket ile belirtilen IP adresindeki ve porttaki hedef sisteme bağlantı kurar. Exploit'in hedefle iletişime geçmesini sağlar.
- s.send(b"veriler")
- İşlev: Bağlantı üzerinden ikili (byte) veri gönderir. Bu, exploit'in payload'ını, kötü niyetli istekleri veya diğer verileri hedefe iletmek için kullanılır. Gönderilen verinin başında b olması, onun bir byte dizisi olduğunu gösterir.
- Örnek: s.send(b"GET / HTTP/1.0\\r\\n\\r\\n")
- İşlev: Bağlantı üzerinden ikili (byte) veri gönderir. Bu, exploit'in payload'ını, kötü niyetli istekleri veya diğer verileri hedefe iletmek için kullanılır. Gönderilen verinin başında b olması, onun bir byte dizisi olduğunu gösterir.
- cevap = s.recv(BUFFER_BOYUTU)
- İşlev: Bağlantı üzerinden hedeften gelen veriyi okur ve alır. BUFFER_BOYUTU (örneğin 1024), kaç bayta kadar veri alınacağını belirtir. Gelen verinin exploit'in başarısı veya hatalar hakkında bilgi vermesi için kullanılır.
- Örnek: cevap = s.recv(4096)
- İşlev: Bağlantı üzerinden hedeften gelen veriyi okur ve alır. BUFFER_BOYUTU (örneğin 1024), kaç bayta kadar veri alınacağını belirtir. Gelen verinin exploit'in başarısı veya hatalar hakkında bilgi vermesi için kullanılır.
- s.close()
- İşlev: Açık olan ağ bağlantısını kapatır. Kaynakları serbest bırakmak ve temiz bir çıkış sağlamak için önemlidir.
2. Veri Paketleme ve Düzenleme Komutları (struct Kütüphanesi)
struct kütüphanesi, Python verilerini C benzeri ikili formatlara dönüştürmek (paketlemek) veya ikili veriyi Python'a geri çevirmek (açmak) için kullanılır. Buffer Overflow gibi zafiyetlerde bellek adreslerini veya diğer ikili değerleri doğru formatta göndermek için kritik öneme sahiptir.- import struct
- İşlev: struct kütüphanesini Python koduna dahil eder.
- paketlenmis_veri = struct.pack("<I", deger)
- İşlev: Bir Python değerini (genellikle bir tamsayı) belirli bir format ve bayt düzenine (endianness) sahip ikili veri dizisine dönüştürür.
- "<I": Biçim dizesidir.
- <: Küçük endian (little-endian) bayt sırasını belirtir.
- I: 4 baytlık işaretsiz bir tam sayı (unsigned int) olduğunu belirtir.
- Diğer yaygın biçimler: >I (büyük endian 4 bayt), Q (8 baytlık işaretsiz uzun), B (1 baytlık işaretsiz bayt).
- "<I": Biçim dizesidir.
- Kullanım Amacı: Bellek adreslerini (örneğin, EIP/RIP üzerine yazılacak adresleri) veya diğer önemli ikili verileri hedef sistemin beklediği formatta hazırlamak.
- Örnek: struct.pack("<I", 0xDEADBEEF)
- İşlev: Bir Python değerini (genellikle bir tamsayı) belirli bir format ve bayt düzenine (endianness) sahip ikili veri dizisine dönüştürür.
- acik_veri = struct.unpack("<I", ikili_veri)
- İşlev: İkili (byte) veriyi belirli bir format ve bayt düzenine göre Python veri tiplerine (genellikle bir tuple içinde) geri dönüştürür.
- Kullanım Amacı: Hedef sistemden gelen ikili cevapları veya bellek dökümlerini analiz etmek için kullanılır.
- Örnek: struct.unpack("<I", b'\xef\xbe\xad\xde')
3. Sistem Etkileşimi Komutları (sys Kütüphanesi)
sys kütüphanesi, Python yorumlayıcısı ve çalışma zamanı ortamı ile etkileşim kurmak için kullanılır. Özellikle komut satırı argümanlarını almak exploit'leri daha esnek hale getirir.- import sys
- İşlev: sys kütüphanesini Python koduna dahil eder.
- sys.argv
- İşlev: Komut satırından Python script'ine geçirilen argümanların bir listesidir. sys.argv[0] script'in adını, sys.argv[1] ilk argümanı vb. içerir.
- Kullanım Amacı: Exploit'e hedef IP, port, payload gibi bilgileri dışarıdan parametre olarak geçirmek.
- Örnek: hedef_ip = sys.argv[1]
- sys.exit(KOD)
- İşlev: Python script'ini belirtilen çıkış koduyla sonlandırır. Genellikle bir hata durumunda veya programın işi bittiğinde kullanılır.
- Örnek: sys.exit(1) (1 genellikle hata kodu anlamına gelir)
- İşlev: Python script'ini belirtilen çıkış koduyla sonlandırır. Genellikle bir hata durumunda veya programın işi bittiğinde kullanılır.
4. Süreç Yönetimi Komutları (subprocess Kütüphanesi)
subprocess kütüphanesi, Python programından yeni süreçler (harici komutlar veya programlar) başlatmak ve bunlarla etkileşim kurmak için kullanılır. Exploit'in kendi sisteminde bazı işlemleri otomatikleştirmesi veya hedefte bir komut çalıştırması gerektiğinde (genellikle ters kabuk sonrası) faydalı olabilir.- import subprocess
- İşlev: subprocess kütüphanesini Python koduna dahil eder.
- subprocess.run(["komut", "arg1", "arg2"])
- İşlev: Belirtilen komutu ve argümanlarını çalıştırır ve tamamlanmasını bekler. Güvenli ve modern bir komut çalıştırma yöntemidir.
- Kullanım Amacı: Exploit'in kendi sisteminde (örneğin, netcat başlatmak, log dosyalarını temizlemek) veya hedefte bir komut çalıştırmak (eğer bir kabuk erişimi elde edildiysen).
- Örnek: subprocess.run(["ls", "-l", "/tmp"])
5. Gelişmiş Exploit Geliştirme Yardımcıları (pwntools Kütüphanesi - Harici)
pwntools, exploit geliştirme süreçlerini büyük ölçüde hızlandıran, çok güçlü ve özel bir kütüphanedir. Soket işlemlerini basitleştirir, bellek düzenlemeleri için özel fonksiyonlar sunar ve kabuk kodları (shellcode) oluşturmaya yardımcı olur.- from pwn import *
- İşlev: pwntools kütüphanesindeki tüm fonksiyonları ve sınıfları mevcut isim alanına aktarır, böylece doğrudan kullanabilirsin.
- r = remote("hedef_ip", hedef_port)
- İşlev: Hedef IP ve portuna kolayca bir TCP bağlantısı kurar. socket kütüphanesindeki socket.socket() ve connect() işlemlerinin basitleştirilmiş halidir.
- Örnek: r = remote("192.168.1.10", 4444)
- İşlev: Hedef IP ve portuna kolayca bir TCP bağlantısı kurar. socket kütüphanesindeki socket.socket() ve connect() işlemlerinin basitleştirilmiş halidir.
- r.send(b"veriler")
- İşlev: Bağlantı üzerinden ikili (byte) veri gönderir. socket.send() ile aynı işlevi görür ama pwntools'un remote nesnesi üzerinden kullanılır.
- r.recv(BUFFER_BOYUTU)
- İşlev: Bağlantı üzerinden hedeften veri alır. socket.recv() ile aynı işlevi görür.
- r.interactive()
- İşlev: Exploit başarılı olup bir kabuk (shell) erişimi elde edildiğinde, hedef sistemle doğrudan etkileşimli bir terminal oturumu açar. Bu, komutları manuel olarak çalıştırabilmeni sağlar.
- Kullanım Amacı: Ters kabuk (reverse shell) veya bind kabuk (bind shell) açıldıktan sonra hedef sistemle doğrudan komut alışverişi yapmak.
- p32(deger)
- İşlev: 32-bit (4 bayt) bir tamsayıyı küçük endian formatında ikili veriye dönüştürür. struct.pack("<I", deger) ile aynıdır.
- Kullanım Amacı: 32-bit sistemlerde bellek adreslerini (örneğin EIP üzerine yazılacak adresi) veya diğer ikili değerleri payload içinde kullanmak.
- Örnek: p32(0x12345678)
- p64(deger)
- İşlev: 64-bit (8 bayt) bir tamsayıyı küçük endian formatında ikili veriye dönüştürür. struct.pack("<Q", deger) ile aynıdır.
- Kullanım Amacı: 64-bit sistemlerde bellek adreslerini (örneğin RIP üzerine yazılacak adresi) veya diğer ikili değerleri payload içinde kullanmak.
- Örnek: p64(0x1122334455667788)
- cyclic(UZUNLUK)
- İşlev: Belirli bir uzunlukta benzersiz ve tekrar etmeyen bir desen (pattern) oluşturur.
- Kullanım Amacı: Buffer Overflow zafiyetlerinde, tam olarak kaçıncı baytın EIP/RIP üzerine yazdığını bulmak için kullanılır. Oluşturulan desen programın çökmesine neden olduktan sonra, çökme anındaki EIP/RIP değerini cyclic_find() ile analiz edebilirsin.
- Örnek: payload = cyclic(200)
- cyclic_find(deger)
- İşlev: cyclic() ile oluşturulmuş bir desende, belirtilen değeri arar ve o değerin desende kaçıncı baytta başladığını döndürür.
- Kullanım Amacı: Bir buffer overflow'da EIP/RIP'ye yazılan değeri bulduktan sonra, bu değerin desende nerede olduğunu belirleyerek, payload'daki offset'i (kaydırma miktarını) hesaplamak.
- Örnek: offset = cyclic_find(0x61616161) (0x61616161, EIP/RIP üzerine yazılan desenden bir parça)
