Ele Geçirilmiş Posta Hesabını Log'larınızdan Yakalamak: Hacim, Coğrafya ve Kalıp Anomalisi
Ele geçirilen bir hesap dakikalar içinde yüzlerce spam kusar ve IP itibarınızı günlerce çöpe atar. Antivirüs değil, kendi Postfix/Dovecot log'larınız yakalar. Giden hacim sıçraması, imkânsız coğrafi seyahat ve gönderim kalıbı bozulmasını gerçek zamanlıya yakın tespit edip hesabı otomatik dondurmanın mühendisliği.
EvilMail Team26 Temmuz 202612 dk okuma
Ele geçirilmiş bir hesabı ilk fark eden şey nadiren sizsiniz. Genelde Spamhaus'un SBL bildirimi, Microsoft SNDS'nin kırmızıya dönen paneli ya da müşterinin "e-postalarım geri dönüyor" tiketi olur. O noktaya geldiğinizde iş çoktan bitmiştir: çalınan kimlik bilgisiyle giren saldırgan dakikalar içinde 500+ mesaj kusmuş, IP'niz blocklist'e düşmüş ve tüm domain'in teslimatı çökmüştür.
Acı gerçek şu: itibarı kaybetmek dakikalar, geri kazanmak günler sürer. Spamhaus DBL'den ya da Microsoft'un JMRP feedback loop'undan çıkmak otomatik değildir; delist talebi, gözlem penceresi ve temiz gönderim geçmişi ister. Pratikte elinizde kabaca altı saatlik bir pencere vardır — o pencere içinde çıkışı durdurursanız çoğu feedback loop tetiklenmeden atlatırsınız. Bu yüzden tespit reaktif ("kullanıcı şikayet etti") olamaz. Eşik tabanlı, gerçek zamanlıya yakın ve otomatik dondurmayla biten olmak zorundadır.
İyi haber: ihtiyacınız olan her şey zaten log'larınızda. Antivirüse, EDR'ye, pahalı bir SIEM'e gerek yok. Postfix ve Dovecot size üç ortogonal sinyal veriyor: giden hacim, oturum coğrafyası ve gönderim kalıbı. Hiçbiri tek başına yeterli değil — her biri meşru senaryolarla çakışır. Ama ikisi kesiştiğinde elinizde neredeyse kesin bir ele geçirme var demektir.
Sinyal 1 — Giden hacim: mutlak eşik değil, taban çizgisinden sapma
Yeni başlayan herkesin yaptığı hata: "saatte 100 mesajı geçen bloklansın" gibi statik bir tavan koymak. Bu iki nedenden çöker. Pazarlama bülteni gönderen meşru kullanıcıyı yakalar (false positive) ve saatte 40 mesaj gönderen ama normalde günde 3 mesaj gönderen ele geçirilmiş bir muhasebe hesabını kaçırır (false negative).
Doğru birim mutlak sayı değil, kullanıcının kendi geçmişine göre sapma. Her hesap için 30 günlük hareketli ortalama ve standart sapma tutun, sonra z-skoru hesaplayın:
Sürekli 0 giden mesajı olan bir temp-email hesabı için stddev sıfıra yakındır, dolayısıyla tek bir giden mesaj bile z-skorunu patlatır — ki bu tam istediğimiz şey. evilmail.pro tarafında geçici hesapların giden trafiği zaten varsayılan olarak kapalıdır; oradan tek bir SMTP kabulü görmek başlı başına olaydır.
Postfix'te per-sender sayacı log'dan çıkarmak için sasl_username alanını ayrıştırın:
bash
# Son bir saatte authenticated gönderici başına mesaj sayısı
grep -E 'sasl_username=' /var/log/mail.log \
| awk -F'sasl_username=' '{print $2}' \
| awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# Günlük özet için hızlı yol
pflogsumm -d today /var/log/mail.log | less
Ham hacimden daha keskin iki metrik var:
Alıcı/gönderim oranı (recipient-to-sent): Tek mesajda 50 alıcıya BCC atan bir hesap, 50 ayrı mesaj atandan farklıdır ama ikisi de tehlikelidir. Oran >10 ise bayrak.
Benzersiz alan adı sayısı: Meşru bir kullanıcı genelde tanıdık birkaç domain'e yazar. 1 saatte >30 farklı alıcı alan adı, adres listesi taraması demektir.
Pratik giriş eşiklerim: baz çizgisinin 5 katı VEYA saatte >200 benzersiz alıcı VEYA 1 saatte >30 farklı alıcı domain. Bunlardan biri bile tek başına HOLD tetiklemez — skora ağırlık olarak girer (aşağıda).
Sinyal 2 — Oturum coğrafyası: imkânsız seyahat ve ASN sıçraması
İkinci sinyal login meta verisinden gelir. Dovecot her başarılı IMAP/POP oturumunu remote IP ile loglar:
Bu IP'leri MaxMind GeoLite2-City ve GeoLite2-ASN ile zenginleştirin. İmkânsız seyahat klasik ilk testtir: aynı kullanıcının iki başarılı login'i arasındaki büyük çember mesafesini zamana bölün.
hız = mesafe_km / saat_farkı
hız > 900 km/s → fiziksel olarak imkânsız → alarm
Ama salt ülke değişimi zayıf bir sinyaldir. Gerçek gezginler, roaming yapan telefonlar ve VPN kullanan meşru kullanıcılar sürekli ülke atlar. Çok daha güçlü sinyal ASN türü değişimidir: kullanıcı ay boyunca konut ISP'sinden (Türk Telekom, Vodafone) girerken aniden bir hosting/VPN ASN'sine atlarsa, bu betiğin izidir. İnsanlar OVH'nin veri merkezinden e-posta okumaz.
Şüpheli listeme sabit tuttuğum ASN'ler: OVH (AS16276), DigitalOcean (AS14061), Choopa/Vultr (AS20473), M247 (AS9009), Hetzner (AS24940). Bir de Tor exit node listesi (check.torproject.org/torbulkexitlist) ve bilinen bulletproof hosting blokları. Konut ASN'sinden bu listelerden birine geçiş, imkânsız seyahatten daha yüksek kesinlik verir.
En üst kesinlik ise eşzamanlı oturumdur: aynı anda hem TR konut IP'sinden hem NG hosting IP'sinden aktif IMAP. Meşru bir kullanıcı iki yerde birden olamaz.
bash
doveadm who -1 # aktif oturumların IP envanteri
doveadm who [email protected] # tek kullanıcının tüm bağlantıları
Sinyal 3 — Gönderim kalıbı: davranışsal parmak izi
Üçüncü sinyal en insani olanı: insanlar ve betikler farklı gönderir. Ele geçirme sonrası çıkan trafik davranışsal olarak tanınabilir. Yakalanacak kalıplar:
Gövde/konu tekrarı: Aynı Subject ve gövdenin SHA-256 hash'i N farklı alıcıya kopyalanıyorsa, bu bir kampanya. Giden mesajın body'sini normalize edip hash'leyin, saatlik pencerede tekrar sayın.
Sirkadyen sapma: Kullanıcının saat diliminde 03:00-05:00 arası ani aktivite. Çoğu ele geçirme başka bir zaman diliminden yönetilir.
Anormal MIME/header: Aniden sadece-HTML tek-link gövde, boş veya rastgele Subject, Reply-To'nun gönderenden farklılaşması, yeni bir X-Mailer/User-Agent başlığı (çoğu betik varsayılan kütüphane imzasını bırakır).
BCC patlaması: Tek zarfta onlarca gizli alıcı.
Giden SpamAssassin skoru: Kendi giden akışınızı SpamAssassin'den geçirin. Kullanıcının geçmiş ortalamasına göre ani skor artışı güçlü bir işaret.
Bir de öncü sinyal var: auth başarısızlık fırtınası. Credential stuffing genelde ele geçirmeden hemen önce gelir. fail2ban'in dovecot ve postfix-sasl jail'lerini kalıp motoruna bağlayın — bir hesaba karşı yoğun başarısız login sonrası gelen ilk başarılı login, coğrafya sinyaliyle birleşince neredeyse kesindir.
Üçünü birleştirmek: ağırlıklı skor ve kademeli yanıt
Tek sinyalle karar vermek false positive fabrikasıdır. Pazarlamacı hacmi patlatır, gezgin coğrafyayı, toplu duyuru kalıbı tetikler. Korelasyon bunu çözer. Basit bir ağırlıklı skor yeter — makine öğrenmesine gerek yok:
Her sinyal 0-1 arası normalize edilir (z-skoru için sigmoid, coğrafya için ikili/kademeli, kalıp için tekrar oranı). Sonra kademeli yanıt — burası kritik, çünkü tek hamlede hard-block meşru toplu gönderimi de keser:
skor ≥ 0.5 → throttle. Postfix policy daemon'la defer verin ya da smtpd_client_message_rate_limit düşürün. Kullanıcı yavaşlar ama kesilmez.
skor ≥ 0.7 → HOLD. Policy servisi yalnızca o gönderici için HOLD döner; kullanıcının giden mesajları kuyrukta tutulur ve kullanıcıya out-of-band uyarı gider (kayıtlı ikinci e-posta ya da SMS — ele geçirilmiş kutuya değil). Ops kanalına webhook.
skor ≥ 0.85 → kick + zorunlu reset.doveadm kick ile tüm aktif oturumlar öldürülür, parola sıfırlama zorlanır, kuyruk karantinaya alınır.
bash
# Panik butonu: TÜM kuyruğu dondurur (herkesin gideni durur) — yalnız tam ihlalde
postsuper -h ALL
doveadm kick [email protected] # kullanıcının aktif oturumlarını düşür
# İnceleme sonrası temizse ilgili mesajları serbest bırak:
postsuper -H <queue_id>
Tek bir hesabı dondurmak için postsuper -h ALL yerine policy servisinin per-sender HOLD'unu kullanın; -h ALL bir acil durum kill-switch'idir ve tüm kullanıcıların giden trafiğini durdurur. Karantina kuyruğunu asla otomatik silmeyin — manuel inceleme için tutun. Ve otomatik dondurmadan sonra hesabı insan onayı olmadan açmayın. Betik dondurur, insan açar.
Uygulama: log boru hattı ve gerçek zamanlı kurallar
Mimari sade tutulmalı. Postfix ve Dovecot rsyslog/journald'a yazar; Vector ya da Fluent Bit satırları ayrıştırıp yapılandırılmış olaylara çevirir; olaylar Redis'te kayan pencere (sliding window) sayaçlarını besler; hafif bir kural motoru sayaçları okuyup skoru hesaplar ve Postfix policy servisine ya da webhook'a aksiyon yollar. GoAccess'e, ağır bir SIEM'e (Wazuh/Graylog opsiyonel) gerek yok — Redis + cron küçük/orta operatör için fazlasıyla yeter.
Postfix tarafında policy servisi main.cf içinde şöyle bağlanır:
import re, redis, time
r = redis.Redis()
RX = re.compile(r'sasl_username=(?P<u>\S+)')
for line in follow('/var/log/mail.log'): # tail -F sarmalayıcı
m = RX.search(line)
if not m:
continue
user = m.group('u')
hour = int(time.time() // 3600)
key = f'snd:{user}:{hour}'
n = r.incr(key)
r.expire(key, 3600)
base = float(r.get(f'base:{user}') or 1) # gece batch'i günceller
if n > 5 * base or n > 200:
r.publish('mailguard:alert', f'{user} hacim={n} baz={base}')
base:* anahtarlarını her gece bir batch job 30 günlük pencereden yeniden hesaplar. Coğrafya ve kalıp sinyalleri ayrı consumer'lar olarak mailguard:* kanallarını dinler, skoru birleştirir ve eşiğe göre postsuper/doveadm çağırır.
Operasyonel kontrol listesi
Postfix, authenticated gönderimlerde sasl_username'i zaten smtpd log satırına yazar; bunu loglamak için smtpd_sasl_authenticated_header'ı açmayın — o parametre kullanıcı adını giden mesajın başlığına ekleyip alıcıya sızdırır.
Per-user 30 günlük gönderim baz çizgisini gece batch ile güncelleyin.
MaxMind GeoLite2-City ve GeoLite2-ASN'yi haftalık geoipupdate ile taze tutun.
SNDS, Google Postmaster Tools ve Spamhaus DBL/SBL feedback loop'larını izleyin — bunlar son savunma hattı, ilk değil.
smtpd_client_message_rate_limit ve anvil ile mutlak bir tavan koyun; anomali motoru kaçırsa bile hard limit devreye girer.
Karantina kuyruğu ve serbest bırakma (postsuper -H) prosedürünü belgeleyin.
Otomatik dondurmadan sonra hesabı insan onayı olmadan açmayın.
Temp-email hesapları için giden'i tamamen kapatın ya da sıfır-tolerans eşiği uygulayın — bu akışta meşru giden trafik zaten yoktur.
Bu üç sinyal ayrı ayrı gürültülüdür; birlikte cerrahidir. Amaç mükemmel tespit değil — amaç, altı saatlik itibar penceresi kapanmadan çıkışı durdurmak. Bir kez giden kuyruk donduğunda, saldırganın elinizdeki en değerli varlığı yani IP ve domain itibarınızı yakma şansı biter.