
PhishCollector è un framework di ricerca per raccogliere, analizzare e tracciare siti di phishing.
PhishCollector è un framework di ricerca per raccogliere, analizzare e tracciare siti di phishing. È intenzionalmente progettato come punto di partenza: le regole di rilevamento, le firme tecnologiche, le wordlist e i plugin sono tutte strutture dati in chiaro che i ricercatori sono invitati a leggere, estendere e adattare al proprio panorama di minacce.
Invia un URL sospetto e PhishCollector:
Tutti i risultati sono accessibili tramite API REST, dashboard web e CLI.


cp .env.example .env # configure (see below)
docker compose up --build # starts db + app + frontend
| Servizio | URL |
|---|---|
| GUI | http://localhost:3000 |
| Documentazione API | http://localhost:8000/docs |
| DB | localhost:5432 |
Tutte le impostazioni sono variabili d'ambiente con il prefisso PHISH_. Copia .env.example in .env e modifica.
Instradare tutto il traffico in uscita attraverso un proxy mantiene nascosto l'IP dell'analista dal server di phishing.
PHISH_PROXY_URL=socks5://127.0.0.1:9050
PHISH_PROXY_SSL_VERIFY=true # Tor does not intercept TLS
Burp agisce come intermediario TLS e presenta il proprio certificato CA per ogni connessione HTTPS. Senza disabilitare la verifica SSL, ogni richiesta HTTPS attraverso il proxy fallirà.
PHISH_PROXY_URL=http://127.0.0.1:8080
PHISH_PROXY_SSL_VERIFY=false # required for Burp / intercepting proxies
Nota:
PHISH_PROXY_SSL_VERIFY=falseinfluisce solo sulle connessioni HTTPS in uscita effettuate dal backend Python (plugin, fingerprinter, spider). Il browser Playwright opera già conignore_https_errors=trueindipendentemente da questa impostazione.
Attenzione: Non impostare mai
PHISH_PROXY_SSL_VERIFY=falsesenza un proxy configurato — disabiliterà la validazione dei certificati per tutte le chiamate API esterne (URLhaus, VirusTotal).
Percorso base: /api/v1
Documentazione interattiva completa su /docs (Swagger UI).
curl -X POST http://localhost:8000/api/v1/collections \
-H 'Content-Type: application/json' \
-d '{"url": "https://suspicious-site.example.com", "use_wordlist": true}'
# Install (inside container or local venv with requirements.txt)
pip install -e .
# Invia un URL e attendi il completamento
phishcollector collect https://target.example.com --wait
# Con fuzzing tramite wordlist
phishcollector collect https://target.example.com --wordlist --wait
# Elenca i job recenti
phishcollector list
# Visualizza dettaglio completo
phishcollector detail <job-id>
# Scarica screenshot
phishcollector screenshot <job-id> -o capture.png
# Cerca per stack tecnologico / hash favicon / paese
phishcollector search --tech WordPress --country RU
phishcollector search --favicon-hash -1234567890
Richiede una chiave di autenticazione gratuita da auth.abuse.ch.
PHISH_URLHAUS_ENABLED=true
PHISH_URLHAUS_API_KEY=<your-auth-key>
Richiede una chiave API gratuita o a pagamento da virustotal.com.
PHISH_VIRUSTOTAL_API_KEY=<your-key>
Quando un URL non è ancora stato analizzato da VT, PhishCollector lo invia per la scansione e recupera automaticamente il risultato ogni 30 secondi fino a quando non viene risolto.
Ogni plugin è un singolo file in phishcollector/plugins/ che espone una funzione asincrona:
# phishcollector/plugins/myplugin.py
from . import CheckResult
async def check(url: str, proxy_url=None, ssl_verify=True) -> CheckResult:
# query your feed / API here
return CheckResult(
plugin_name="myplugin",
status="malicious", # malicious | suspicious | clean | unknown | error
score=0.95, # 0.0–1.0, or None
result={"raw": ...}, # stored as JSONB, displayed in the GUI
)
Quindi registralo in phishcollector/plugins/runner.py:
from .myplugin import check as myplugin_check
tasks.append(myplugin_check(url, proxy_url=settings.proxy_url, ssl_verify=settings.proxy_ssl_verify))
Non sono necessarie altre modifiche: il risultato viene automaticamente memorizzato, visualizzato nella dashboard e incluso nel punteggio di minaccia.
Il motore di rilevamento è intenzionalmente mantenuto come dati semplici e leggibili in modo che i ricercatori possano adattarlo ai kit e alle campagne che stanno tracciando. Tutto risiede in un unico file:
phishcollector/collector/fingerprint.py
PHISHING_PATTERNS — regole regex scansionate sull'HTML + JS renderizzatoOgni voce è una tupla (regex, etichetta_leggibile) raggruppata in categorie. Una corrispondenza in qualsiasi categoria viene visualizzata nella scheda Indicatori e contribuisce al punteggio di minaccia.
PHISHING_PATTERNS: dict[str, list[tuple[str, str]]] = {
"credential_harvest": [
(r"document\.getElementById\(['\"]password['\"]", "JS reads password field by ID"),
(r"btoa\s*\(.*password", "Base64-encoding a password"),
# add your own rules here …
],
"obfuscation": [
(r"\beval\s*\(", "eval() usage"),
(r"atob\s*\(", "Base64 decoding at runtime"),
],
"exfiltration": [
(r"api\.telegram\.org/bot", "Telegram bot exfiltration"),
(r"@(?:gmail|yahoo|hotmail|outlook)\.com", "Freemail address in code"),
],
"antibot": [
(r"navigator\.webdriver", "WebDriver property check"),
(r"ipqualityscore|ipqs\.com", "IPQS anti-bot service"),
],
"kit_indicators": [
(r"office365|microsoft365", "Office 365 phishing theme"),
(r"paypal.*limit|limit.*paypal", "PayPal limitation theme"),
# brand-new kit you spotted? add a rule here:
(r"docusign.*sign|e.?sign.*document", "DocuSign lure"),
(r"(?:dhl|fedex|ups).*track", "Parcel delivery lure"),
],
}
Per aggiungere una regola: aggiungi una tupla alla lista della categoria pertinente. Per aggiungere una categoria: aggiungi una nuova chiave — il nome della categoria appare automaticamente come intestazione di sezione nella scheda Indicatori.
# Example: track a newly discovered kit's fingerprint
"my_campaign_2024": [
(r"panel\.php\?cmd=send", "Known C2 panel path"),
(r"X-Mailer:\s*PHPMailer\s*5\.2\.1", "Specific PHPMailer version used by kit"),
],
TECH_SIGNATURES — rilevamento tecnologiaFirme confrontate con HTML, intestazioni delle risposte, cookie e URL finale. Le tecnologie rilevate appaiono nel pannello Tecnologie e sono ricercabili in tutte le raccolte.
TECH_SIGNATURES: dict[str, dict] = {
"WordPress": {
"html": [r"wp-content", r"wp-includes"],
"url": [r"/wp-login\.php"],
"cookies": ["wordpress_"],
},
# Add anything you want to track:
"GoPhish": {
"html": [r"rid=[a-zA-Z0-9]{20}"],
"url": [r"/track\?rid="],
},
"Evilginx": {
"url": [r"phishlets"],
"html": [r"__utmz.*evilginx"],
},
}
Ogni chiave della firma (il nome della tecnologia) diventa una stringa ricercabile tramite GET /search?technology=GoPhish.
La wordlist predefinita dello spider si trova in wordlists/phishing_paths.txt — un percorso per riga, # per i commenti. Contiene percorsi comuni dei kit di phishing (gate.php, send.php, result.php, pannelli admin, ecc.). Aggiungi percorsi per i kit che incontri regolarmente:
# Newly observed kit paths
/panel/send.php
/b374k.php
/uploads/gate.php
Content-Type: text/plain e Content-Disposition: attachment — il browser lo scarica invece di renderizzarlo.hmac.compare_digest per prevenire attacchi temporali.X-Frame-Options: DENY e Referrer-Policy: no-referrer.Gli artefatti vengono scritti in PHISH_DATA_DIR (predefinito /data, volume montato in Docker):
/data/
screenshots/ <collection-id>.png
html/ <collection-id>.html
assets/
<collection-id>/
<sha256-prefix>.js
<sha256-prefix>.css
Tutto il resto (fingerprint, log HTTP, risultati dello spider, risultati dei plugin, tag, note) risiede in PostgreSQL.
phishcollector/
collector/
browser.py # Playwright capture, stealth JS, UA rotation
fingerprint.py # All fingerprinting probes + PHISHING_PATTERNS + TECH_SIGNATURES
spider.py # Link extraction, robots.txt, sitemap, wordlist fuzzing
orchestrator.py # Job lifecycle: ties all modules together
plugins/
__init__.py # CheckResult dataclass
urlhaus.py # abuse.ch URLhaus plugin
virustotal.py # VirusTotal v3 plugin
runner.py # Runs enabled plugins concurrently
api/
routes.py # FastAPI endpoints
main.py # App entry point, CORS, auth middleware
models.py # SQLAlchemy ORM models
config.py # Pydantic settings (env vars)
database.py # Engine, session factory, schema migrations
frontend/
app.js # Vanilla JS SPA
style.css # Cyber terminal UI
nginx.conf # Reverse proxy + security headers
wordlists/
phishing_paths.txt # Default spider wordlist
# Start only the database
docker compose up db -d
# Run the API locally
pip install -r requirements.txt
playwright install chromium
uvicorn phishcollector.main:app --reload
# Run tests (if present)
pytest
| Variabile | Predefinito | Descrizione |
|---|
PHISH_DATABASE_URL | postgres://… | DSN PostgreSQL |
PHISH_API_KEY | (vuoto) | Se impostata, tutte le richieste richiedono X-API-Key: <valore> |
PHISH_DATA_DIR | /data | Radice di archiviazione per screenshot, HTML, asset |
PHISH_BROWSER_TIMEOUT | 30000 | Timeout caricamento pagina in ms |
PHISH_REQUEST_TIMEOUT | 15 | Timeout richiesta HTTP secondaria in secondi |
PHISH_MAX_SPIDER_PAGES | 50 | Numero massimo di URL visitati dallo spider per job |
PHISH_MAX_ASSET_SIZE | 10485760 | Dimensione massima file JS/CSS da memorizzare (byte) |
PHISH_PROXY_URL | (vuoto) | Proxy in uscita — vedi sotto |
PHISH_PROXY_SSL_VERIFY | true | Imposta false per proxy intercettanti — vedi sotto |
PHISH_URLHAUS_ENABLED | false | Abilita controllo reputazione URLhaus |
PHISH_VIRUSTOTAL_API_KEY | (vuoto) | Chiave API VirusTotal v3 (lascia vuoto per disabilitare) |
| Metodo | Percorso | Descrizione |
|---|
POST | /collections | Invia un URL per la raccolta |
GET | /collections | Elenca tutte le raccolte |
GET | /collections/{id} | Dettagli completi + fingerprint |
GET | /collections/{id}/screenshot | PNG a pagina intera |
GET | /collections/{id}/html | HTML catturato (scaricato come testo semplice) |
GET | /collections/{id}/requests | Registro delle richieste di rete |
GET | /collections/{id}/spider | Risultati dello spider |
GET | /collections/{id}/plugins | Risultati del plugin di threat intelligence |
POST | /collections/{id}/plugins/refresh | Riesegue i plugin (ad es. recupera risultato VT in sospeso) |
POST | /collections/{id}/rescan | Raccoglie nuovamente lo stesso URL (l'originale viene conservato) |
PATCH | /collections/{id} | Aggiorna tag e note |
GET | /collections/{id}/export?format=json|csv | Esporta dati della raccolta |
DELETE | /collections/{id} | Elimina una raccolta e tutti i suoi artefatti |
GET | /search | Cerca fingerprint per IP, hash del favicon, tecnologia, paese, titolo |