<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title><![CDATA[TurkTeam | Türk Siber Güvenlik Topluluğu - Python]]></title>
		<link>https://www.turkteam.org/</link>
		<description><![CDATA[TurkTeam | Türk Siber Güvenlik Topluluğu - https://www.turkteam.org]]></description>
		<pubDate>Sun, 25 Oct 2026 18:48:36 +0000</pubDate>
		<generator>MyBB</generator>
		<item>
			<title><![CDATA[Pillow CVE-2026-112900: EPS Dosyası ve Ghostscript Üzerinden Komut Çalıştırma Riski]]></title>
			<link>https://www.turkteam.org/konu-pillow-cve-2026-112900-eps-dosyasi-ve-ghostscript-uzerinden-komut-calistirma-riski.html</link>
			<pubDate>Sat, 24 Oct 2026 11:17:59 +0300</pubDate>
			<dc:creator><![CDATA[<a href="https://www.turkteam.org/member.php?action=profile&uid=2">Tonyukuk</a>]]></dc:creator>
			<guid isPermaLink="false">https://www.turkteam.org/konu-pillow-cve-2026-112900-eps-dosyasi-ve-ghostscript-uzerinden-komut-calistirma-riski.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=392" loading="lazy"  alt="[Resim: attachment.php?aid=392]" class="mycode_img" /></div>
<br />
Selamlar,<br />
<br />
Python dünyasının en yaygın görsel işleme kütüphanesi <span style="font-weight: bold;" class="mycode_b">Pillow</span> için önemli bir güvenlik güncellemesi var. The Hacker News'in 23 Ekim 2026 tarihli haberine göre <span style="font-weight: bold;" class="mycode_b">CVE-2026-112900</span>, EPS dosyalarının Ghostscript'e aktarılması sırasında dosya adının kontrolsüz iletilmesinden kaynaklanıyor. Kullanıcıdan görsel alan bir web uygulaması yazıyorsanız okumanızı öneririm.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Konuda anlatılacaklar</span></span><br />
<ol type="1" class="mycode_list"><li>Açığın özeti<br />
</li>
<li>Kimler risk altında?<br />
</li>
<li>Aynı sürümde kapanan diğer açıklar<br />
</li>
<li>Güncelleme ve Python 3.10 notu<br />
</li>
<li>Güvenli görsel işleme için kod önerileri<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">1. Açığın özeti</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>CVE           : CVE-2026-112900
Etkilenen     : Pillow 2.6.0 - 12.3.0
Duzeltme      : Pillow 13.0.0 (16 Ekim 2026)
Kosul         : Sistemde Ghostscript (gs) kurulu olmasi
Puan          : GitHub CNA 9.2; bakimcilar "orta" olarak degerlendiriyor</code></div></div>Pillow, EPS formatını kendi başına işleyemez; bu iş için sistemdeki Ghostscript'i çağırır. Sorun, bu çağrı sırasında dosya adının yeterince denetlenmemesi. Ghostscript kurulu değilse risk büyük ölçüde ortadan kalkıyor.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">2. Kimler risk altında?</span></span><ul class="mycode_list"><li>Kullanıcı yüklemelerini Image.open() ile açan ve sunucusunda gs kurulu olan uygulamalar.<br />
</li>
<li>ImageMagick veya PDF araçları nedeniyle Ghostscript'in zaten yüklü olduğu konteyner imajları.<br />
</li>
<li>Dosya uzantısına güvenen, içeriği doğrulamayan yükleme formları.<br />
</li>
</ul>
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>which gs &amp;&amp; gs --version
python3 -c "import PIL; print(PIL.__version__)"</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">3. Aynı sürümde kapanan diğer açıklar</span></span><br />
Pillow 13.0.0 iki açığı daha kapatıyor: JPEG küçük resim işlemesinde bir taşma olan <span style="font-weight: bold;" class="mycode_b">CVE-2026-112403</span> (Anthropic'in Claude modeliyle bulunup Ada Logics tarafından doğrulandı) ve 2013'ten beri kodda olan, TIFF'in belleğe yazılmasıyla ilgili <span style="font-weight: bold;" class="mycode_b">CVE-2026-112393</span>.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">4. Güncelleme</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>pip install -U "Pillow&gt;=13.0.0"
pip-audit</code></div></div>Dikkat: Pillow 13, <span style="font-weight: bold;" class="mycode_b">Python 3.10 desteğini bıraktı</span>. Hâlâ 3.10 kullanan projelerde önce Python sürümünü yükseltmeniz gerekecek.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5. Güvenli görsel işleme önerileri</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>from PIL import Image

IZINLI = ["JPEG", "PNG", "WEBP"]

def guvenli_ac(yol):
    im = Image.open(yol, formats=IZINLI)
    im.verify()
    im = Image.open(yol, formats=IZINLI)
    return im</code></div></div><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">formats</span> parametresiyle kabul ettiğiniz formatları sınırlayın.<br />
</li>
<li>Ghostscript'e ihtiyacınız yoksa görsel işleyen sunucudan kaldırın.<br />
</li>
<li>Görsel işlemeyi yetkisi düşük bir işçi süreçte veya konteynerde yapın.<br />
</li>
</ul>
<br />
Projelerinizde kullanıcı yüklemelerini nasıl işliyorsunuz? Format kısıtlaması kullanan var mı?<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Yasal uyarı</span></span><br />
Bu yazı bilgilendirme ve savunma amaçlıdır. Anlatılan kontrolleri yalnızca kendi sistemlerinizde veya yazılı izinle yapın. İzinsiz erişim, tarama ve sömürü girişimleri TCK 243-245 kapsamında suçtur. TurkTeam white-hat bir topluluktur; çalıntı veri, hesap, combo/log paylaşımı ve hack hizmeti talepleri forum kurallarına aykırıdır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://thehackernews.com/2026/10/critical-flaw-in-pythons-popular-pillow.html" target="_blank" rel="noopener" class="mycode_url">https://thehackernews.com/2026/10/critic...illow.html</a><br />
</li>
<li><a href="https://pypi.org/project/Pillow/" target="_blank" rel="noopener" class="mycode_url">https://pypi.org/project/Pillow/</a><br />
</li>
</ul>
<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=392" target="_blank" title="">03-t03-pillow-cve-2026-112900.png</a> (Dosya Boyutu: 122.06 KB / İndirme Sayısı: 4)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=392" loading="lazy"  alt="[Resim: attachment.php?aid=392]" class="mycode_img" /></div>
<br />
Selamlar,<br />
<br />
Python dünyasının en yaygın görsel işleme kütüphanesi <span style="font-weight: bold;" class="mycode_b">Pillow</span> için önemli bir güvenlik güncellemesi var. The Hacker News'in 23 Ekim 2026 tarihli haberine göre <span style="font-weight: bold;" class="mycode_b">CVE-2026-112900</span>, EPS dosyalarının Ghostscript'e aktarılması sırasında dosya adının kontrolsüz iletilmesinden kaynaklanıyor. Kullanıcıdan görsel alan bir web uygulaması yazıyorsanız okumanızı öneririm.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Konuda anlatılacaklar</span></span><br />
<ol type="1" class="mycode_list"><li>Açığın özeti<br />
</li>
<li>Kimler risk altında?<br />
</li>
<li>Aynı sürümde kapanan diğer açıklar<br />
</li>
<li>Güncelleme ve Python 3.10 notu<br />
</li>
<li>Güvenli görsel işleme için kod önerileri<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">1. Açığın özeti</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>CVE           : CVE-2026-112900
Etkilenen     : Pillow 2.6.0 - 12.3.0
Duzeltme      : Pillow 13.0.0 (16 Ekim 2026)
Kosul         : Sistemde Ghostscript (gs) kurulu olmasi
Puan          : GitHub CNA 9.2; bakimcilar "orta" olarak degerlendiriyor</code></div></div>Pillow, EPS formatını kendi başına işleyemez; bu iş için sistemdeki Ghostscript'i çağırır. Sorun, bu çağrı sırasında dosya adının yeterince denetlenmemesi. Ghostscript kurulu değilse risk büyük ölçüde ortadan kalkıyor.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">2. Kimler risk altında?</span></span><ul class="mycode_list"><li>Kullanıcı yüklemelerini Image.open() ile açan ve sunucusunda gs kurulu olan uygulamalar.<br />
</li>
<li>ImageMagick veya PDF araçları nedeniyle Ghostscript'in zaten yüklü olduğu konteyner imajları.<br />
</li>
<li>Dosya uzantısına güvenen, içeriği doğrulamayan yükleme formları.<br />
</li>
</ul>
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>which gs &amp;&amp; gs --version
python3 -c "import PIL; print(PIL.__version__)"</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">3. Aynı sürümde kapanan diğer açıklar</span></span><br />
Pillow 13.0.0 iki açığı daha kapatıyor: JPEG küçük resim işlemesinde bir taşma olan <span style="font-weight: bold;" class="mycode_b">CVE-2026-112403</span> (Anthropic'in Claude modeliyle bulunup Ada Logics tarafından doğrulandı) ve 2013'ten beri kodda olan, TIFF'in belleğe yazılmasıyla ilgili <span style="font-weight: bold;" class="mycode_b">CVE-2026-112393</span>.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">4. Güncelleme</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>pip install -U "Pillow&gt;=13.0.0"
pip-audit</code></div></div>Dikkat: Pillow 13, <span style="font-weight: bold;" class="mycode_b">Python 3.10 desteğini bıraktı</span>. Hâlâ 3.10 kullanan projelerde önce Python sürümünü yükseltmeniz gerekecek.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5. Güvenli görsel işleme önerileri</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>from PIL import Image

IZINLI = ["JPEG", "PNG", "WEBP"]

def guvenli_ac(yol):
    im = Image.open(yol, formats=IZINLI)
    im.verify()
    im = Image.open(yol, formats=IZINLI)
    return im</code></div></div><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">formats</span> parametresiyle kabul ettiğiniz formatları sınırlayın.<br />
</li>
<li>Ghostscript'e ihtiyacınız yoksa görsel işleyen sunucudan kaldırın.<br />
</li>
<li>Görsel işlemeyi yetkisi düşük bir işçi süreçte veya konteynerde yapın.<br />
</li>
</ul>
<br />
Projelerinizde kullanıcı yüklemelerini nasıl işliyorsunuz? Format kısıtlaması kullanan var mı?<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Yasal uyarı</span></span><br />
Bu yazı bilgilendirme ve savunma amaçlıdır. Anlatılan kontrolleri yalnızca kendi sistemlerinizde veya yazılı izinle yapın. İzinsiz erişim, tarama ve sömürü girişimleri TCK 243-245 kapsamında suçtur. TurkTeam white-hat bir topluluktur; çalıntı veri, hesap, combo/log paylaşımı ve hack hizmeti talepleri forum kurallarına aykırıdır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://thehackernews.com/2026/10/critical-flaw-in-pythons-popular-pillow.html" target="_blank" rel="noopener" class="mycode_url">https://thehackernews.com/2026/10/critic...illow.html</a><br />
</li>
<li><a href="https://pypi.org/project/Pillow/" target="_blank" rel="noopener" class="mycode_url">https://pypi.org/project/Pillow/</a><br />
</li>
</ul>
<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=392" target="_blank" title="">03-t03-pillow-cve-2026-112900.png</a> (Dosya Boyutu: 122.06 KB / İndirme Sayısı: 4)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Python site-packages Tuzağı: .pth import Satırları ve sitecustomize]]></title>
			<link>https://www.turkteam.org/konu-python-site-packages-tuzagi-pth-import-satirlari-ve-sitecustomize.html</link>
			<pubDate>Thu, 22 Oct 2026 11:27:39 +0300</pubDate>
			<dc:creator><![CDATA[<a href="https://www.turkteam.org/member.php?action=profile&uid=3">BilgeKagan</a>]]></dc:creator>
			<guid isPermaLink="false">https://www.turkteam.org/konu-python-site-packages-tuzagi-pth-import-satirlari-ve-sitecustomize.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=350" loading="lazy"  alt="[Resim: attachment.php?aid=350]" class="mycode_img" /></div>
<br />
Selamlar,<br />
<br />
LiteLLM 1.107.0'ın zararlısı neden "litellm import etmeden" çalıştı? Cevap Python'un site başlangıç mekanizmasında. Bu yazıda resmi site modülü belgelerine dayanarak .pth dosyaları, sitecustomize ve yeni .start dosyalarının nasıl çalıştığını, neden tedarik zinciri saldırılarında bu kadar sevildiğini anlatıyorum.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Konuda anlatılacaklar</span></span><br />
<ol type="1" class="mycode_list"><li>site modülü ne zaman yüklenir?<br />
</li>
<li>.pth dosyalarında "import" satırları<br />
</li>
<li>sitecustomize ve usercustomize<br />
</li>
<li>Python 3.15+ .start dosyaları<br />
</li>
<li>Savunma: kendi ortamınızda nasıl tararsınız?<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">site modülü ne zaman yüklenir?</span></span><br />
Python belgelerine göre site modülü yorumlayıcı başlatılırken otomatik içe aktarılır. -S seçeneğiyle bu otomatik içe aktarma bastırılabilir. Modül, sys.prefix / sys.exec_prefix altındaki site-packages dizinlerini sys.path'e ekler ve o dizinlerdeki yapılandırma dosyalarını işler.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">.pth dosyaları</span></span><br />
name.pth dosyaları site-packages içinde bulunur. Her satır normalde sys.path'e eklenecek bir yoldur. Ama geriye dönük uyumluluk için <span style="font-weight: bold;" class="mycode_b">"import" ile başlayan satırlar exec() ile çalıştırılır</span>. LiteLLM olayındaki cook.pth dosyası yalnızca şunu içeriyordu: <span style="font-weight: bold;" class="mycode_b">import cook</span>. Yani her Python başlangıcında cook.py çalışıyordu.<br />
<br />
Belgeler ayrıca diyor ki: yürütülebilir satırlar (pth içindeki import satırları ve .start giriş noktaları), belirli bir modülün gerçekten kullanılıp kullanılmayacağından bağımsız olarak başlangıçta her zaman çalışır; -S verilmedikçe.<br />
<br />
Python 3.15'te pth içindeki import satırları kullanımdan kaldırıldı (deprecated); 3.20'de kaldırılacak. Yerine .start dosyaları geliyor.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">sitecustomize</span></span><br />
Yol manipülasyonlarından sonra site modülü <span style="font-weight: bold;" class="mycode_b">sitecustomize</span> adlı bir modülü içe aktarmaya çalışır. Bu dosya tipik olarak sistem yöneticisi tarafından site-packages'e konur ve keyfi özelleştirme yapabilir. ImportError (name='sitecustomize') sessizce yok sayılır. LiteLLM olayında saldırgan sitecustomize.py'yi wheel'in .data/purelib/ dizinine koyarak pip'in onu site-packages köküne kopyalamasını sağladı; böylece her başlangıçta arka plan yükleyici ayağa kalkıyordu.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Lab: zararsız bir gösterim</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># Yalnızca kendi venv'inizde deneyin
python3 -m venv /tmp/sitedemo &amp;&amp; source /tmp/sitedemo/bin/activate
SP=&#36;(python -c "import site; print(site.getsitepackages()[0])")
# Zararsız bir isaretleyici
cat &gt; "&#36;SP/demo_hook.py" &lt;&lt;'E'
print("[demo_hook] calisti - bu satiri uretimde GORMEK istemezsiniz")
E
echo "import demo_hook" &gt; "&#36;SP/demo_hook.pth"
python -c "print('merhaba')"
# Temizlik
rm -f "&#36;SP/demo_hook.py" "&#36;SP/demo_hook.pth"</code></div></div>python -c "print('merhaba')" satırı demo_hook'u hiç import etmez; yine de pth yüzünden çalışır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Savunma taraması</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># Tum site-packages icinde supheli pth / sitecustomize
python - &lt;&lt;'PY'
import site, pathlib
paths = list(site.getsitepackages())
if site.ENABLE_USER_SITE and site.USER_SITE:
    paths.append(site.USER_SITE)
for p in paths:
    root = pathlib.Path(p)
    if not root.is_dir():
        continue
    for f in root.glob("*.pth"):
        text = f.read_text(errors="replace")
        if any(ln.lstrip().startswith("import ") for ln in text.splitlines()):
            print("PTH_IMPORT", f)
    for name in ("sitecustomize.py", "usercustomize.py"):
        t = root / name
        if t.exists():
            print("CUSTOMIZE", t)
PY</code></div></div>CI imajlarınızda ve üretim venv'lerinizde bu taramayı düzenli çalıştırın. pip uninstall litellm demek ekstra dosyaları temizlemez; LiteLLM'in de vurguladığı gibi cook.pth ve sitecustomize.py elle silinmelidir.<br />
<br />
Üretim imajlarınızda pth/sitecustomize taraması var mı? Script'inizi paylaşırsanız herkes faydalanır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Yasal uyarı</span></span><br />
Bu yazı bilgilendirme ve savunma amaçlıdır. Anlatılan kontrolleri yalnızca kendi sistemlerinizde veya yazılı izinle yapın. İzinsiz erişim, tarama ve sömürü girişimleri TCK 243-245 kapsamında suçtur. TurkTeam white-hat bir topluluktur; çalıntı veri, hesap, combo/log paylaşımı ve hack hizmeti talepleri forum kurallarına aykırıdır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://docs.python.org/3/library/site.html" target="_blank" rel="noopener" class="mycode_url">https://docs.python.org/3/library/site.html</a><br />
</li>
<li><a href="https://osv.dev/vulnerability/MAL-2026-2144" target="_blank" rel="noopener" class="mycode_url">https://osv.dev/vulnerability/MAL-2026-2144</a><br />
</li>
<li><a href="https://aisle.com/blog/litellm-11070-on-pypi-shipped-a-credential-stealer" target="_blank" rel="noopener" class="mycode_url">https://aisle.com/blog/litellm-11070-on-...al-stealer</a><br />
</li>
</ul>
<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=350" target="_blank" title="">12-b02-sitecustomize-pth.png</a> (Dosya Boyutu: 112.66 KB / İndirme Sayısı: 6)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=350" loading="lazy"  alt="[Resim: attachment.php?aid=350]" class="mycode_img" /></div>
<br />
Selamlar,<br />
<br />
LiteLLM 1.107.0'ın zararlısı neden "litellm import etmeden" çalıştı? Cevap Python'un site başlangıç mekanizmasında. Bu yazıda resmi site modülü belgelerine dayanarak .pth dosyaları, sitecustomize ve yeni .start dosyalarının nasıl çalıştığını, neden tedarik zinciri saldırılarında bu kadar sevildiğini anlatıyorum.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Konuda anlatılacaklar</span></span><br />
<ol type="1" class="mycode_list"><li>site modülü ne zaman yüklenir?<br />
</li>
<li>.pth dosyalarında "import" satırları<br />
</li>
<li>sitecustomize ve usercustomize<br />
</li>
<li>Python 3.15+ .start dosyaları<br />
</li>
<li>Savunma: kendi ortamınızda nasıl tararsınız?<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">site modülü ne zaman yüklenir?</span></span><br />
Python belgelerine göre site modülü yorumlayıcı başlatılırken otomatik içe aktarılır. -S seçeneğiyle bu otomatik içe aktarma bastırılabilir. Modül, sys.prefix / sys.exec_prefix altındaki site-packages dizinlerini sys.path'e ekler ve o dizinlerdeki yapılandırma dosyalarını işler.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">.pth dosyaları</span></span><br />
name.pth dosyaları site-packages içinde bulunur. Her satır normalde sys.path'e eklenecek bir yoldur. Ama geriye dönük uyumluluk için <span style="font-weight: bold;" class="mycode_b">"import" ile başlayan satırlar exec() ile çalıştırılır</span>. LiteLLM olayındaki cook.pth dosyası yalnızca şunu içeriyordu: <span style="font-weight: bold;" class="mycode_b">import cook</span>. Yani her Python başlangıcında cook.py çalışıyordu.<br />
<br />
Belgeler ayrıca diyor ki: yürütülebilir satırlar (pth içindeki import satırları ve .start giriş noktaları), belirli bir modülün gerçekten kullanılıp kullanılmayacağından bağımsız olarak başlangıçta her zaman çalışır; -S verilmedikçe.<br />
<br />
Python 3.15'te pth içindeki import satırları kullanımdan kaldırıldı (deprecated); 3.20'de kaldırılacak. Yerine .start dosyaları geliyor.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">sitecustomize</span></span><br />
Yol manipülasyonlarından sonra site modülü <span style="font-weight: bold;" class="mycode_b">sitecustomize</span> adlı bir modülü içe aktarmaya çalışır. Bu dosya tipik olarak sistem yöneticisi tarafından site-packages'e konur ve keyfi özelleştirme yapabilir. ImportError (name='sitecustomize') sessizce yok sayılır. LiteLLM olayında saldırgan sitecustomize.py'yi wheel'in .data/purelib/ dizinine koyarak pip'in onu site-packages köküne kopyalamasını sağladı; böylece her başlangıçta arka plan yükleyici ayağa kalkıyordu.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Lab: zararsız bir gösterim</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># Yalnızca kendi venv'inizde deneyin
python3 -m venv /tmp/sitedemo &amp;&amp; source /tmp/sitedemo/bin/activate
SP=&#36;(python -c "import site; print(site.getsitepackages()[0])")
# Zararsız bir isaretleyici
cat &gt; "&#36;SP/demo_hook.py" &lt;&lt;'E'
print("[demo_hook] calisti - bu satiri uretimde GORMEK istemezsiniz")
E
echo "import demo_hook" &gt; "&#36;SP/demo_hook.pth"
python -c "print('merhaba')"
# Temizlik
rm -f "&#36;SP/demo_hook.py" "&#36;SP/demo_hook.pth"</code></div></div>python -c "print('merhaba')" satırı demo_hook'u hiç import etmez; yine de pth yüzünden çalışır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Savunma taraması</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># Tum site-packages icinde supheli pth / sitecustomize
python - &lt;&lt;'PY'
import site, pathlib
paths = list(site.getsitepackages())
if site.ENABLE_USER_SITE and site.USER_SITE:
    paths.append(site.USER_SITE)
for p in paths:
    root = pathlib.Path(p)
    if not root.is_dir():
        continue
    for f in root.glob("*.pth"):
        text = f.read_text(errors="replace")
        if any(ln.lstrip().startswith("import ") for ln in text.splitlines()):
            print("PTH_IMPORT", f)
    for name in ("sitecustomize.py", "usercustomize.py"):
        t = root / name
        if t.exists():
            print("CUSTOMIZE", t)
PY</code></div></div>CI imajlarınızda ve üretim venv'lerinizde bu taramayı düzenli çalıştırın. pip uninstall litellm demek ekstra dosyaları temizlemez; LiteLLM'in de vurguladığı gibi cook.pth ve sitecustomize.py elle silinmelidir.<br />
<br />
Üretim imajlarınızda pth/sitecustomize taraması var mı? Script'inizi paylaşırsanız herkes faydalanır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Yasal uyarı</span></span><br />
Bu yazı bilgilendirme ve savunma amaçlıdır. Anlatılan kontrolleri yalnızca kendi sistemlerinizde veya yazılı izinle yapın. İzinsiz erişim, tarama ve sömürü girişimleri TCK 243-245 kapsamında suçtur. TurkTeam white-hat bir topluluktur; çalıntı veri, hesap, combo/log paylaşımı ve hack hizmeti talepleri forum kurallarına aykırıdır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://docs.python.org/3/library/site.html" target="_blank" rel="noopener" class="mycode_url">https://docs.python.org/3/library/site.html</a><br />
</li>
<li><a href="https://osv.dev/vulnerability/MAL-2026-2144" target="_blank" rel="noopener" class="mycode_url">https://osv.dev/vulnerability/MAL-2026-2144</a><br />
</li>
<li><a href="https://aisle.com/blog/litellm-11070-on-pypi-shipped-a-credential-stealer" target="_blank" rel="noopener" class="mycode_url">https://aisle.com/blog/litellm-11070-on-...al-stealer</a><br />
</li>
</ul>
<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=350" target="_blank" title="">12-b02-sitecustomize-pth.png</a> (Dosya Boyutu: 112.66 KB / İndirme Sayısı: 6)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Python asyncio ile Ağ I/O: Güvenlik Araçlarında open_connection Pratiği]]></title>
			<link>https://www.turkteam.org/konu-python-asyncio-ile-ag-i-o-guvenlik-araclarinda-open-connection-pratigi.html</link>
			<pubDate>Wed, 21 Oct 2026 11:30:33 +0300</pubDate>
			<dc:creator><![CDATA[<a href="https://www.turkteam.org/member.php?action=profile&uid=4">KulTigin</a>]]></dc:creator>
			<guid isPermaLink="false">https://www.turkteam.org/konu-python-asyncio-ile-ag-i-o-guvenlik-araclarinda-open-connection-pratigi.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=333" loading="lazy"  alt="[Resim: attachment.php?aid=333]" class="mycode_img" /></div>
<br />
Selam,<br />
<br />
Thread bombası yerine asyncio, binlerce yavaş I/O bekleyen bağlantıyı tek iş parçacığında yönetmenizi sağlar. Banner grab, health-check, kendi lab port tarayıcınız... Resmi dokümandaki asyncio.open_connection ile küçük bir örnek yazalım.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Minimal banner okuma</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>import asyncio

async def grab(host: str, port: int, timeout: float = 3.0) -&gt; str:
    try:
        reader, writer = await asyncio.wait_for(
            asyncio.open_connection(host, port), timeout=timeout
        )
        data = await asyncio.wait_for(reader.read(256), timeout=timeout)
        writer.close()
        await writer.wait_closed()
        return data.decode("latin-1", errors="replace")
    except Exception as e:
        return f"ERR: {e!r}"

async def main():
    hosts = [("127.0.0.1", 22), ("127.0.0.1", 80)]
    results = await asyncio.gather(*(grab(h, p) for h, p in hosts))
    for (h, p), r in zip(hosts, results):
        print(f"{h}:{p} -&gt; {r[:120]!r}")

asyncio.run(main())</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Dikkat edilecekler</span></span><ul class="mycode_list"><li>Timeout'suz gather lab'ı kilitleyebilir; wait_for kullanın<br />
</li>
<li>Semaphore ile eşzamanlılık sınırı koyun (ör. 100)<br />
</li>
<li>TLS için open_connection(..., ssl=True) veya kendi SSLContext<br />
</li>
<li>Bu bir silahlaştırılmış tarayıcı değil; yalnızca kendi host'larınız<br />
</li>
</ul>
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>sem = asyncio.Semaphore(50)
async def bounded(h, p):
    async with sem:
        return await grab(h, p)</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Güvenlik aracı disiplini</span></span><br />
Kütüphane seçimi kadar kullanıcı arayüzü önemli: varsayılan hedef localhost, scope dosyası zorunlu, User-Agent/etiket logu. asyncio + rate limit ikilisi "hızlı ama nezaketli" araçların omurgası.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Yasal uyarı</span></span><br />
İzinsiz port/banner tarama suç olabilir. TCK 243-245.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://docs.python.org/3/library/asyncio-stream.html" target="_blank" rel="noopener" class="mycode_url">https://docs.python.org/3/library/asyncio-stream.html</a><br />
</li>
<li><a href="https://docs.python.org/3/library/asyncio-task.html" target="_blank" rel="noopener" class="mycode_url">https://docs.python.org/3/library/asyncio-task.html</a><br />
</li>
</ul>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Test</span></span><br />
pytest-asyncio ile timeout ve semaphore sınırlarını birim test edin. Labda kasıtlı olarak kapalı porta istek atıp ERR yolunu doğrulayın. Loglara hedef IP yazarken KVKK/minimization uygulayın.<br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Uygulamada sık gördüğüm hatalar</span></span><br />
Birçok ekip yamayı "planlandı" diye işaretleyip internete açık yüzeyde günlerce bekletiyor. İkinci sık hata: yalnızca CVE numarasına bakıp zincir etkisini görmemek. Üçüncü hata: yama sonrası log ve dosya bütünlüğüne bakmamak; oysa yama öncesi sömürü olmuş olabilir. Bu üç noktayı kendi kontrol listenize eklemenizi öneririm.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Ekip içi iletişim şablonu</span></span><br />
Yönetime veya müşteriye yazarken teknik jargonu azaltın: hangi varlık etkilendi, internete açık mı, yama var mı, geçici azaltma ne, doğrulama nasıl yapılacak. Tek paragrafta risk + eylem + sahiplik yazmak, uzun CVE özetinden daha hızlı karar aldırır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Lab not defteri</span></span><br />
Bu konuyu kendi defterime şu başlıklarla işliyorum: tarih, kaynak URL, etkilenen ürün/sürüm, internete açık mı, yama komutu, geri alma planı, IOC listesi, kime haber verildi. Siz de benzer basit bir şablon tutarsanız bir ay sonra "ne yapmıştık?" sorusu cevapsız kalmaz.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">İzleme ve doğrulama</span></span><br />
Değişiklikten sonra en az bir negatif ve bir pozitif kontrol tanımlayın. Negatif: alarm boş yere düşmemeli. Pozitif: bilinen kötü örneği veya beklenen log satırını yakalamalı. İkisini de kaydedin; aksi halde "sanırım düzeldi" ile yetinirsiniz.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sonuç</span></span><br />
Özetle: kaynağı okuyun, kendi envanterinize bağlayın, yama veya azaltmayı uygulayın, sonra doğrulayın. TurkTeam'de yorumlarda kendi ortamınızdan (ürün adı ve sürüm yeter, hassas IP yazmayın) kısa deneyim paylaşırsanız herkes faydalanır.<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Adım adım kontrol listesi (kopyala-yapıştır)</span></span><br />
<ol type="1" class="mycode_list"><li>Kaynak duyuruyu ve varsa üretici güvenlik sayfasını arşivleyin (PDF/HTML).<br />
</li>
<li>Envanterde etkilenen ürün var mı diye CMDB / agent raporu / netscan ile bakın.<br />
</li>
<li>İnternete açık mı, yoksa yalnızca iç ağda mı? Buna göre SLA seçin.<br />
</li>
<li>Yama veya yapılandırma azaltmasını stagingde deneyin.<br />
</li>
<li>Üretim penceresinde uygulayın; değişiklik kaydı açın.<br />
</li>
<li>Servis sağlık kontrolü + log doğrulaması yapın.<br />
</li>
<li>Gerekliyse IOC avı veya compromise assessment planlayın.<br />
</li>
<li>Kapanış notunu yazın: sürüm, tarih, kim onayladı.<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sık sorulanlar</span></span><br />
<span style="font-weight: bold;" class="mycode_b">Sadece okumak yeter mi?</span> Hayır. Okuduktan sonra envanter satırına bağlanmayan bilgi operasyonel değildir.<br />
<span style="font-weight: bold;" class="mycode_b">PoC çalıştırmalı mıyım?</span> Yalnızca izole lab ve yazılı izinle. İnternette rastgele deneme hem etik dışı hem yasadışı olabilir.<br />
<span style="font-weight: bold;" class="mycode_b">WAF / EDR tek başına kurtarır mı?</span> Katmanlı savunma işe yarar ama yamanın yerini tutmaz; özellikle kimlik doğrulamasız RCE sınıflarında.<br />
<span style="font-weight: bold;" class="mycode_b">Ne zaman yönetime çıkmalıyım?</span> İnternete açık kritik yüzey, aktif sömürü istihbaratı veya veri sızıntısı şüphesi varsa gecikmeden.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Örnek komut defteri</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># Tarih damgası ve ortam notu
date -Is
hostnamectl 2&gt;/dev/null | head -5 || true
# Ağ dinleme özeti (lab)
ss -lntp | head -30
# Son reboot / güncelleme ipucu (systemd)
who -b 2&gt;/dev/null || true</code></div></div>Bu komutlar tanı koymaz; değişiklik öncesi/sonrası basline almak için kullanın.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">İlgili TurkTeam bölümleri</span></span><br />
Bu yazıyı okuduktan sonra aynı kategorideki komşu konulara ve Soru-Cevap bölümüne kendi lab çıktınızı (hassas veri olmadan) taşıyabilirsiniz. Kısa ekran görüntüsü veya komut çıktısı, uzun teoriden daha çok işe yarar.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kapanış ve yasal çerçeve</span></span><br />
TurkTeam white-hat bir topluluktur. Anlatılan teknikler eğitim, savunma ve izinli test içindir. Başkalarının sistemlerinde izinsiz tarama, sömürü, veri çalma veya "hack hizmeti" sunmak forum kurallarına ve TCK 243, 244, 245 maddelerine aykırıdır. Kendi laboratuvarınızı izolasyonla kurun; üretim verisi kullanmayın. Kaynaklardaki bağlantıları birincil referans kabul edin; bu yazı özet ve yol göstericidir, üretici duyurusunun yerini tutmaz.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kişisel deneyim notu</span></span><br />
Ben benzer konuları işlerken önce resmi duyuruyu iki kez okuyup sonra labda en küçük yeniden üretilebilir adımı arıyorum. Yeniden üretemiyorsam bile envanter ve yama doğrulamasını aynı gün bitirmeye çalışıyorum. Siz de "bugün tek iş" diye bir satır seçin: ya yamayı uygulayın ya da etkilenen varlık olmadığını kanıtlayın. İkisi de geçerli kapanıştır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Okuma listesi</span></span><ul class="mycode_list"><li>Üretici / araştırmacı birincil yazısı (kaynakçada)<br />
</li>
<li>CISA KEV veya CERT duyurusu varsa o<br />
</li>
<li>Kendi iç runbook'unuzun ilgili maddesi<br />
</li>
</ul>
Üçünden fazlasını aynı anda açmak yerine birini bitirip not alın; aksi halde tab kaybı başlar.<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=333" target="_blank" title="">16-k01-asyncio.png</a> (Dosya Boyutu: 113.88 KB / İndirme Sayısı: 7)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=333" loading="lazy"  alt="[Resim: attachment.php?aid=333]" class="mycode_img" /></div>
<br />
Selam,<br />
<br />
Thread bombası yerine asyncio, binlerce yavaş I/O bekleyen bağlantıyı tek iş parçacığında yönetmenizi sağlar. Banner grab, health-check, kendi lab port tarayıcınız... Resmi dokümandaki asyncio.open_connection ile küçük bir örnek yazalım.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Minimal banner okuma</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>import asyncio

async def grab(host: str, port: int, timeout: float = 3.0) -&gt; str:
    try:
        reader, writer = await asyncio.wait_for(
            asyncio.open_connection(host, port), timeout=timeout
        )
        data = await asyncio.wait_for(reader.read(256), timeout=timeout)
        writer.close()
        await writer.wait_closed()
        return data.decode("latin-1", errors="replace")
    except Exception as e:
        return f"ERR: {e!r}"

async def main():
    hosts = [("127.0.0.1", 22), ("127.0.0.1", 80)]
    results = await asyncio.gather(*(grab(h, p) for h, p in hosts))
    for (h, p), r in zip(hosts, results):
        print(f"{h}:{p} -&gt; {r[:120]!r}")

asyncio.run(main())</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Dikkat edilecekler</span></span><ul class="mycode_list"><li>Timeout'suz gather lab'ı kilitleyebilir; wait_for kullanın<br />
</li>
<li>Semaphore ile eşzamanlılık sınırı koyun (ör. 100)<br />
</li>
<li>TLS için open_connection(..., ssl=True) veya kendi SSLContext<br />
</li>
<li>Bu bir silahlaştırılmış tarayıcı değil; yalnızca kendi host'larınız<br />
</li>
</ul>
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>sem = asyncio.Semaphore(50)
async def bounded(h, p):
    async with sem:
        return await grab(h, p)</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Güvenlik aracı disiplini</span></span><br />
Kütüphane seçimi kadar kullanıcı arayüzü önemli: varsayılan hedef localhost, scope dosyası zorunlu, User-Agent/etiket logu. asyncio + rate limit ikilisi "hızlı ama nezaketli" araçların omurgası.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Yasal uyarı</span></span><br />
İzinsiz port/banner tarama suç olabilir. TCK 243-245.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://docs.python.org/3/library/asyncio-stream.html" target="_blank" rel="noopener" class="mycode_url">https://docs.python.org/3/library/asyncio-stream.html</a><br />
</li>
<li><a href="https://docs.python.org/3/library/asyncio-task.html" target="_blank" rel="noopener" class="mycode_url">https://docs.python.org/3/library/asyncio-task.html</a><br />
</li>
</ul>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Test</span></span><br />
pytest-asyncio ile timeout ve semaphore sınırlarını birim test edin. Labda kasıtlı olarak kapalı porta istek atıp ERR yolunu doğrulayın. Loglara hedef IP yazarken KVKK/minimization uygulayın.<br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Uygulamada sık gördüğüm hatalar</span></span><br />
Birçok ekip yamayı "planlandı" diye işaretleyip internete açık yüzeyde günlerce bekletiyor. İkinci sık hata: yalnızca CVE numarasına bakıp zincir etkisini görmemek. Üçüncü hata: yama sonrası log ve dosya bütünlüğüne bakmamak; oysa yama öncesi sömürü olmuş olabilir. Bu üç noktayı kendi kontrol listenize eklemenizi öneririm.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Ekip içi iletişim şablonu</span></span><br />
Yönetime veya müşteriye yazarken teknik jargonu azaltın: hangi varlık etkilendi, internete açık mı, yama var mı, geçici azaltma ne, doğrulama nasıl yapılacak. Tek paragrafta risk + eylem + sahiplik yazmak, uzun CVE özetinden daha hızlı karar aldırır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Lab not defteri</span></span><br />
Bu konuyu kendi defterime şu başlıklarla işliyorum: tarih, kaynak URL, etkilenen ürün/sürüm, internete açık mı, yama komutu, geri alma planı, IOC listesi, kime haber verildi. Siz de benzer basit bir şablon tutarsanız bir ay sonra "ne yapmıştık?" sorusu cevapsız kalmaz.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">İzleme ve doğrulama</span></span><br />
Değişiklikten sonra en az bir negatif ve bir pozitif kontrol tanımlayın. Negatif: alarm boş yere düşmemeli. Pozitif: bilinen kötü örneği veya beklenen log satırını yakalamalı. İkisini de kaydedin; aksi halde "sanırım düzeldi" ile yetinirsiniz.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sonuç</span></span><br />
Özetle: kaynağı okuyun, kendi envanterinize bağlayın, yama veya azaltmayı uygulayın, sonra doğrulayın. TurkTeam'de yorumlarda kendi ortamınızdan (ürün adı ve sürüm yeter, hassas IP yazmayın) kısa deneyim paylaşırsanız herkes faydalanır.<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Adım adım kontrol listesi (kopyala-yapıştır)</span></span><br />
<ol type="1" class="mycode_list"><li>Kaynak duyuruyu ve varsa üretici güvenlik sayfasını arşivleyin (PDF/HTML).<br />
</li>
<li>Envanterde etkilenen ürün var mı diye CMDB / agent raporu / netscan ile bakın.<br />
</li>
<li>İnternete açık mı, yoksa yalnızca iç ağda mı? Buna göre SLA seçin.<br />
</li>
<li>Yama veya yapılandırma azaltmasını stagingde deneyin.<br />
</li>
<li>Üretim penceresinde uygulayın; değişiklik kaydı açın.<br />
</li>
<li>Servis sağlık kontrolü + log doğrulaması yapın.<br />
</li>
<li>Gerekliyse IOC avı veya compromise assessment planlayın.<br />
</li>
<li>Kapanış notunu yazın: sürüm, tarih, kim onayladı.<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sık sorulanlar</span></span><br />
<span style="font-weight: bold;" class="mycode_b">Sadece okumak yeter mi?</span> Hayır. Okuduktan sonra envanter satırına bağlanmayan bilgi operasyonel değildir.<br />
<span style="font-weight: bold;" class="mycode_b">PoC çalıştırmalı mıyım?</span> Yalnızca izole lab ve yazılı izinle. İnternette rastgele deneme hem etik dışı hem yasadışı olabilir.<br />
<span style="font-weight: bold;" class="mycode_b">WAF / EDR tek başına kurtarır mı?</span> Katmanlı savunma işe yarar ama yamanın yerini tutmaz; özellikle kimlik doğrulamasız RCE sınıflarında.<br />
<span style="font-weight: bold;" class="mycode_b">Ne zaman yönetime çıkmalıyım?</span> İnternete açık kritik yüzey, aktif sömürü istihbaratı veya veri sızıntısı şüphesi varsa gecikmeden.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Örnek komut defteri</span></span><br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># Tarih damgası ve ortam notu
date -Is
hostnamectl 2&gt;/dev/null | head -5 || true
# Ağ dinleme özeti (lab)
ss -lntp | head -30
# Son reboot / güncelleme ipucu (systemd)
who -b 2&gt;/dev/null || true</code></div></div>Bu komutlar tanı koymaz; değişiklik öncesi/sonrası basline almak için kullanın.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">İlgili TurkTeam bölümleri</span></span><br />
Bu yazıyı okuduktan sonra aynı kategorideki komşu konulara ve Soru-Cevap bölümüne kendi lab çıktınızı (hassas veri olmadan) taşıyabilirsiniz. Kısa ekran görüntüsü veya komut çıktısı, uzun teoriden daha çok işe yarar.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kapanış ve yasal çerçeve</span></span><br />
TurkTeam white-hat bir topluluktur. Anlatılan teknikler eğitim, savunma ve izinli test içindir. Başkalarının sistemlerinde izinsiz tarama, sömürü, veri çalma veya "hack hizmeti" sunmak forum kurallarına ve TCK 243, 244, 245 maddelerine aykırıdır. Kendi laboratuvarınızı izolasyonla kurun; üretim verisi kullanmayın. Kaynaklardaki bağlantıları birincil referans kabul edin; bu yazı özet ve yol göstericidir, üretici duyurusunun yerini tutmaz.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kişisel deneyim notu</span></span><br />
Ben benzer konuları işlerken önce resmi duyuruyu iki kez okuyup sonra labda en küçük yeniden üretilebilir adımı arıyorum. Yeniden üretemiyorsam bile envanter ve yama doğrulamasını aynı gün bitirmeye çalışıyorum. Siz de "bugün tek iş" diye bir satır seçin: ya yamayı uygulayın ya da etkilenen varlık olmadığını kanıtlayın. İkisi de geçerli kapanıştır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Okuma listesi</span></span><ul class="mycode_list"><li>Üretici / araştırmacı birincil yazısı (kaynakçada)<br />
</li>
<li>CISA KEV veya CERT duyurusu varsa o<br />
</li>
<li>Kendi iç runbook'unuzun ilgili maddesi<br />
</li>
</ul>
Üçünden fazlasını aynı anda açmak yerine birini bitirip not alın; aksi halde tab kaybı başlar.<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=333" target="_blank" title="">16-k01-asyncio.png</a> (Dosya Boyutu: 113.88 KB / İndirme Sayısı: 7)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Python ile Dosya Butunlugu Izleme: hashlib ile Basit FIM Scripti]]></title>
			<link>https://www.turkteam.org/konu-python-ile-dosya-butunlugu-izleme-hashlib-ile-basit-fim-scripti.html</link>
			<pubDate>Sat, 17 Oct 2026 11:20:25 +0300</pubDate>
			<dc:creator><![CDATA[<a href="https://www.turkteam.org/member.php?action=profile&uid=3">BilgeKagan</a>]]></dc:creator>
			<guid isPermaLink="false">https://www.turkteam.org/konu-python-ile-dosya-butunlugu-izleme-hashlib-ile-basit-fim-scripti.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=64" loading="lazy"  alt="[Resim: attachment.php?aid=64]" class="mycode_img" /></div>
<br />
Merhaba arkadaslar,<br />
<br />
Sunucularda en sik gozden kacan savunma katmanlarindan biri dosya butunlugu izlemesi (File Integrity Monitoring, FIM). Pahali bir urun almadan, standart kutuphanelerle kendi basit FIM aracinizi yazabilirsiniz. Bu konuda hashlib ile calisan, harici bagimliligi olmayan kucuk bir script uzerinden mantigi anlatacagim.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Konuda Anlatilacaklar</span></span><br />
<ol type="1" class="mycode_list"><li>FIM nedir, neden onemlidir?<br />
</li>
<li>Hangi dizinleri izlemeli?<br />
</li>
<li>Baseline (referans) olusturma<br />
</li>
<li>Degisiklik tespiti ve raporlama<br />
</li>
<li>Zamanlama (cron) ve sinirlar<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">1) FIM Nedir, Neden Onemli?</span></span><br />
FIM, kritik dosyalarin icerik ozetini (hash) belirli araliklarla hesaplayip referans degerle karsilastirir. Bir saldirgan /etc/passwd, bir web uygulamasinin index dosyasi veya bir systemd servis dosyasini degistirdiginde fark aninda ortaya cikar. Mantik basit: once temiz bir referans al, sonra duzenli olarak karsilastir. Kurumsal dunyada AIDE veya Tripwire bu isi yapar; buradaki amac mantigi ogrenmek.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">2) Baseline Olusturma</span></span><br />
Once izlenecek dizinleri tarayip her dosyanin SHA-256 ozetini bir JSON dosyasina yaziyoruz.<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>import hashlib, os, json, sys, time

def sha256(path, chunk=65536):
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for block in iter(lambda: f.read(chunk), b""):
            h.update(block)
    return h.hexdigest()

def scan(roots):
    db = {}
    for root in roots:
        for dirpath, _, files in os.walk(root):
            for name in files:
                p = os.path.join(dirpath, name)
                try:
                    db[p] = sha256(p)
                except (PermissionError, FileNotFoundError):
                    continue
    return db</code></div></div><br />
Buyuk dosyalari parca parca okudugumuza dikkat edin; boylece bellek sismaz.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">3) Degisiklik Tespiti</span></span><br />
Baseline ile guncel tarama arasindaki farki uc kumeye ayiriyoruz: eklenen, silinen ve degisen dosyalar.<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>def diff(old, new):
    old_k, new_k = set(old), set(new)
    added = new_k - old_k
    removed = old_k - new_k
    changed = {k for k in old_k &amp; new_k if old[k] != new[k]}
    return added, removed, changed

if __name__ == "__main__":
    ROOTS = ["/etc", "/var/www"]
    DB = "/var/lib/fim/baseline.json"
    if "--baseline" in sys.argv:
        os.makedirs(os.path.dirname(DB), exist_ok=True)
        json.dump(scan(ROOTS), open(DB, "w"))
        print("Baseline olusturuldu.")
    else:
        old = json.load(open(DB))
        a, r, c = diff(old, scan(ROOTS))
        for tag, s in (("EKLENDI", a), ("SILINDI", r), ("DEGISTI", c)):
            for p in sorted(s):
                print(f"[{tag}] {p}")</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">4) Zamanlama</span></span><br />
Scripti saatlik calistirmak icin basit bir cron satiri:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>0 * * * * /usr/bin/python3 /opt/fim/fim.py &gt;&gt; /var/log/fim.log 2&gt;&amp;1</code></div></div><br />
Ciktida <span style="font-weight: bold;" class="mycode_b">DEGISTI</span> satiri gorurseniz once mesru bir guncelleme mi (paket yukseltmesi, deploy) diye bakin; degilse incelemeye alin.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5) Sinirlar</span></span><br />
Bu script bir baslangic noktasidir. Gercek ortamda baseline dosyasini salt-okunur veya ayri bir yerde tutun; saldirgan hem dosyayi hem baseline'i degistirebilir. Ayrica cok degisen dizinleri (log, cache) izleme disinda birakin, yoksa gurultu olur. Uretim icin AIDE gibi olgun araclara gecmenizi oneririm.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://docs.python.org/3/library/hashlib.html" target="_blank" rel="noopener" class="mycode_url">Python hashlib dokumantasyonu</a><br />
</li>
<li><a href="https://aide.github.io/" target="_blank" rel="noopener" class="mycode_url">AIDE - Advanced Intrusion Detection Environment</a><br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>Alıntı:</cite><span style="font-weight: bold;" class="mycode_b">Yasal not:</span> Scripti yalnizca kendi sunucularinizda veya yetkili oldugunuz sistemlerde calistirin.</blockquote>
<br />
Kolay gelsin.<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=64" target="_blank" title="">bilgekagan-b01.png</a> (Dosya Boyutu: 82.93 KB / İndirme Sayısı: 7)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=64" loading="lazy"  alt="[Resim: attachment.php?aid=64]" class="mycode_img" /></div>
<br />
Merhaba arkadaslar,<br />
<br />
Sunucularda en sik gozden kacan savunma katmanlarindan biri dosya butunlugu izlemesi (File Integrity Monitoring, FIM). Pahali bir urun almadan, standart kutuphanelerle kendi basit FIM aracinizi yazabilirsiniz. Bu konuda hashlib ile calisan, harici bagimliligi olmayan kucuk bir script uzerinden mantigi anlatacagim.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Konuda Anlatilacaklar</span></span><br />
<ol type="1" class="mycode_list"><li>FIM nedir, neden onemlidir?<br />
</li>
<li>Hangi dizinleri izlemeli?<br />
</li>
<li>Baseline (referans) olusturma<br />
</li>
<li>Degisiklik tespiti ve raporlama<br />
</li>
<li>Zamanlama (cron) ve sinirlar<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">1) FIM Nedir, Neden Onemli?</span></span><br />
FIM, kritik dosyalarin icerik ozetini (hash) belirli araliklarla hesaplayip referans degerle karsilastirir. Bir saldirgan /etc/passwd, bir web uygulamasinin index dosyasi veya bir systemd servis dosyasini degistirdiginde fark aninda ortaya cikar. Mantik basit: once temiz bir referans al, sonra duzenli olarak karsilastir. Kurumsal dunyada AIDE veya Tripwire bu isi yapar; buradaki amac mantigi ogrenmek.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">2) Baseline Olusturma</span></span><br />
Once izlenecek dizinleri tarayip her dosyanin SHA-256 ozetini bir JSON dosyasina yaziyoruz.<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>import hashlib, os, json, sys, time

def sha256(path, chunk=65536):
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for block in iter(lambda: f.read(chunk), b""):
            h.update(block)
    return h.hexdigest()

def scan(roots):
    db = {}
    for root in roots:
        for dirpath, _, files in os.walk(root):
            for name in files:
                p = os.path.join(dirpath, name)
                try:
                    db[p] = sha256(p)
                except (PermissionError, FileNotFoundError):
                    continue
    return db</code></div></div><br />
Buyuk dosyalari parca parca okudugumuza dikkat edin; boylece bellek sismaz.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">3) Degisiklik Tespiti</span></span><br />
Baseline ile guncel tarama arasindaki farki uc kumeye ayiriyoruz: eklenen, silinen ve degisen dosyalar.<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>def diff(old, new):
    old_k, new_k = set(old), set(new)
    added = new_k - old_k
    removed = old_k - new_k
    changed = {k for k in old_k &amp; new_k if old[k] != new[k]}
    return added, removed, changed

if __name__ == "__main__":
    ROOTS = ["/etc", "/var/www"]
    DB = "/var/lib/fim/baseline.json"
    if "--baseline" in sys.argv:
        os.makedirs(os.path.dirname(DB), exist_ok=True)
        json.dump(scan(ROOTS), open(DB, "w"))
        print("Baseline olusturuldu.")
    else:
        old = json.load(open(DB))
        a, r, c = diff(old, scan(ROOTS))
        for tag, s in (("EKLENDI", a), ("SILINDI", r), ("DEGISTI", c)):
            for p in sorted(s):
                print(f"[{tag}] {p}")</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">4) Zamanlama</span></span><br />
Scripti saatlik calistirmak icin basit bir cron satiri:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>0 * * * * /usr/bin/python3 /opt/fim/fim.py &gt;&gt; /var/log/fim.log 2&gt;&amp;1</code></div></div><br />
Ciktida <span style="font-weight: bold;" class="mycode_b">DEGISTI</span> satiri gorurseniz once mesru bir guncelleme mi (paket yukseltmesi, deploy) diye bakin; degilse incelemeye alin.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5) Sinirlar</span></span><br />
Bu script bir baslangic noktasidir. Gercek ortamda baseline dosyasini salt-okunur veya ayri bir yerde tutun; saldirgan hem dosyayi hem baseline'i degistirebilir. Ayrica cok degisen dizinleri (log, cache) izleme disinda birakin, yoksa gurultu olur. Uretim icin AIDE gibi olgun araclara gecmenizi oneririm.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://docs.python.org/3/library/hashlib.html" target="_blank" rel="noopener" class="mycode_url">Python hashlib dokumantasyonu</a><br />
</li>
<li><a href="https://aide.github.io/" target="_blank" rel="noopener" class="mycode_url">AIDE - Advanced Intrusion Detection Environment</a><br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>Alıntı:</cite><span style="font-weight: bold;" class="mycode_b">Yasal not:</span> Scripti yalnizca kendi sunucularinizda veya yetkili oldugunuz sistemlerde calistirin.</blockquote>
<br />
Kolay gelsin.<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=64" target="_blank" title="">bilgekagan-b01.png</a> (Dosya Boyutu: 82.93 KB / İndirme Sayısı: 7)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Python ile SSH Brute Force Tespiti: auth.log Analiz Scripti (Adım Adım)]]></title>
			<link>https://www.turkteam.org/konu-python-ile-ssh-brute-force-tespiti-auth-log-analiz-scripti-adim-adim.html</link>
			<pubDate>Fri, 16 Oct 2026 11:09:46 +0300</pubDate>
			<dc:creator><![CDATA[<a href="https://www.turkteam.org/member.php?action=profile&uid=3">BilgeKagan</a>]]></dc:creator>
			<guid isPermaLink="false">https://www.turkteam.org/konu-python-ile-ssh-brute-force-tespiti-auth-log-analiz-scripti-adim-adim.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=3" loading="lazy"  alt="[Resim: attachment.php?aid=3]" class="mycode_img" /></div>
<br />
Selam arkadaşlar,<br />
<br />
İnternete açık bir VPS kiraladıysanız ilk gün şunu fark etmişsinizdir: sunucu daha hiçbir yerde duyurulmadan SSH portuna dakikada onlarca giriş denemesi gelmeye başlar. Bunların çoğu otomatik tarayıcılar ve botlardır. Ben kendi sunucularımda bu trafiği hem anlamak hem de raporlamak için küçük bir Python scripti kullanıyorum. Bu konuda o scripti satır satır anlatıyorum; tamamen savunma amaçlıdır ve sadece kendi sunucunuzun loglarında kullanılmalıdır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Konuda Anlatılacaklar</span></span><br />
<ol type="1" class="mycode_list"><li>SSH giriş denemeleri loglarda nasıl görünür?<br />
</li>
<li>auth.log mu, journalctl mi? (Debian/Ubuntu farkı)<br />
</li>
<li>Python scripti: regex, Counter ve argparse ile analiz<br />
</li>
<li>Çıktıyı yorumlamak: asıl tehlikeli olan satır hangisi?<br />
</li>
<li>Scripti otomatikleştirmek ve sonraki adımlar<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">1) Loglarda SSH Denemeleri Nasıl Görünür?</span></span><br />
OpenSSH sunucusu (sshd) her kimlik doğrulama olayını syslog'a yazar. Bizi ilgilendiren üç tip satır var:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>Failed password for root from 198.51.100.7 port 52122 ssh2
Invalid user admin from 203.0.113.45 port 40022
Accepted publickey for bilge from 192.168.1.20 port 51000 ssh2</code></div></div><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">Failed password / Failed publickey:</span> Var olan (veya "invalid user" olarak işaretlenen) bir hesaba hatalı deneme.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Invalid user:</span> Sistemde hiç olmayan bir kullanıcı adı denenmiş. Botlar admin, test, oracle, pi gibi isimleri sırayla dener.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Accepted:</span> Başarılı giriş. Brute force yapan bir IP'den bu satırı görüyorsanız alarm zili çalmalı.<br />
</li>
</ul>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">2) auth.log mu, journalctl mi?</span></span><br />
Ubuntu'da rsyslog varsayılan olarak geldiği için kayıtlar <span style="font-weight: bold;" class="mycode_b">/var/log/auth.log</span> dosyasında durur. Debian 12 ve sonrasında ise rsyslog varsayılan kurulumda gelmez, loglar sadece systemd journal içindedir. Script iki durumu da desteklesin diye dosya verilmezse standart girdiden (stdin) okuyacak şekilde yazdım:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># Ubuntu (rsyslog varsa)
sudo python3 ssh_tespit.py /var/log/auth.log

# Debian 12+ veya journal kullanan sistemler (servis adı dağıtıma göre ssh ya da sshd)
sudo journalctl -u ssh --since today -o cat | python3 ssh_tespit.py
sudo journalctl -u sshd --since "2 days ago" -o cat | python3 ssh_tespit.py --esik 5</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">3) Script</span></span><br />
Python 3.8 ve üstü yeterli (walrus operatörü := kullandım). Harici paket yok, sadece standart kütüphane:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>#!/usr/bin/env python3
"""auth.log / journalctl çıktısından SSH brute force denemelerini özetler."""
import argparse, ipaddress, json, re, sys
from collections import Counter, defaultdict

FAILED = re.compile(r"Failed (?:password|publickey) for (?:invalid user )?(?P&lt;user&gt;&#92;S+) from (?P&lt;ip&gt;[0-9a-fA-F:.]+)")
INVALID = re.compile(r"Invalid user (?P&lt;user&gt;&#92;S*) from (?P&lt;ip&gt;[0-9a-fA-F:.]+)")
ACCEPTED = re.compile(r"Accepted (?P&lt;method&gt;&#92;S+) for (?P&lt;user&gt;&#92;S+) from (?P&lt;ip&gt;[0-9a-fA-F:.]+)")

def analiz(satirlar):
    hata = Counter()        # "Failed password/publickey" satırları
    gecersiz = Counter()    # "Invalid user" satırları (olmayan kullanıcı)
    kullanicilar = defaultdict(set)
    basarili = defaultdict(list)
    for satir in satirlar:
        if m := FAILED.search(satir):
            hata[m["ip"]] += 1
            kullanicilar[m["ip"]].add(m["user"])
        elif m := INVALID.search(satir):
            gecersiz[m["ip"]] += 1
            kullanicilar[m["ip"]].add(m["user"] or "(bos)")
        elif m := ACCEPTED.search(satir):
            basarili[m["ip"]].append(f'{m["user"]}/{m["method"]}')
    return hata, gecersiz, kullanicilar, basarili

def main():
    p = argparse.ArgumentParser(description="SSH brute force özet raporu")
    p.add_argument("dosya", nargs="?", help="auth.log yolu (boşsa stdin okunur)")
    p.add_argument("--esik", type=int, default=10, help="şüpheli sayılacak minimum hatalı deneme")
    p.add_argument("--json", action="store_true", help="çıktıyı JSON ver")
    a = p.parse_args()

    kaynak = open(a.dosya, encoding="utf-8", errors="replace") if a.dosya else sys.stdin
    with kaynak:
        hata, gecersiz, kullanicilar, basarili = analiz(kaynak)

    rapor = []
    toplam = hata + gecersiz
    for ip, adet in toplam.most_common():
        if adet &lt; a.esik:
            break
        rapor.append({
            "ip": ip,
            "hatali_deneme": hata[ip],
            "gecersiz_kullanici": gecersiz[ip],
            "yerel_veya_ayrilmis": ipaddress.ip_address(ip).is_private,
            "denenen_kullanicilar": sorted(kullanicilar[ip])[:10],
            "basarili_giris": basarili.get(ip, []),
        })

    if a.json:
        print(json.dumps(rapor, ensure_ascii=False, indent=2))
        return
    print(f"{'IP':&lt;40}{'HATA':&gt;6}{'GECERSIZ':&gt;10}  KULLANICILAR")
    for r in rapor:
        uyari = "  &lt;-- DIKKAT: basarili giris var!" if r["basarili_giris"] else ""
        print(f"{r['ip']:&lt;40}{r['hatali_deneme']:&gt;6}{r['gecersiz_kullanici']:&gt;10}  {','.join(r['denenen_kullanicilar'])}{uyari}")
    print(f"&#92;nToplam {len(rapor)} şüpheli IP (eşik: {a.esik})")

if __name__ == "__main__":
    main()</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">Ne yapıyor, kısaca:</span><ul class="mycode_list"><li>Üç ayrı regex ile satırları sınıflandırıyor. IPv6 adresleri de yakalansın diye IP desenini [0-9a-fA-F:.] olarak geniş tuttum.<br />
</li>
<li>"Failed" ve "Invalid user" sayılarını ayrı tutuyorum. Bunun bir sebebi var: sshd olmayan bir kullanıcı için çoğu zaman önce "Invalid user" sonra "Failed password for invalid user" yazar. Tek sayaçta toplarsanız aynı denemeyi iki kez saymış olursunuz.<br />
</li>
<li>Eşik değeri (--esik) altında kalan IP'leri raporlamıyor; gürültü azalıyor.<br />
</li>
<li>ipaddress modülü ile adresin yerel/ayrılmış bir blokta olup olmadığını işaretliyor. Kendi ağınızdan gelen hatalı denemeler genelde şifresini unutan bir kullanıcıdır, farklı değerlendirin.<br />
</li>
<li>--json ile çıktıyı başka bir araca (SIEM, Telegram botu, cron maili) aktarabilirsiniz.<br />
</li>
</ul>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">4) Çıktıyı Yorumlamak</span></span><br />
Test için oluşturduğum örnek logda (dokümantasyon IP blokları kullanıldı) çıktı şöyle:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>IP                                        HATA  GECERSIZ  KULLANICILAR
203.0.113.45                                25         0  admin,oracle,test
198.51.100.7                                12         0  root  &lt;-- DIKKAT: basarili giris var!
192.0.2.9                                    0         3  pi

Toplam 3 şüpheli IP (eşik: 3)</code></div></div><br />
Burada asıl dikkat edilmesi gereken ikinci satır: 12 hatalı root denemesinin ardından aynı IP'den başarılı giriş var. Gerçek bir sunucuda bunu görürseniz yapılacaklar sırasıyla şunlar:<br />
<ol type="1" class="mycode_list"><li>O oturumu ve kullanıcıyı tespit edin: <span style="font-weight: bold;" class="mycode_b">last -i</span>, <span style="font-weight: bold;" class="mycode_b">who</span> ve journal kayıtları.<br />
</li>
<li>Şifreyi değiştirin, authorized_keys dosyasına sizin eklemediğiniz bir anahtar eklenmiş mi bakın.<br />
</li>
<li>crontab, systemd servisleri ve /tmp altında tanımadığınız dosya var mı kontrol edin.<br />
</li>
<li>Kalıcı çözüm: parola ile girişi kapatın, sadece anahtar kullanın.<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5) Otomatikleştirme ve Sonraki Adımlar</span></span><br />
Ben scripti günde bir kez çalıştırıp JSON çıktıyı bir dosyaya ekliyorum. Basit bir cron satırı:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># her gün 07:00'de dünün özetini kaydet
0 7 * * * journalctl -u ssh --since yesterday --until today -o cat | /usr/bin/python3 /opt/ssh_tespit.py --json &gt;&gt; /var/log/ssh_ozet.jsonl</code></div></div><br />
Tespit tek başına koruma değildir. Asıl koruma için sırasıyla:<ul class="mycode_list"><li>/etc/ssh/sshd_config içinde <span style="font-weight: bold;" class="mycode_b">PasswordAuthentication no</span> ve <span style="font-weight: bold;" class="mycode_b">PermitRootLogin no</span> (veya prohibit-password).<br />
</li>
<li>Fail2ban gibi bir araçla tekrarlayan denemeleri otomatik engelleme.<br />
</li>
<li>Mümkünse SSH'ı sadece VPN veya belirli IP'lerden erişilebilir yapmak.<br />
</li>
</ul>
<br />
Bu scripti geliştirmek isteyenlere fikir: saat bazlı dağılım (botlar genelde gece yoğunlaşıyor), ülke bilgisi için yerel bir GeoIP veritabanı, ya da sonuçları SQLite'a yazıp haftalık trend çıkarmak. Geliştiren olursa konunun altına eklesin, birlikte toparlarız.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://docs.python.org/3/library/re.html" target="_blank" rel="noopener" class="mycode_url">Python re modülü dokümantasyonu</a><br />
</li>
<li><a href="https://docs.python.org/3/library/collections.html#collections.Counter" target="_blank" rel="noopener" class="mycode_url">collections.Counter</a> ve <a href="https://docs.python.org/3/library/ipaddress.html" target="_blank" rel="noopener" class="mycode_url">ipaddress modülü</a><br />
</li>
<li><a href="https://man.openbsd.org/sshd_config" target="_blank" rel="noopener" class="mycode_url">OpenSSH sshd_config kılavuz sayfası</a><br />
</li>
<li><a href="https://www.freedesktop.org/software/systemd/man/latest/journalctl.html" target="_blank" rel="noopener" class="mycode_url">journalctl kılavuzu</a><br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>Alıntı:</cite><span style="font-weight: bold;" class="mycode_b">Yasal not:</span> Bu içerik savunma amaçlıdır. Scripti yalnızca yöneticisi olduğunuz veya yazılı izin aldığınız sistemlerin loglarında kullanın. Başkasına ait sistemlere izinsiz erişim TCK 243-245 kapsamında suçtur.</blockquote>
<br />
Kapak görseli: TurkTeam için hazırlanmış özgün görsel.<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=3" target="_blank" title="">bilgekagan-01.png</a> (Dosya Boyutu: 90.98 KB / İndirme Sayısı: 10)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><img src="https://www.turkteam.org/attachment.php?aid=3" loading="lazy"  alt="[Resim: attachment.php?aid=3]" class="mycode_img" /></div>
<br />
Selam arkadaşlar,<br />
<br />
İnternete açık bir VPS kiraladıysanız ilk gün şunu fark etmişsinizdir: sunucu daha hiçbir yerde duyurulmadan SSH portuna dakikada onlarca giriş denemesi gelmeye başlar. Bunların çoğu otomatik tarayıcılar ve botlardır. Ben kendi sunucularımda bu trafiği hem anlamak hem de raporlamak için küçük bir Python scripti kullanıyorum. Bu konuda o scripti satır satır anlatıyorum; tamamen savunma amaçlıdır ve sadece kendi sunucunuzun loglarında kullanılmalıdır.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Konuda Anlatılacaklar</span></span><br />
<ol type="1" class="mycode_list"><li>SSH giriş denemeleri loglarda nasıl görünür?<br />
</li>
<li>auth.log mu, journalctl mi? (Debian/Ubuntu farkı)<br />
</li>
<li>Python scripti: regex, Counter ve argparse ile analiz<br />
</li>
<li>Çıktıyı yorumlamak: asıl tehlikeli olan satır hangisi?<br />
</li>
<li>Scripti otomatikleştirmek ve sonraki adımlar<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">1) Loglarda SSH Denemeleri Nasıl Görünür?</span></span><br />
OpenSSH sunucusu (sshd) her kimlik doğrulama olayını syslog'a yazar. Bizi ilgilendiren üç tip satır var:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>Failed password for root from 198.51.100.7 port 52122 ssh2
Invalid user admin from 203.0.113.45 port 40022
Accepted publickey for bilge from 192.168.1.20 port 51000 ssh2</code></div></div><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">Failed password / Failed publickey:</span> Var olan (veya "invalid user" olarak işaretlenen) bir hesaba hatalı deneme.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Invalid user:</span> Sistemde hiç olmayan bir kullanıcı adı denenmiş. Botlar admin, test, oracle, pi gibi isimleri sırayla dener.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Accepted:</span> Başarılı giriş. Brute force yapan bir IP'den bu satırı görüyorsanız alarm zili çalmalı.<br />
</li>
</ul>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">2) auth.log mu, journalctl mi?</span></span><br />
Ubuntu'da rsyslog varsayılan olarak geldiği için kayıtlar <span style="font-weight: bold;" class="mycode_b">/var/log/auth.log</span> dosyasında durur. Debian 12 ve sonrasında ise rsyslog varsayılan kurulumda gelmez, loglar sadece systemd journal içindedir. Script iki durumu da desteklesin diye dosya verilmezse standart girdiden (stdin) okuyacak şekilde yazdım:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># Ubuntu (rsyslog varsa)
sudo python3 ssh_tespit.py /var/log/auth.log

# Debian 12+ veya journal kullanan sistemler (servis adı dağıtıma göre ssh ya da sshd)
sudo journalctl -u ssh --since today -o cat | python3 ssh_tespit.py
sudo journalctl -u sshd --since "2 days ago" -o cat | python3 ssh_tespit.py --esik 5</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">3) Script</span></span><br />
Python 3.8 ve üstü yeterli (walrus operatörü := kullandım). Harici paket yok, sadece standart kütüphane:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>#!/usr/bin/env python3
"""auth.log / journalctl çıktısından SSH brute force denemelerini özetler."""
import argparse, ipaddress, json, re, sys
from collections import Counter, defaultdict

FAILED = re.compile(r"Failed (?:password|publickey) for (?:invalid user )?(?P&lt;user&gt;&#92;S+) from (?P&lt;ip&gt;[0-9a-fA-F:.]+)")
INVALID = re.compile(r"Invalid user (?P&lt;user&gt;&#92;S*) from (?P&lt;ip&gt;[0-9a-fA-F:.]+)")
ACCEPTED = re.compile(r"Accepted (?P&lt;method&gt;&#92;S+) for (?P&lt;user&gt;&#92;S+) from (?P&lt;ip&gt;[0-9a-fA-F:.]+)")

def analiz(satirlar):
    hata = Counter()        # "Failed password/publickey" satırları
    gecersiz = Counter()    # "Invalid user" satırları (olmayan kullanıcı)
    kullanicilar = defaultdict(set)
    basarili = defaultdict(list)
    for satir in satirlar:
        if m := FAILED.search(satir):
            hata[m["ip"]] += 1
            kullanicilar[m["ip"]].add(m["user"])
        elif m := INVALID.search(satir):
            gecersiz[m["ip"]] += 1
            kullanicilar[m["ip"]].add(m["user"] or "(bos)")
        elif m := ACCEPTED.search(satir):
            basarili[m["ip"]].append(f'{m["user"]}/{m["method"]}')
    return hata, gecersiz, kullanicilar, basarili

def main():
    p = argparse.ArgumentParser(description="SSH brute force özet raporu")
    p.add_argument("dosya", nargs="?", help="auth.log yolu (boşsa stdin okunur)")
    p.add_argument("--esik", type=int, default=10, help="şüpheli sayılacak minimum hatalı deneme")
    p.add_argument("--json", action="store_true", help="çıktıyı JSON ver")
    a = p.parse_args()

    kaynak = open(a.dosya, encoding="utf-8", errors="replace") if a.dosya else sys.stdin
    with kaynak:
        hata, gecersiz, kullanicilar, basarili = analiz(kaynak)

    rapor = []
    toplam = hata + gecersiz
    for ip, adet in toplam.most_common():
        if adet &lt; a.esik:
            break
        rapor.append({
            "ip": ip,
            "hatali_deneme": hata[ip],
            "gecersiz_kullanici": gecersiz[ip],
            "yerel_veya_ayrilmis": ipaddress.ip_address(ip).is_private,
            "denenen_kullanicilar": sorted(kullanicilar[ip])[:10],
            "basarili_giris": basarili.get(ip, []),
        })

    if a.json:
        print(json.dumps(rapor, ensure_ascii=False, indent=2))
        return
    print(f"{'IP':&lt;40}{'HATA':&gt;6}{'GECERSIZ':&gt;10}  KULLANICILAR")
    for r in rapor:
        uyari = "  &lt;-- DIKKAT: basarili giris var!" if r["basarili_giris"] else ""
        print(f"{r['ip']:&lt;40}{r['hatali_deneme']:&gt;6}{r['gecersiz_kullanici']:&gt;10}  {','.join(r['denenen_kullanicilar'])}{uyari}")
    print(f"&#92;nToplam {len(rapor)} şüpheli IP (eşik: {a.esik})")

if __name__ == "__main__":
    main()</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b">Ne yapıyor, kısaca:</span><ul class="mycode_list"><li>Üç ayrı regex ile satırları sınıflandırıyor. IPv6 adresleri de yakalansın diye IP desenini [0-9a-fA-F:.] olarak geniş tuttum.<br />
</li>
<li>"Failed" ve "Invalid user" sayılarını ayrı tutuyorum. Bunun bir sebebi var: sshd olmayan bir kullanıcı için çoğu zaman önce "Invalid user" sonra "Failed password for invalid user" yazar. Tek sayaçta toplarsanız aynı denemeyi iki kez saymış olursunuz.<br />
</li>
<li>Eşik değeri (--esik) altında kalan IP'leri raporlamıyor; gürültü azalıyor.<br />
</li>
<li>ipaddress modülü ile adresin yerel/ayrılmış bir blokta olup olmadığını işaretliyor. Kendi ağınızdan gelen hatalı denemeler genelde şifresini unutan bir kullanıcıdır, farklı değerlendirin.<br />
</li>
<li>--json ile çıktıyı başka bir araca (SIEM, Telegram botu, cron maili) aktarabilirsiniz.<br />
</li>
</ul>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">4) Çıktıyı Yorumlamak</span></span><br />
Test için oluşturduğum örnek logda (dokümantasyon IP blokları kullanıldı) çıktı şöyle:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code>IP                                        HATA  GECERSIZ  KULLANICILAR
203.0.113.45                                25         0  admin,oracle,test
198.51.100.7                                12         0  root  &lt;-- DIKKAT: basarili giris var!
192.0.2.9                                    0         3  pi

Toplam 3 şüpheli IP (eşik: 3)</code></div></div><br />
Burada asıl dikkat edilmesi gereken ikinci satır: 12 hatalı root denemesinin ardından aynı IP'den başarılı giriş var. Gerçek bir sunucuda bunu görürseniz yapılacaklar sırasıyla şunlar:<br />
<ol type="1" class="mycode_list"><li>O oturumu ve kullanıcıyı tespit edin: <span style="font-weight: bold;" class="mycode_b">last -i</span>, <span style="font-weight: bold;" class="mycode_b">who</span> ve journal kayıtları.<br />
</li>
<li>Şifreyi değiştirin, authorized_keys dosyasına sizin eklemediğiniz bir anahtar eklenmiş mi bakın.<br />
</li>
<li>crontab, systemd servisleri ve /tmp altında tanımadığınız dosya var mı kontrol edin.<br />
</li>
<li>Kalıcı çözüm: parola ile girişi kapatın, sadece anahtar kullanın.<br />
</li>
</ol>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5) Otomatikleştirme ve Sonraki Adımlar</span></span><br />
Ben scripti günde bir kez çalıştırıp JSON çıktıyı bir dosyaya ekliyorum. Basit bir cron satırı:<br />
<br />
<div class="codeblock"><div class="title">Kod:</div><div class="body" dir="ltr"><code># her gün 07:00'de dünün özetini kaydet
0 7 * * * journalctl -u ssh --since yesterday --until today -o cat | /usr/bin/python3 /opt/ssh_tespit.py --json &gt;&gt; /var/log/ssh_ozet.jsonl</code></div></div><br />
Tespit tek başına koruma değildir. Asıl koruma için sırasıyla:<ul class="mycode_list"><li>/etc/ssh/sshd_config içinde <span style="font-weight: bold;" class="mycode_b">PasswordAuthentication no</span> ve <span style="font-weight: bold;" class="mycode_b">PermitRootLogin no</span> (veya prohibit-password).<br />
</li>
<li>Fail2ban gibi bir araçla tekrarlayan denemeleri otomatik engelleme.<br />
</li>
<li>Mümkünse SSH'ı sadece VPN veya belirli IP'lerden erişilebilir yapmak.<br />
</li>
</ul>
<br />
Bu scripti geliştirmek isteyenlere fikir: saat bazlı dağılım (botlar genelde gece yoğunlaşıyor), ülke bilgisi için yerel bir GeoIP veritabanı, ya da sonuçları SQLite'a yazıp haftalık trend çıkarmak. Geliştiren olursa konunun altına eklesin, birlikte toparlarız.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Kaynaklar</span></span><ul class="mycode_list"><li><a href="https://docs.python.org/3/library/re.html" target="_blank" rel="noopener" class="mycode_url">Python re modülü dokümantasyonu</a><br />
</li>
<li><a href="https://docs.python.org/3/library/collections.html#collections.Counter" target="_blank" rel="noopener" class="mycode_url">collections.Counter</a> ve <a href="https://docs.python.org/3/library/ipaddress.html" target="_blank" rel="noopener" class="mycode_url">ipaddress modülü</a><br />
</li>
<li><a href="https://man.openbsd.org/sshd_config" target="_blank" rel="noopener" class="mycode_url">OpenSSH sshd_config kılavuz sayfası</a><br />
</li>
<li><a href="https://www.freedesktop.org/software/systemd/man/latest/journalctl.html" target="_blank" rel="noopener" class="mycode_url">journalctl kılavuzu</a><br />
</li>
</ul>
<br />
<blockquote class="mycode_quote"><cite>Alıntı:</cite><span style="font-weight: bold;" class="mycode_b">Yasal not:</span> Bu içerik savunma amaçlıdır. Scripti yalnızca yöneticisi olduğunuz veya yazılı izin aldığınız sistemlerin loglarında kullanın. Başkasına ait sistemlere izinsiz erişim TCK 243-245 kapsamında suçtur.</blockquote>
<br />
Kapak görseli: TurkTeam için hazırlanmış özgün görsel.<br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://cdn.turkteam.org/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=3" target="_blank" title="">bilgekagan-01.png</a> (Dosya Boyutu: 90.98 KB / İndirme Sayısı: 10)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
	</channel>
</rss>