Seri: Scapy ile Etik Hacking — Bölüm 2 / 4
Seviye: Başlangıç → Orta
Ön koşul: 101'i oku — katman mantığını ve send/sr farkını bilmen şart
Bu Bölümde Öğreneceklerin
101'de paket mantığını öğrendik. Şimdi o mantığı gerçek işe koşacağız.
Bir sızma testinde "keşif aşaması" (reconnaissance) şu soruları cevaplar:
- Ağda hangi cihazlar var?
- Bu cihazlarda hangi portlar açık?
- Hangi servisler çalışıyor, hangi versiyon?
- İşletim sistemi ne?
Nmap bu soruları cevaplar — ama imzasını her IDS tanır. Scapy ile aynı işi farklı şekillerde yapabilirsin. Önemli olan arka planda ne döndüğünü anlamak.
Feynman Durağı #1 — TCP El Sıkışması (3-Way Handshake)
Port taramayı anlamadan önce TCP'nin nasıl çalıştığını anlamak şart.
İki insan telefonda konuşmadan önce şunu yapar:
- A: "Duyuyor musun?" (SYN)
- B: "Duyuyorum, sen duyuyor musun?" (SYN-ACK)
- A: "Duyuyorum." (ACK)
TCP de aynısını yapar. Buna 3-way handshake denir.
Aşağıdaki üç durum, SYN taramanın temelidir.
Sen (SYN) ──────────────► Hedef
◄────────────── Hedef (SYN-ACK) → Port AÇIK
──────────────► Sen (RST) → Bağlantıyı kes
Sen (SYN) ──────────────► Hedef
◄────────────── Hedef (RST-ACK) → Port KAPALI
Sen (SYN) ──────────────► Hedef
(cevap yok)─► Port FİLTRELİ (firewall var)SYN Tarama — "Yarı Açık" Teknik
SYN taraması neden "stealth" (gizli) sayılır?
Çünkü tam bağlantı kurulmaz. SYN gönderirsin, SYN-ACK alırsın — port açık olduğunu anlarsın — hemen RST gönderirsin, bağlantıyı kapatırsın. Log'a düşme riski azalır.
def syn_scan(hedef, port):
paket = IP(dst=hedef) / TCP(dport=port, flags="S", sport=RandShort())
# RandShort() → rastgele kaynak port
cevap = sr1(paket, timeout=2, verbose=0)
if cevap is None:
return "filtered" # Firewall engelledi ya da cevap yok
if cevap.haslayer(TCP):
flag = cevap[TCP].flags
if flag == "SA": # SYN-ACK → açık
# RST gönder → bağlantıyı temizlemek için
send(IP(dst=hedef) / TCP(dport=port, flags="R"), verbose=0)
return "open"
elif flag == "RA": # RST-ACK → kapalı
return "closed"
return "unknown"
# Tek port testi için
hedef = "10.10.10.5"
sonuc = syn_scan(hedef, 80)
print(f"Port 80: {sonuc}")
Neden böyle yaptım : Tek bir porta SYN gönder, cevabı yorumla. Neden sr1? → Cevap almamız lazım (port açık/kapalı mı) Neden timeout=2? → 2 saniye bekle, cevap gelmezse filtered kabul et
Şimdi bunu bir port listesine uygula:
def port_tara(hedef, portlar):
acik = []
for port in portlar:
durum = syn_scan(hedef, port)
if durum == "open":
print(f"[AÇIK] {port}/tcp")
acik.append(port)
elif durum == "filtered":
print(f"[FİLTRELİ] {port}/tcp")
return acik
# Yaygın portları tara
yaygin = [21, 22, 23, 25, 53, 80, 110, 135, 139, 143, 443, 445, 3389, 8080]
acik_portlar = port_tara("10.10.10.5", yaygin)Feynman Durağı #2 — Neden "SA" ve "RA"?
TCP flag'leri bitlerle ifade edilir. Scapy bunları harf kombinasyonuyla gösterir:
S = SYN
A = ACK
R = RST
F = FIN
P = PSH
U = URG
SA = SYN + ACK → "Bağlantıya hazırım"
RA = RST + ACK → "Bu port kapalı, git"Bunu bir kez anladıktan sonra flags == "SA" kontrolü ezbere gerek kalmadan mantıklı gelir.
Ek bilgi ve hatırlatma:
ACK (Acknowledgment): Onay mekanizmasıdır. Gönderilen bir verinin veya bağlantı isteğinin başarıyla alındığını karşı tarafa bildirmek için kullanılır.
RST (Reset): Bağlantıyı zorla sonlandırır. Bir hata oluştuğunda veya geçersiz bir paket alındığında bağlantıyı anında kesmek için kullanılır.
FIN (Finish): Bağlantıyı düzgünce kapatma isteğidir. Gönderen tarafın artık gönderecek verisi kalmadığını belirtir.
PSH (Push): Verinin bekletilmeden hemen uygulamaya iletilmesini sağlar. Tampon belleğin (buffer) dolmasını beklemeden veriyi "ittirir".
URG (Urgent): Acil veri bildirimidir. Paketin içindeki belirli bir verinin öncelikli olduğunu ve diğer verilerden önce işlenmesi gerektiğini belirtir.
Nmapte:
Xmas Scan: FIN, PSH ve URG bayraklarının aynı anda gönderildiği tarama türüdür. Paketin içi bir yılbaşı ağacı gibi "ışıldadığı" için bu ismi alır.
Maimon Scan: FIN ve ACK yanına bazen URG eklenerek cihazın standartlara ne kadar uyduğu test edilir.CUE NOTU — Flag Okuma Şeması
Gönderdin: SYN (S)
│
├── SA geldi? → Port AÇIK (el sıkış teklif kabul)
├── RA geldi? → Port KAPALI (reddedildi)
└── Cevap yok? → FİLTRELİ (firewall düşürdü)ARP Sweep - Aynı Ağda Kim Var?
ICMP (ping) her zaman çalışmaz — bazı hostlar ping'e cevap vermez. Ama ARP'a cevap vermek zorundalar, çünkü ARP Layer 2'de çalışır ve engellemek çok daha zordur.
ARP nasıl çalışır?
"Bu IP adresi kimin? MAC adresini söyle!" diye broadcast (herkese) soru soran bir protokol.
Sen: "192.168.1.10 kimde?" (ff:ff:ff:ff:ff:ff'ye broadcast)
Hedef: "Bende! MAC adresim 00:11:22:33:44:55"
def arp_sweep(network):
paket = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=network)
# iface → doğru interface'i seç (101'den hatırlıyoruz)
iface = conf.iface
print(f"[*] {network} taranıyor → {iface} ({get_if_addr(iface)})")
cevaplar, _ = srp(paket, iface=iface, timeout=3, verbose=0)
print(f"\n{'IP':<20} {'MAC':<22}")
print("-" * 42)
for gonderilen, gelen in cevaplar:
ip = gelen[ARP].psrc # Cevap verenin IP'si
mac = gelen[Ether].src # Cevap verenin MAC'i
print(f"{ip:<20} {mac:<22}")
print(f"\n[+] {len(cevaplar)} host bulundu")
arp_sweep("192.168.1.0/24")
Neden? Bir /24 ağındaki tüm cihazları ARP ile bul. Neden srp? → Layer 2 (Ethernet), cevap almamız lazım Neden Ether(dst="ff:ff:ff:ff:ff:ff")? → Broadcast, herkese gidiyor
Interface Seçimi — Birden Fazla Ağ Kartı Varsa
101'de get_if_list() öğrendik. Şimdi bunu tarama koduna entegre edelim:
# Foothold aldın, hangi ağ kartları var?
for iface in get_if_list():
if iface == "lo": # loopback'i atla
continue
try:
ip = get_if_addr(iface)
mac = get_if_hwaddr(iface)
if ip == "0.0.0.0":
continue
print(f"{iface:<12} IP: {ip:<18} MAC: {mac}")
except:
pass
Banner Grabbing — Servis Versiyonunu Öğren
Port açık olduğunu buldun. Peki hangi servis, hangi versiyon? Banner grabbing ile servise bağlan, kendini tanıtmasını bekle.
import socket
PROBLAR = {
21: None,
22: None,
25: b"EHLO test\r\n",
80: b"HEAD / HTTP/1.0\r\n\r\n",
110: None,
3306: None,
}
def banner_al(ip, port, probe=None):
try:
with socket.socket() as s:
s.settimeout(3)
s.connect((ip, port))
if probe:
s.send(probe)
banner = s.recv(1024).decode(errors="ignore").strip()
return banner.split("\n")[0][:80]
except (socket.timeout, ConnectionRefusedError, OSError):
return None
# Taranack IP
hedef_ip = input("Hedef IP: ").strip()
print(f"\n[*] {hedef_ip} taranıyor...\n")
for port in PROBLAR:
b = banner_al(hedef_ip, port, PROBLAR.get(port))
durum = f"Banner: {b}" if b else "cevap yok"
print(f" Port {port:<6} {durum}")
OS Fingerprinting — TTL ile İşletim Sistemi Tahmini
101'de TTL'den bahsetmiştik. Şimdi bunu işe yarar hale getirelim.
Neden TTL işe yarar?
Her işletim sistemi paketi farklı TTL ile gönderir:
- Windows → 128 (genellikle)
- Linux/macOS → 64
- Cisco IOS → 255
Paket ağda her hop'ta 1 TTL kaybeder. Sana ulaşan TTL'i bilince başlangıç TTL'ini tahmin edebilirsin.
def os_tahmin(ip):
# Hem TCP hem ICMP dene — birisi cevap verir
cevap = sr1(IP(dst=ip) / TCP(dport=80, flags="S"), timeout=1, verbose=0)
if not cevap:
cevap = sr1(IP(dst=ip) / ICMP(), timeout=1, verbose=0)
if not cevap:
print(f"[-] {ip} cevap vermedi")
return
ttl = cevap.ttl
# Gelen TTL'e bakarak başlangıç TTL'ini tahmin et
if ttl <= 64:
os_tahmini = "Linux / macOS"
elif ttl <= 128:
os_tahmini = "Windows"
elif ttl <= 255:
os_tahmini = "Cisco / Network cihazı"
else:
os_tahmini = "Bilinmiyor"
print(f"[+] {ip:<18} TTL={ttl:<4} → muhtemelen {os_tahmini}")
# Birden fazla hosta uygula
for host in ["10.10.10.5", "10.10.10.10", "10.10.10.1"]:
os_tahmin(host)Hepsini Birleştir — İç Ağ Keşif Scripti
Şu ana kadar öğrendiklerin: interface keşfi, ARP sweep, SYN tarama, banner grabbing, OS fingerprint.
Bunları birleştirince elimde ne olur?
import ipaddress
def ic_ag_kesfi(network=None):
print(" İÇ AĞ KEŞİF - SCAPY")
print("=" * 50)
print("\n[1] AĞ KARTLARI:")
for iface in get_if_list():
if iface == "lo": continue
try:
ip = get_if_addr(iface)
mac = get_if_hwaddr(iface)
if ip == "0.0.0.0": continue
print(f" {iface}: {ip} / {mac}")
# Network belirtilmemişse ilk aktif interface'i kullan
if not network:
network = str(ipaddress.IPv4Network(f"{ip}/24", strict=False))
except: pass
# ARP sweep
print(f"\n[2] ARP SWEEP: {network}")
paket = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=network)
cevaplar, _ = srp(paket, timeout=2, verbose=0)
hostlar = [(g[ARP].psrc, g[Ether].src) for _, g in cevaplar]
for ip, mac in hostlar:
print(f" LIVE: {ip:<18} {mac}")
# Açık portlar + OS tahmini
print("\n[3] PORT + OS ANALİZİ:")
kontrol_portlari = [22, 80, 443, 445, 3389]
for ip, _ in hostlar:
acik = []
ttl_deger = None
for port in kontrol_portlari:
r = sr1(IP(dst=ip)/TCP(dport=port,flags="S",sport=RandShort()),
timeout=0.5, verbose=0)
if r and r.haslayer(TCP) and r[TCP].flags == "SA":
acik.append(port)
if not ttl_deger:
ttl_deger = r.ttl
send(IP(dst=ip)/TCP(dport=port,flags="R"), verbose=0)
os_t = "Linux" if ttl_deger and ttl_deger<=64 else "Windows" if ttl_deger and ttl_deger<=128 else "?"
print(f" {ip:<18} Portlar={acik} OS≈{os_t} TTL={ttl_deger}")
ic_ag_kesfi()CUE NOTU — 102 Özeti
┌────────────────────────────────────────────────┐
│ SCAPY 102 — Aktif Keşif Özeti │
│ │
│ SYN SCAN: │
│ SYN gönder → SA geldi = AÇIK │
│ RA geldi = KAPALI │
│ Yok = FİLTRELİ │
│ │
│ ARP SWEEP: │
│ srp(Ether broadcast / ARP(pdst=network)) │
│ Layer 2 → ICMP'den güvenilir │
│ │
│ BANNER GRAB: │
│ socket.connect → recv(1024) → ilk satır │
│ │
│ OS TAHMİNİ: │
│ TTL ≤ 64 → Linux/macOS │
│ TTL ≤ 128 → Windows │
│ TTL ≤ 255 → Cisco │
└────────────────────────────────────────────────┘Feynman Son Testi
- SYN taramada neden ACK yerine RST gönderiyoruz?
- ARP sweep için neden
srp()kullanıyoruz,sr1()değil? - Banner grabbing ile servis versiyonu öğrenmek neden önemli?
get_if_addr()veget_if_hwaddr()ne döndürür?- Bir host TTL=110 ile cevap verdi. OS'u ne tahmin edersin?
Sıradaki Bölüm
Scapy 201: Trafik Analizi ve MITM — Sniffing, ARP poisoning ve ağ trafiğini araya girme. Aktif sorgulamadan passif dinlemeye geçiyoruz.
⚠️ Tüm teknikler yalnızca izin alınmış sistemlerde uygulanmalıdır.
Scapy ile Etik Hacking Serisi — Bölüm 2/4