July 19, 2026
External Pentest: Uçtan Uca Recon Workflow
Bir external penetration test’te genellikle çok dar bir girdiyle başlarız: bir scope.txt dosyası ve içinde birkaç root domain. Amaç, bu dar…

By Exript
12 min read
External Pentest: Uçtan Uca Recon Workflow
Bir external penetration test'te genellikle çok dar bir girdiyle başlarız: bir scope.txt dosyası ve içinde birkaç root domain. Amaç, bu dar girdiden başlayarak tüm attack surface'i ortaya çıkarmak ve kritik zafiyetlere doğru ilerlemektir.
Bu yazıda, OSCP tarzı "manuel + LotL (Living off the Land) öncelikli, otomatik exploit son çare" yaklaşımını benimseyen bir external pentest recon workflow'unu adım adım paylaşacağım. Tek girdi scope.txt, her faz bir öncekinin çıktı dosyasını yer ve akış şu şekilde: recon → content discovery → analysis → tech-specific attacks → manual review
Yetki (Authorization):_ Buradaki tüm teknikler yalnızca yazılı izinli (signed scope) engagement'larda, kendi lab'ında ya da CTF/OSCP pratiğinde kullanılmalıdır. External test'te ekstra bir sorumluluk daha vardır: sadece scope içindeki asset'leri tara. CDN, paylaşımlı hosting ve üçüncü parti IP'lere port taraması atmak hem işe yaramaz hem de scope ihlalidir._
Directory Layout ve Dosya Zinciri
İşe başlamadan önce dosya yapısını kurmak önemli. Bu, sonraki fazlarda "hangi dosyayı nerede bulacağım" karmaşasını engeller.
mkdir -p recon/{subs,urls,js,fuzz,screenshots,viewstate,nmap,internetdb}
cp scope.txt recon/scope.txt
cd reconmkdir -p recon/{subs,urls,js,fuzz,screenshots,viewstate,nmap,internetdb}
cp scope.txt recon/scope.txt
cd reconDosya zinciri isimlendirmeleri:
scope.txt → girdi (root domainler)
subs/subs_all.txt → tüm subdomainler (merge)
subs/resolved.txt → çözülen DOMAIN'ler (httpx girdisi, vhost-safe)
subs/dns_map.txt → domain [IP] haritası (referans)
subs/ips.txt → unique IP'ler (naabu/nmap girdisi)
live.txt → CANLI web servisleri ana dosya (domain bazlı)
live_detailed.txt → status + length + title (eleme için)
urls/all_urls.txt → historical + crawl URL'leri
urls/interesting.txt → urinteresting ile filtrelenmiş URL'ler
urls/params.txt → parametreli URL'ler
js/js_urls.txt → JS dosya URL'leri
viewstate/aspx.txt → .NET / ASPX hedefleri scope.txt → girdi (root domainler)
subs/subs_all.txt → tüm subdomainler (merge)
subs/resolved.txt → çözülen DOMAIN'ler (httpx girdisi, vhost-safe)
subs/dns_map.txt → domain [IP] haritası (referans)
subs/ips.txt → unique IP'ler (naabu/nmap girdisi)
live.txt → CANLI web servisleri ana dosya (domain bazlı)
live_detailed.txt → status + length + title (eleme için)
urls/all_urls.txt → historical + crawl URL'leri
urls/interesting.txt → urinteresting ile filtrelenmiş URL'ler
urls/params.txt → parametreli URL'ler
js/js_urls.txt → JS dosya URL'leri
viewstate/aspx.txt → .NET / ASPX hedefleriBu dosyalar, fazlar arasında birbirini besleyecek şekilde tasarlandı. Kritik nokta şu: web tabanlı araçlar (httpx, ffuf, gowitness) domain/URL yer; port tarayıcıları (naabu, nmap) ise unique IP yer. İkisini karıştırmamak, hem doğru sonuç hem de dedup (aynı IP'yi 20 kez taramama) sağlar.
Faz 0 — Toplu Kurulum (Setup)
1) Go Ortamı + Sistem Bağımlılıkları
sudo apt update && sudo apt install -y \
golang-go git python3-pip mono-complete libpcap-dev \
jq whatweb nmap amass wpscan seclists pipx
# NOT: whatweb/nmap/amass/jq/seclists Kali'de çoğunlukla hazır gelir, yine de burada garanti altına alıyoruz. seclists → Faz 4 için şart.
# go binary path'ini kalıcı yap:
echo 'export PATH=$PATH:$HOME/go/bin' >> ~/.zshrc && source ~/.zshrcsudo apt update && sudo apt install -y \
golang-go git python3-pip mono-complete libpcap-dev \
jq whatweb nmap amass wpscan seclists pipx
# NOT: whatweb/nmap/amass/jq/seclists Kali'de çoğunlukla hazır gelir, yine de burada garanti altına alıyoruz. seclists → Faz 4 için şart.
# go binary path'ini kalıcı yap:
echo 'export PATH=$PATH:$HOME/go/bin' >> ~/.zshrc && source ~/.zshrcKali-VM / Wayland uyarısı: Kali'nin son sürümleri Wayland'e geçebiliyor.
gowitnessgibi Chrome-headless kullanan araçlar Wayland altında sorun çıkarmaz (kendi headless Chromium'unu indirir), ama clipboard sharing ve screenshot tool'ları (flameshot,spectacle) Wayland'de X11'e göre farklı davranır. VM'de takılırsanecho $XDG_SESSION_TYPEile session tipini kontrol et; gerekirse login ekranından X11 (Xorg) session'a geç.
2) ProjectDiscovery + tomnomnom Araçları
# PD suite (subfinder, httpx, dnsx, naabu, katana) tek seferde:
go install github.com/projectdiscovery/pdtm/cmd/pdtm@latest
pdtm -install-all
# tomnomnom & co.
go install github.com/lc/gau/v2/cmd/gau@latest
go install github.com/tomnomnom/waybackurls@latest
go install github.com/tomnomnom/qsreplace@latest
go install github.com/tomnomnom/anew@latest # pipeline için
go install github.com/tomnomnom/hacks/urinteresting@latest# PD suite (subfinder, httpx, dnsx, naabu, katana) tek seferde:
go install github.com/projectdiscovery/pdtm/cmd/pdtm@latest
pdtm -install-all
# tomnomnom & co.
go install github.com/lc/gau/v2/cmd/gau@latest
go install github.com/tomnomnom/waybackurls@latest
go install github.com/tomnomnom/qsreplace@latest
go install github.com/tomnomnom/anew@latest # pipeline için
go install github.com/tomnomnom/hacks/urinteresting@latesturinteresting config notu: urinteresting neyin "ilginç" sayılacağını bir JSON config'ten okur. İlk çalıştırmada boş dönerse config'i getir:
git clone https://github.com/tomnomnom/hacks ~/tools/hacks
cp ~/tools/hacks/urinteresting/.urinteresting.json ~/.urinteresting.jsongit clone https://github.com/tomnomnom/hacks ~/tools/hacks
cp ~/tools/hacks/urinteresting/.urinteresting.json ~/.urinteresting.jsonConfig içinde ilginç extension'lar (.bak, .config, .sql, .json) ve path pattern'leri tanımlı; kendine göre genişletebilirsin.
3) Python Kurulum Standardı
Sistem Python'unu pip install ile kirletmemek için:
- Packaged tool (setup.py / PyPI var) →
pipx install ...(izole, global komut). - Clone-and-run script (packaging yok) → araç başına
venv:
python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txtpython3 -m venv venv && source venv/bin/activate && pip install -r requirements.txtpipx'i Faz 0.1'de kurduk; ensurepath ile PATH'e ekle. İstersen hızlı ephemeral çalıştırma için uv/uvx:
pipx ensurepath # global CLI'lar için
curl -LsSf https://astral.sh/uv/install.sh | sh # uv + uvx (opsiyonel)pipx ensurepath # global CLI'lar için
curl -LsSf https://astral.sh/uv/install.sh | sh # uv + uvx (opsiyonel)4) Screenshot / JS / Secret Araçları
go install github.com/sensepost/gowitness@latest
go install github.com/BishopFox/jsluice/cmd/jsluice@latest
# trufflehog
curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \
| sudo sh -s -- -b /usr/local/bin
# LinkFinder - packaged (setup.py var) → pipx ile doğrudan git'ten:
pipx install git+https://github.com/GerbenJavado/LinkFinder.git # → 'linkfinder' komutu
# NOT: entry-point bulunamazsa fallback → python linkfinder.py -i <url> -o cli
# SecretFinder - venv:
git clone https://github.com/m4ll0k/SecretFinder ~/tools/SecretFinder
cd ~/tools/SecretFinder
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt jsbeautifier requests
deactivate && cd -
# Çalıştırma: ~/tools/SecretFinder/venv/bin/python ~/tools/SecretFinder/SecretFinder.py -i <url> -o cligo install github.com/sensepost/gowitness@latest
go install github.com/BishopFox/jsluice/cmd/jsluice@latest
# trufflehog
curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \
| sudo sh -s -- -b /usr/local/bin
# LinkFinder - packaged (setup.py var) → pipx ile doğrudan git'ten:
pipx install git+https://github.com/GerbenJavado/LinkFinder.git # → 'linkfinder' komutu
# NOT: entry-point bulunamazsa fallback → python linkfinder.py -i <url> -o cli
# SecretFinder - venv:
git clone https://github.com/m4ll0k/SecretFinder ~/tools/SecretFinder
cd ~/tools/SecretFinder
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt jsbeautifier requests
deactivate && cd -
# Çalıştırma: ~/tools/SecretFinder/venv/bin/python ~/tools/SecretFinder/SecretFinder.py -i <url> -o cli5) ViewState / machineKey Araçları
# badsecrets - PyPI'de var → pipx (izole global 'badsecrets' komutu):
pipx install badsecrets
# crapsecrets - clone-and-run (irsdl fork) → venv:
git clone https://github.com/irsdl/crapsecrets ~/tools/crapsecrets
cd ~/tools/crapsecrets
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt # (repo'da varsa; yoksa README'deki bağımlılıklar)
deactivate && cd -
# ysoserial.net → github releases'ten son .zip'i ~/tools/ysoserial.net/ altına aç (mono ile çalışır)# badsecrets - PyPI'de var → pipx (izole global 'badsecrets' komutu):
pipx install badsecrets
# crapsecrets - clone-and-run (irsdl fork) → venv:
git clone https://github.com/irsdl/crapsecrets ~/tools/crapsecrets
cd ~/tools/crapsecrets
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt # (repo'da varsa; yoksa README'deki bağımlılıklar)
deactivate && cd -
# ysoserial.net → github releases'ten son .zip'i ~/tools/ysoserial.net/ altına aç (mono ile çalışır)Faz 1+2 — Subdomain Enum → Live (scope.txt → live.txt) [PIPELINE]
Passive kaynakları subs_all.txt'te topla; ardından sırayla resolve (wildcard temizliğiyle) → live tespiti → IP çıkarımı yap. anew her adımda sadece yeni/unique satırları geçirir (idempotent pipeline).
# scope.txt → root domainler
sort -u scope.txt > roots.txt
# --- Passive toplama (subs_all.txt'te merge) ---
subfinder -dL roots.txt -all -silent | anew subs/subs_all.txt
amass enum -passive -df roots.txt | anew subs/subs_all.txt
# crt.sh
while read -r d; do
curl -s "https://crt.sh/?q=%25.$d&output=json" | jq -r '.[].name_value'
done < roots.txt | sed 's/\*\.//g'| tr '[:upper:]' '[:lower:]' \
| grep -v '@' | anew subs/subs_all.txt# scope.txt → root domainler
sort -u scope.txt > roots.txt
# --- Passive toplama (subs_all.txt'te merge) ---
subfinder -dL roots.txt -all -silent | anew subs/subs_all.txt
amass enum -passive -df roots.txt | anew subs/subs_all.txt
# crt.sh
while read -r d; do
curl -s "https://crt.sh/?q=%25.$d&output=json" | jq -r '.[].name_value'
done < roots.txt | sed 's/\*\.//g'| tr '[:upper:]' '[:lower:]' \
| grep -v '@' | anew subs/subs_all.txtWildcard DNS'i önceden ele (kritik!)
Bazı domainler wildcard DNS kullanır: *.target.com → her subdomain aynı IP'ye çözülür. Bu, enum'unu binlerce false positive ile şişirir. dnsx bunu temizler. Birden fazla root domain olduğu için -auto-wildcard kullanıyoruz (tek domain'lik eski -wd yerine):
# resolve + otomatik wildcard temizliği (domain'ler korunur):
dnsx -l subs/subs_all.txt -auto-wildcard -silent | anew subs/resolved.txt# resolve + otomatik wildcard temizliği (domain'ler korunur):
dnsx -l subs/subs_all.txt -auto-wildcard -silent | anew subs/resolved.txtBayrak notu:
-wd <domain>yalnızca tek bir domain alır ve o modda diğer flag'ler yok sayılır — bizimroots.txt'imizde birden çok root olduğu için işe yaramaz.-auto-wildcardmixed-domain input'ta wildcard'ları otomatik tespit eder. Eğer kuruludnsxsürümün-auto-wildcardtanımıyorsa güncelle (dnsx -up) ya da her root için ayrı ayrı-wdile döngü kur.
Live web servislerini bul
# resolved DOMAIN'ler → httpx → live.txt (★ ana dosya, domain bazlı)
httpx -l subs/resolved.txt -silent -o live.txt# resolved DOMAIN'ler → httpx → live.txt (★ ana dosya, domain bazlı)
httpx -l subs/resolved.txt -silent -o live.txtDetaylı sürüm (eleme için — status + length + title + tech):
httpx -l subs/resolved.txt -silent \
-status-code -content-length -title -tech-detect -web-server \
-o live_detailed.txthttpx -l subs/resolved.txt -silent \
-status-code -content-length -title -tech-detect -web-server \
-o live_detailed.txtNot:
live.txt→ sadece URL'ler (ffuf / gowitness / katana bunu doğrudan yer;gau/waybackurlsise scheme'siz host ister — Faz 5'telive.txt'ten türetiyoruz).live_detailed.txt→ status+length+title (manuel eleme /grep -v).
IP haritasını ve unique IP listesini üret (dosya zincirinin eksik halkası)
Port tarama fazları subs/ips.txt ister ama bu dosya kendiliğinden oluşmaz — burada üretiyoruz:
# domain [IP] haritası (referans/raporlama)
dnsx -l subs/resolved.txt -a -resp -silent -o subs/dns_map.txt
# unique IP'ler (naabu/nmap girdisi) → aynı IP tekrar tekrar taranmasın
dnsx -l subs/resolved.txt -a -resp-only -silent | sort -u > subs/ips.txt# domain [IP] haritası (referans/raporlama)
dnsx -l subs/resolved.txt -a -resp -silent -o subs/dns_map.txt
# unique IP'ler (naabu/nmap girdisi) → aynı IP tekrar tekrar taranmasın
dnsx -l subs/resolved.txt -a -resp-only -silent | sort -u > subs/ips.txtAynı status+length imzasını eleme
# Hangi status+length imzası kaç kez tekrar ediyor?
awk '{print $2, $3}' live_detailed.txt | sort | uniq -c | sort -rn
# En çok tekrar eden = jenerik/parking/wildcard → ele:
grep -v -e '\[200\] \[1547\]' -e '\[302\] \[0\]' live_detailed.txt > interesting_hosts.txt# Hangi status+length imzası kaç kez tekrar ediyor?
awk '{print $2, $3}' live_detailed.txt | sort | uniq -c | sort -rn
# En çok tekrar eden = jenerik/parking/wildcard → ele:
grep -v -e '\[200\] \[1547\]' -e '\[302\] \[0\]' live_detailed.txt > interesting_hosts.txtScreenshots
gowitness scan file -f live.txt --screenshot-path screenshots/ --write-db
# Sonuçları tarayıcıda gözden geçir:
gowitness report server # → http://localhost:7171gowitness scan file -f live.txt --screenshot-path screenshots/ --write-db
# Sonuçları tarayıcıda gözden geçir:
gowitness report server # → http://localhost:7171gowitness sürüm uyarısı: v2'de komut
gowitness file -f ...idi; v3'tegowitness scan file -f ...oldu.go install ...@latestv3 getirir. Eski blog'lardakigowitness filekomutunu kullanma.
Faz 2.5 — Port Tarama (subs/ips.txt → nmap/)
Bu, orijinal akışın en eksik bölümüydü. Doğru external port tarama iki katmanlıdır ve OSCP mantığıyla her portu görmek ister:
Karar Ağacı :
- Hedef IP bir CDN/WAF arkasında mı (Cloudflare/Akamai/Fastly)? → Port taraması ANLAMSIZ, CDN'i tararsın, origin'i değil. Önce ele.
- CDN değilse → Stage 1: full TCP port discovery (naabu, 1–65535).
- Açık port bulundu → Stage 2: sadece o portlarda nmap service/version + default script taraması.
- Web portu (80/443/8080/8443…) çıktıysa →
live.txt'e geri besle (Faz 1'e feedback loop).
Adım 0 — CDN/WAF IP'lerini ayıkla
CDN arkasındaki IP'yi taramak boşa efordur. httpx CDN tespit eder:
# 1) httpx ile CDN tespiti (JSON) — 'input' alanı orijinal domain'i verir (stabil field)
httpx -l subs/resolved.txt -silent -cdn -json -o cdncheck.json
# 2) CDN olmayan (origin adayı) domain'ler
jq -r 'select(.cdn != true) | .input' cdncheck.json 2>/dev/null | sort -u > subs/noncdn_domains.txt
# 3) Bu domain'leri IP'ye çöz → port tarama girdisi
dnsx -l subs/noncdn_domains.txt -a -resp-only -silent | sort -u > subs/ips_noncdn.txt
# Güvenlik ağı: adım boş dönerse tüm IP'lerle devam et (CDN'leri manuel not al)
[ -s subs/ips_noncdn.txt ] || cp subs/ips.txt subs/ips_noncdn.txt# 1) httpx ile CDN tespiti (JSON) — 'input' alanı orijinal domain'i verir (stabil field)
httpx -l subs/resolved.txt -silent -cdn -json -o cdncheck.json
# 2) CDN olmayan (origin adayı) domain'ler
jq -r 'select(.cdn != true) | .input' cdncheck.json 2>/dev/null | sort -u > subs/noncdn_domains.txt
# 3) Bu domain'leri IP'ye çöz → port tarama girdisi
dnsx -l subs/noncdn_domains.txt -a -resp-only -silent | sort -u > subs/ips_noncdn.txt
# Güvenlik ağı: adım boş dönerse tüm IP'lerle devam et (CDN'leri manuel not al)
[ -s subs/ips_noncdn.txt ] || cp subs/ips.txt subs/ips_noncdn.txtAdım 1 — Full TCP port discovery (naabu)
naabu'nun en büyük avantajı otomatik IP dedup'ı: 20 subdomain aynı IP'ye çözülüyorsa o IP'yi bir kez tarar.
# Tüm portlar (1-65535). External'de agresif gitme: rate'i makul tut.
sudo naabu -l subs/ips_noncdn.txt -p - -rate 1000 -c 50 -retries 2 \
-silent -o nmap/naabu_full.txt
# Çıktı formatı: ip:port# Tüm portlar (1-65535). External'de agresif gitme: rate'i makul tut.
sudo naabu -l subs/ips_noncdn.txt -p - -rate 1000 -c 50 -retries 2 \
-silent -o nmap/naabu_full.txt
# Çıktı formatı: ip:portAdım 2 — Nmap ile derin service/version taraması
İki yol var. Temiz yol (önerilen): naabu'nun native -nmap-cli entegrasyonu — naabu portları bulur, sonucu doğrudan nmap'e verir:
sudo naabu -l subs/ips_noncdn.txt -p - -rate 1000 -silent \
-nmap-cli 'nmap -sVC -Pn --open -oA nmap/full'sudo naabu -l subs/ips_noncdn.txt -p - -rate 1000 -silent \
-nmap-cli 'nmap -sVC -Pn --open -oA nmap/full'Manuel yol (kontrol istiyorsan): naabu çıktısından IP ve port listelerini ayır, sonra nmap'i sen çalıştır:
# naabu 'ip:port' çıktısını nmap girdisine çevir
cut -d: -f1 nmap/naabu_full.txt | sort -u > nmap/live_ips.txt
cut -d: -f2 nmap/naabu_full.txt | sort -u | paste -sd, - > nmap/open_ports.txt
# Sadece bulunan portlarda derin tarama
sudo nmap -sVC -Pn --open -p "$(cat nmap/open_ports.txt)" \
-iL nmap/live_ips.txt -oA nmap/full# naabu 'ip:port' çıktısını nmap girdisine çevir
cut -d: -f1 nmap/naabu_full.txt | sort -u > nmap/live_ips.txt
cut -d: -f2 nmap/naabu_full.txt | sort -u | paste -sd, - > nmap/open_ports.txt
# Sadece bulunan portlarda derin tarama
sudo nmap -sVC -Pn --open -p "$(cat nmap/open_ports.txt)" \
-iL nmap/live_ips.txt -oA nmap/fullBayrakların (flags) anlamı:
-sVC=-sV -sC→ service/version detection + default NSE script scan.-Pn→ host discovery'yi (ping) atla. External hedefler ICMP'yi çoğunlukla drop eder;-Pnolmadan nmap host'u "down" sanıp hiç taramaz. External'de neredeyse her zaman gerekli.--open→ sadece açık portları göster (çıktı temizliği).-oA nmap/full→ üç formatta kaydet (.nmap,.gnmap,.xml)..xmlsonradan raporlama/gowitness nmapiçin lazım.
Adım 3 — UDP top ports (unutulan yüzey)
External'de UDP çoğu zaman atlanır ama DNS(53), SNMP(161), TFTP(69), NTP(123), IKE(500) gibi servisler kritik olabilir:
sudo nmap -sU --top-ports 100 -Pn --open -iL nmap/live_ips.txt -oA nmap/udpsudo nmap -sU --top-ports 100 -Pn --open -iL nmap/live_ips.txt -oA nmap/udproot notu: SYN scan (
-sS, naabu'nun default'u) ve UDP scan (-sU) root ister →sudo. Root yoksa naabu CONNECT scan'e (-s c) düşer; nmap ise-sT(TCP connect) kullanır — daha yavaş ama privilege gerektirmez.
Adım 4 — Web portlarını akışa geri besle (feedback loop)
Nmap'in bulduğu HTTP(S) servislerini live.txt'e ekleyip tüm web fazlarını bu yeni yüzeyde de çalıştır:
# naabu'nun bulduğu ip:port çiftlerini httpx'e ver → canlı HTTP(S) olanlar live.txt'e
sed 's#:# #' nmap/naabu_full.txt | while read -r ip port; do
echo "http://$ip:$port"; echo "https://$ip:$port"
done | httpx -silent | anew live.txt# naabu'nun bulduğu ip:port çiftlerini httpx'e ver → canlı HTTP(S) olanlar live.txt'e
sed 's#:# #' nmap/naabu_full.txt | while read -r ip port; do
echo "http://$ip:$port"; echo "https://$ip:$port"
done | httpx -silent | anew live.txtBöylece "8443'te açık ama subdomain enum'da görünmeyen" bir yönetim paneli de
live.txt'e girer ve Faz 3-6'da otomatik ele alınır.
Faz 3 — Tech Fingerprinting (live.txt → tech.json + viewstate/aspx.txt)
whatweb -i live.txt --log-brief=whatweb.txt --no-errors
httpx -l live.txt -tech-detect -json -o tech.jsonwhatweb -i live.txt --log-brief=whatweb.txt --no-errors
httpx -l live.txt -tech-detect -json -o tech.json.NET / IIS hedeflerini ayır (Faz 8'in girdisi). Burada iki bağımsız sinyal kullanıyoruz, çünkü httpx -json çıktısı response body içermez — yani __VIEWSTATE'i tech.json içinde aramak boşadır. Doğrusu:
# (a) tech-detect / server header sinyali: satırda ASP.NET veya IIS geçen kayıtların URL'i
grep -iaE 'asp\.net|iis' tech.json | jq -r '.url' | sort -u > viewstate/aspx.txt
# (b) gerçek body kontrolü: sayfada __VIEWSTATE var mı? (asıl güvenilir kanıt)
while read -r u; do
curl -s -k "$u" | grep -qi '__VIEWSTATE' && echo "$u"
done < live.txt | anew viewstate/aspx.txt
# (c) URL uzantısı ipucu (Faz 5'ten sonra all_urls.txt hazırsa)
grep -iE '\.aspx?($|\?)' urls/all_urls.txt 2>/dev/null | sort -u | anew viewstate/aspx.txt# (a) tech-detect / server header sinyali: satırda ASP.NET veya IIS geçen kayıtların URL'i
grep -iaE 'asp\.net|iis' tech.json | jq -r '.url' | sort -u > viewstate/aspx.txt
# (b) gerçek body kontrolü: sayfada __VIEWSTATE var mı? (asıl güvenilir kanıt)
while read -r u; do
curl -s -k "$u" | grep -qi '__VIEWSTATE' && echo "$u"
done < live.txt | anew viewstate/aspx.txt
# (c) URL uzantısı ipucu (Faz 5'ten sonra all_urls.txt hazırsa)
grep -iE '\.aspx?($|\?)' urls/all_urls.txt 2>/dev/null | sort -u | anew viewstate/aspx.txtKarar Ağacı:
- ASP.NET / IIS /
__VIEWSTATE→viewstate/aspx.txt→ Faz 8 ana koz. - WordPress →
wpscan --url TARGET --enumerate vp,vt,u. - Tomcat / JBoss / WebLogic → manager panel + deserialization.
- Else → generic content discovery.
Faz 4 — Dir Fuzz (live.txt → fuzz/)
ffuf'un native çoklu-wordlist özelliğiyle: bir wordlist host'ları (live.txt), biri path'leri besler. Default mod clusterbomb = her host × her path. -ac (auto-calibration), "aynı status+length'i ignore ede ede git" mantığının otomatik hali.
ffuf -w live.txt:HOST \
-w /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt:FUZZ \
-u HOST/FUZZ -mc all -ac -o fuzz/all.json -of jsonffuf -w live.txt:HOST \
-w /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt:FUZZ \
-u HOST/FUZZ -mc all -ac -o fuzz/all.json -of jsonNot:
live.txtgirdileri scheme dahil tam URL (https://sub.domain.com) olduğundan-u HOST/FUZZdoğru sonucu verir.seclistsFaz 0'da kuruldu; yoksasudo apt install seclists.
Alternatif — dirsearch (-l ile liste):
dirsearch -l live.txt -e aspx,asmx,ashx,config,php,bak -x 404,403 --format json -o fuzz/dirsearch.jsondirsearch -l live.txt -e aspx,asmx,ashx,config,php,bak -x 404,403 --format json -o fuzz/dirsearch.jsonÇıktı Analizi :
- WAF 403/429 alırsan →
-rate 30 -p 0.5-1.5(throttle + random delay) ve gerçekçi-H "User-Agent: ...". - .NET hedefte → extension daralt:
-e aspx,asmx,ashx,config.
(Opsiyonel) Virtual host fuzzing: Aynı IP'de birden fazla site barınıyorsa Host header fuzzing ile gizli vhost bulabilirsin:
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ \
-u https://TARGET_IP/ -H "Host: FUZZ.target.com" -acffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ \
-u https://TARGET_IP/ -H "Host: FUZZ.target.com" -acFaz 5 — Historical URLs + urinteresting (live.txt → all_urls.txt → interesting.txt)
Önemli: gau ve waybackurls girdi olarak host/domain bekler, tam URL değil. live.txt scheme içerdiği için önce host'ları çıkaralım; katana ise tam URL yediği için doğrudan live.txt alır.
# gau/waybackurls için scheme'siz host listesi üret
sed -E 's#^https?://##; s#/.*##' live.txt | sort -u > urls/hosts.txt
gau --threads 5 < urls/hosts.txt > urls/gau.txt # getallurls
waybackurls < urls/hosts.txt >> urls/gau.txt # wayback machine
katana -list live.txt -jc -d 3 -o urls/katana.txt # active crawl + JS
# Merge
cat urls/gau.txt urls/katana.txt | sort -u > urls/all_urls.txt# gau/waybackurls için scheme'siz host listesi üret
sed -E 's#^https?://##; s#/.*##' live.txt | sort -u > urls/hosts.txt
gau --threads 5 < urls/hosts.txt > urls/gau.txt # getallurls
waybackurls < urls/hosts.txt >> urls/gau.txt # wayback machine
katana -list live.txt -jc -d 3 -o urls/katana.txt # active crawl + JS
# Merge
cat urls/gau.txt urls/katana.txt | sort -u > urls/all_urls.txturinteresting ile filtrele (binlerce URL → sadece dikkat çekenler):
cat urls/all_urls.txt | urinteresting | sort -u > urls/interesting.txtcat urls/all_urls.txt | urinteresting | sort -u > urls/interesting.txtParametreli URL'ler (injection için altın madeni):
grep '=' urls/all_urls.txt | sort -u > urls/params.txtgrep '=' urls/all_urls.txt | sort -u > urls/params.txtÖrnek parametre → zafiyet eşlemesi:
?redirect=/?url=/?next=→ Open Redirect / SSRF.?id=/?file=/?page=→ IDOR / LFI / SQLi.- Else →
qsreplaceile değerleri toplu değiştirip fuzz et.
Faz 6 — JS Analysis (all_urls.txt → js_urls.txt → secrets)
bash
# 1) JS URL'lerini ayır
grep -iE '\.js($|\?)' urls/all_urls.txt | sort -u > js/js_urls.txt
katana -list live.txt -jc -silent | grep '\.js' | anew js/js_urls.txt# 1) JS URL'lerini ayır
grep -iE '\.js($|\?)' urls/all_urls.txt | sort -u > js/js_urls.txt
katana -list live.txt -jc -silent | grep '\.js' | anew js/js_urls.txt2) Endpoint + secret çıkar. Dikkat: jsluice stdin'den JS içeriği değil, dosya/URL listesi okur (satır başına bir dosya; remote HTTP URL'leri kendisi indirir). Yani curl ... | jsluice yanlıştır — doğrudan URL listesini veriyoruz:
cat js/js_urls.txt | jsluice urls | sort -u > js/js_endpoints.txt
cat js/js_urls.txt | jsluice secrets > js/js_secrets.txt
# LinkFinder (pipx ile global 'linkfinder' komutu):
linkfinder -i https://TARGET/main.js -o cli
# SecretFinder (venv):
~/tools/SecretFinder/venv/bin/python ~/tools/SecretFinder/SecretFinder.py -i https://TARGET/app.js -o clicat js/js_urls.txt | jsluice urls | sort -u > js/js_endpoints.txt
cat js/js_urls.txt | jsluice secrets > js/js_secrets.txt
# LinkFinder (pipx ile global 'linkfinder' komutu):
linkfinder -i https://TARGET/main.js -o cli
# SecretFinder (venv):
~/tools/SecretFinder/venv/bin/python ~/tools/SecretFinder/SecretFinder.py -i https://TARGET/app.js -o cli3) JS'i indir + trufflehog (yalnızca doğrulanmış / VERIFIED secret):
mkdir -p js/files && wget -q -i js/js_urls.txt -P js/files
trufflehog filesystem js/files --only-verifiedmkdir -p js/files && wget -q -i js/js_urls.txt -P js/files
trufflehog filesystem js/files --only-verifiedÇıktı Analizi:
apiKey/Bearer/AKIA...→ önce verify et (canlı mı, revoke mu?). "unverified" bulguyu rapora yazmadan önce test et.- Gizli
/api/v2/adminendpoint'i →urls/params.txt'e ekle, Faz 4'e geri besle. - Else →
.js.mapsource map var mı? Varsaunwebpack-sourcemapile orijinal kaynağı aç.
Faz 7 — Google Dorking (roots.txt → manuel)
Örnek:
site:target.com.tr ext:aspx
site:target.com.tr ext:asmx | ext:ashx | ext:config
site:target.com.tr inurl:login | inurl:admin | inurl:dashboard
site:target.com.tr intitle:"index of"
site:target.com.tr ext:pdf | ext:xls | ext:docx
"target.com.tr" -site:target.com.trsite:target.com.tr ext:aspx
site:target.com.tr ext:asmx | ext:ashx | ext:config
site:target.com.tr inurl:login | inurl:admin | inurl:dashboard
site:target.com.tr intitle:"index of"
site:target.com.tr ext:pdf | ext:xls | ext:docx
"target.com.tr" -site:target.com.trBağlantı: ext:aspx sonuçları Faz 8 için .NET hedeflerini doğrudan gösterir → viewstate/aspx.txt'e ekle.
Uyarı:_ Toplu otomatik dork = hızlı CAPTCHA / rate-limit. tek IP'den agresif gitme; manuel ya da küçük gruplar halinde çalıştır._
Faz 8 — ViewState & MachineKey (aspx.txt → RCE)
ASP.NET, __VIEWSTATE'i machineKey ile imzalar/şifreler. Key leak olmuşsa → geçerli ViewState forge → RCE.
badsecrets pipx ile kuruldu → global badsecrets komutu. Doğru bayrak --url'dir (-u değil). URL modunda badsecrets sayfaya bağlanır, __VIEWSTATE ve __VIEWSTATEGENERATOR'ı otomatik carve eder ve tüm known-key'lere karşı dener:
# aspx.txt'teki her hedefi tara (known/leaked key match)
while read -r url; do
echo "[*] $url"
badsecrets --url "$url"
done < viewstate/aspx.txt# aspx.txt'teki her hedefi tara (known/leaked key match)
while read -r url; do
echo "[*] $url"
badsecrets --url "$url"
done < viewstate/aspx.txtElde ham ViewState + generator değeri varsa (ör. Burp'ten aldın), blacklist3r modu ile doğrudan crack et:
# pip/pipx kurulumunda bazı örnekler ayrı komut olarak gelir (telerik-knownkey, symfony-knownkey).
# Generic ASP.NET viewstate için repo'daki blacklist3r örneği:
git clone https://github.com/blacklanternsecurity/badsecrets ~/tools/badsecrets 2>/dev/null
python ~/tools/badsecrets/examples/blacklist3r.py \
--viewstate "<VIEWSTATE_DEGERI>" --generator "<GENERATOR_DEGERI>"# pip/pipx kurulumunda bazı örnekler ayrı komut olarak gelir (telerik-knownkey, symfony-knownkey).
# Generic ASP.NET viewstate için repo'daki blacklist3r örneği:
git clone https://github.com/blacklanternsecurity/badsecrets ~/tools/badsecrets 2>/dev/null
python ~/tools/badsecrets/examples/blacklist3r.py \
--viewstate "<VIEWSTATE_DEGERI>" --generator "<GENERATOR_DEGERI>"crapsecrets ile çapraz kontrol (irsdl fork'unun known-key DB'si farklı olabilir):
cd ~/tools/crapsecrets
source venv/bin/activate # Faz 0'da kurduğumuz venv
# README'deki kullanım — badsecrets match'ini burada doğrula
deactivate && cd -cd ~/tools/crapsecrets
source venv/bin/activate # Faz 0'da kurduğumuz venv
# README'deki kullanım — badsecrets match'ini burada doğrula
deactivate && cd -Faz 9 — Burp Scan + Manuel Review (her hedef özelinde)
interesting_hosts.txt'teki her servis için standart set: dir fuzz + historical + Burp scan + tech-specific.
Her hedef için:
├─ Burp'te gez → Active Scan (auth + unauth)
├─ Passive bulguları triage et (false positive ele)
├─ fuzz/all.json + urls/interesting.txt'i Burp'e besle
└─ Tech-specific: .NET → ViewState | WP → wpscan | API → param fuzz├─ Burp'te gez → Active Scan (auth + unauth)
├─ Passive bulguları triage et (false positive ele)
├─ fuzz/all.json + urls/interesting.txt'i Burp'e besle
└─ Tech-specific: .NET → ViewState | WP → wpscan | API → param fuzzFaz 10 — Internet-Wide Tarama (scope.txt → internetdb/*.txt)
Pasif attack-surface genişletme: dışarıdaki veri kaynaklarını sorgulayıp yeni IP/port bulup önceki fazlara geri besleriz.
10.1 — Shodan InternetDB
internetdb.shodan.io API'si bir IP/hostname için açık portları, bilinen zafiyetleri (CVE) ve banner'ları JSON olarak döner (API key gerektirmez).
bash
for i in $(cat scope.txt); do
echo "[*] Querying Shodan InternetDB for $i"
curl -s "https://internetdb.shodan.io/$i" | jq -c . >> internetdb/shodan.txt
donefor i in $(cat scope.txt); do
echo "[*] Querying Shodan InternetDB for $i"
curl -s "https://internetdb.shodan.io/$i" | jq -c . >> internetdb/shodan.txt
doneÇıktıyı IP ve portlara ayır:
jq -r '.ip? // empty' internetdb/shodan.txt | grep -v null | sort -u > internetdb/ips_from_shodan.txt
jq -r '.ports[]?' internetdb/shodan.txt | sort -un > internetdb/ports_from_shodan.txtjq -r '.ip? // empty' internetdb/shodan.txt | grep -v null | sort -u > internetdb/ips_from_shodan.txt
jq -r '.ports[]?' internetdb/shodan.txt | sort -un > internetdb/ports_from_shodan.txt10.2 — Censys (API key gerekir)
for d in $(cat scope.txt); do
curl -s -u "$CENSYS_API_ID:$CENSYS_API_SECRET" \
"https://search.censys.io/api/v2/hosts/search?q=ssl.certificate.issuer.common_name:\"$d\"" \
| jq -c . >> internetdb/censys.txt
done
jq -r '.result.hits[]?.ip' internetdb/censys.txt | sort -u > internetdb/ips_from_censys.txtfor d in $(cat scope.txt); do
curl -s -u "$CENSYS_API_ID:$CENSYS_API_SECRET" \
"https://search.censys.io/api/v2/hosts/search?q=ssl.certificate.issuer.common_name:\"$d\"" \
| jq -c . >> internetdb/censys.txt
done
jq -r '.result.hits[]?.ip' internetdb/censys.txt | sort -u > internetdb/ips_from_censys.txt10.3 — Fofa (API key gerekir)
for d in $(cat scope.txt); do
curl -s "https://fofa.info/api/v1/search/all?email=$FOFA_EMAIL&key=$FOFA_KEY&q=domain=\"$d\"" \
| jq -c . >> internetdb/fofa.txt
done
jq -r '.results[]? | if type=="array" then .[0] else . end' internetdb/fofa.txt | sort -u > internetdb/ips_from_fofa.txtfor d in $(cat scope.txt); do
curl -s "https://fofa.info/api/v1/search/all?email=$FOFA_EMAIL&key=$FOFA_KEY&q=domain=\"$d\"" \
| jq -c . >> internetdb/fofa.txt
done
jq -r '.results[]? | if type=="array" then .[0] else . end' internetdb/fofa.txt | sort -u > internetdb/ips_from_fofa.txt10.4 — ZoomEye (API key gerekir)
for d in $(cat scope.txt); do
curl -s "https://api.zoomeye.org/host/search?query=$d" -H "Authorization: JWT $ZOOMEYE_TOKEN" \
| jq -c . >> internetdb/zoomeye.txt
done
jq -r '.matches[]?.ip' internetdb/zoomeye.txt | sort -u > internetdb/ips_from_zoomeye.txtfor d in $(cat scope.txt); do
curl -s "https://api.zoomeye.org/host/search?query=$d" -H "Authorization: JWT $ZOOMEYE_TOKEN" \
| jq -c . >> internetdb/zoomeye.txt
done
jq -r '.matches[]?.ip' internetdb/zoomeye.txt | sort -u > internetdb/ips_from_zoomeye.txt10.5 — Feedback: yeni IP'leri akışa geri besle
# Tüm dış kaynaklardan gelen IP'leri subs/ips.txt'e ekle (yalnızca yeni olanlar)
cat internetdb/ips_from_*.txt 2>/dev/null | sort -u | anew subs/ips.txt
# Yeni IP'ler üzerinden port tarama (Faz 2.5'i tekrar çalıştır — CDN filtresini unutma!)
sudo naabu -l subs/ips.txt -p - -rate 1000 -silent \
-nmap-cli 'nmap -sVC -Pn --open -oA nmap/full_internetdb'
# Yeni IP'lerden canlı web servislerini bul → live.txt'e ekle
while read -r ip; do echo "http://$ip"; echo "https://$ip"; done < subs/ips.txt \
| httpx -silent | anew live.txt# Tüm dış kaynaklardan gelen IP'leri subs/ips.txt'e ekle (yalnızca yeni olanlar)
cat internetdb/ips_from_*.txt 2>/dev/null | sort -u | anew subs/ips.txt
# Yeni IP'ler üzerinden port tarama (Faz 2.5'i tekrar çalıştır — CDN filtresini unutma!)
sudo naabu -l subs/ips.txt -p - -rate 1000 -silent \
-nmap-cli 'nmap -sVC -Pn --open -oA nmap/full_internetdb'
# Yeni IP'lerden canlı web servislerini bul → live.txt'e ekle
while read -r ip; do echo "http://$ip"; echo "https://$ip"; done < subs/ips.txt \
| httpx -silent | anew live.txtNot:_ InternetDB/Censys/Fofa/ZoomEye sonuçlarının scope içinde olduğunu mutlaka doğrula. Bu kaynaklar bazen paylaşımlı/CDN IP'leri veya ilgisiz asset'leri döndürür._
Özet Dosya Akışı (File Chain)
scope.txt
│ sort -u
▼
roots.txt ──subfinder/amass/crt.sh──► subs/subs_all.txt
│ │ dnsx -wd (wildcard temizliği)
│ ▼
│ subs/resolved.txt ──httpx──► live.txt ★
│ │ dnsx -a
│ ├──► subs/dns_map.txt (referans)
│ └──► subs/ips.txt ──[CDN filtre]──► naabu ►nmap/
▼ │
internetdb/* ──(yeni IP)──► subs/ips.txt ◄───────────────── feedback ◄───────────┘
(web portları → live.txt)
live.txt ─┬─ whatweb/httpx ──► tech.json ──► viewstate/aspx.txt ──► Faz 8 (badsecrets → RCE)
├─ ffuf/dirsearch ──► fuzz/
├─ gau/wayback/katana ──► urls/all_urls.txt ─┬─ urinteresting ──► urls/interesting.txt
│ └─ grep '=' ──────► urls/params.txt
├─ katana -jc ──► js/js_urls.txt ──► jsluice/trufflehog ──► js/js_secrets.txt
└─ gowitness ──► screenshots/scope.txt
│ sort -u
▼
roots.txt ──subfinder/amass/crt.sh──► subs/subs_all.txt
│ │ dnsx -wd (wildcard temizliği)
│ ▼
│ subs/resolved.txt ──httpx──► live.txt ★
│ │ dnsx -a
│ ├──► subs/dns_map.txt (referans)
│ └──► subs/ips.txt ──[CDN filtre]──► naabu ►nmap/
▼ │
internetdb/* ──(yeni IP)──► subs/ips.txt ◄───────────────── feedback ◄───────────┘
(web portları → live.txt)
live.txt ─┬─ whatweb/httpx ──► tech.json ──► viewstate/aspx.txt ──► Faz 8 (badsecrets → RCE)
├─ ffuf/dirsearch ──► fuzz/
├─ gau/wayback/katana ──► urls/all_urls.txt ─┬─ urinteresting ──► urls/interesting.txt
│ └─ grep '=' ──────► urls/params.txt
├─ katana -jc ──► js/js_urls.txt ──► jsluice/trufflehog ──► js/js_secrets.txt
└─ gowitness ──► screenshots/
İlgili Linkler
- urinteresting → https://github.com/tomnomnom/hacks/tree/master/urinteresting
- badsecrets → https://github.com/blacklanternsecurity/badsecrets
- crapsecrets → https://github.com/irsdl/crapsecrets
- jsluice → https://github.com/BishopFox/jsluice
- naabu → https://github.com/projectdiscovery/naabu
- Google Hacking DB → https://www.exploit-db.com/google-hacking-database?category=1
Bu workflow, tek bir scope.txt'ten başlayarak tüm external attack surface'i sistematik bir şekilde ortaya çıkarmanıza ve OSCP tarzı manuel testlerde yardımcı olacak şekilde tasarlandı. Dosya zinciri ve araçların entegrasyonu, tekrarlanabilir ve raporlanabilir bir pentest süreci sağlıyor.