
PhishCollector est un framework de recherche pour collecter, analyser et suivre les sites de phishing.
PhishCollector est un cadre de recherche pour collecter, analyser et suivre les sites de phishing. Il est intentionnellement conçu comme un point de départ — les règles de détection, les signatures technologiques, les listes de mots et les plugins sont tous des structures de données en clair que les chercheurs sont censés lire, étendre et adapter à leur propre paysage de menaces.
Soumettez une URL suspecte et PhishCollector va :
Tous les résultats sont accessibles via une API REST, un tableau de bord web et une CLI.


cp .env.example .env # configurer (voir ci-dessous)
docker compose up --build # démarre db + app + frontend
| Service | URL |
|---|---|
| GUI | http://localhost:3000 |
| API docs | http://localhost:8000/docs |
| DB | localhost:5432 |
Tous les paramètres sont des variables d'environnement avec le préfixe PHISH_. Copiez .env.example vers .env et ajustez.
Router tout le trafic sortant via un proxy permet de cacher l'IP de l'analyste au serveur de phishing.
PHISH_PROXY_URL=socks5://127.0.0.1:9050
PHISH_PROXY_SSL_VERIFY=true # Tor n'intercepte pas TLS
Burp agit comme un intermédiaire TLS et présente son propre certificat CA pour chaque connexion HTTPS. Sans désactiver la vérification SSL, chaque requête HTTPS via le proxy échouera.
PHISH_PROXY_URL=http://127.0.0.1:8080
PHISH_PROXY_SSL_VERIFY=false # requis pour Burp / proxys d'interception
Remarque :
PHISH_PROXY_SSL_VERIFY=falsen'affecte que les connexions HTTPS sortantes effectuées par le backend Python (plugins, empreinte numérique, explorateur). Le navigateur Playwright fonctionne déjà avecignore_https_errors=trueindépendamment de ce paramètre.
Avertissement : Ne définissez jamais
PHISH_PROXY_SSL_VERIFY=falsesans proxy configuré — cela désactiverait la validation des certificats pour tous les appels API externes (URLhaus, VirusTotal).
Chemin de base : /api/v1
Documentation interactive complète à /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}'
# Installer (dans le conteneur ou venv local avec requirements.txt)
pip install -e .
# Soumettre une URL et attendre la fin
phishcollector collect https://target.example.com --wait
# Avec fuzzing de liste de mots
phishcollector collect https://target.example.com --wordlist --wait
# Lister les tâches récentes
phishcollector list
# Voir les détails complets
phishcollector detail <job-id>
# Télécharger la capture d'écran
phishcollector screenshot <job-id> -o capture.png
# Rechercher par pile technologique / hash de favicon / pays
phishcollector search --tech WordPress --country RU
phishcollector search --favicon-hash -1234567890
Nécessite une Auth-Key gratuite depuis auth.abuse.ch.
PHISH_URLHAUS_ENABLED=true
PHISH_URLHAUS_API_KEY=<votre-cle-auth>
Nécessite une clé API gratuite ou payante depuis virustotal.com.
PHISH_VIRUSTOTAL_API_KEY=<votre-cle>
Lorsqu'une URL n'a pas encore été analysée par VT, PhishCollector la soumet pour analyse et récupère automatiquement le résultat toutes les 30 secondes jusqu'à résolution.
Chaque plugin est un fichier unique dans phishcollector/plugins/ qui expose une fonction asynchrone :
# phishcollector/plugins/myplugin.py
from . import CheckResult
async def check(url: str, proxy_url=None, ssl_verify=True) -> CheckResult:
# interroger votre flux / API ici
return CheckResult(
plugin_name="myplugin",
status="malicious", # malicious | suspicious | clean | unknown | error
score=0.95, # 0.0–1.0, ou None
result={"raw": ...}, # stocké en JSONB, affiché dans le GUI
)
Ensuite, enregistrez-le dans 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))
Aucune autre modification n'est nécessaire — le résultat est automatiquement stocké, affiché dans le tableau de bord et intégré dans le score de menace.
Le moteur de détection est intentionnellement conservé sous forme de données simples et lisibles afin que les chercheurs puissent l'adapter aux kits et campagnes qu'ils suivent. Tout se trouve dans un seul fichier :
phishcollector/collector/fingerprint.py
PHISHING_PATTERNS — règles regex analysées sur le HTML + JS renduChaque entrée est un tuple (regex, étiquette_lisible) regroupé par catégories. Une correspondance dans n'importe quelle catégorie est signalée dans l'onglet Indicateurs et compte dans le score de menace.
PHISHING_PATTERNS: dict[str, list[tuple[str, str]]] = {
"credential_harvest": [
(r"document\.getElementById\(['\"]password['\"]", "JS lit le champ mot de passe par ID"),
(r"btoa\s*\(.*password", "Encodage Base64 d'un mot de passe"),
# ajoutez vos propres règles ici ...
],
"obfuscation": [
(r"\beval\s*\(", "utilisation de eval()"),
(r"atob\s*\(", "décodage Base64 à l'exécution"),
],
"exfiltration": [
(r"api\.telegram\.org/bot", "Exfiltration via bot Telegram"),
(r"@(?:gmail|yahoo|hotmail|outlook)\.com", "Adresse e-mail gratuite dans le code"),
],
"antibot": [
(r"navigator\.webdriver", "Vérification de la propriété WebDriver"),
(r"ipqualityscore|ipqs\.com", "Service anti-bot IPQS"),
],
"kit_indicators": [
(r"office365|microsoft365", "Thème de phishing Office 365"),
(r"paypal.*limit|limit.*paypal", "Thème de limitation PayPal"),
# nouveau kit repéré ? ajoutez une règle ici :
(r"docusign.*sign|e.?sign.*document", "Leurre DocuSign"),
(r"(?:dhl|fedex|ups).*track", "Leurre de livraison de colis"),
],
}
Pour ajouter une règle : ajoutez un tuple à la liste de la catégorie concernée. Pour ajouter une catégorie : ajoutez une nouvelle clé — le nom de la catégorie apparaît automatiquement comme en-tête de section dans l'onglet Indicateurs.
# Exemple : suivre l'empreinte d'un kit nouvellement découvert
"my_campaign_2024": [
(r"panel\.php\?cmd=send", "Chemin de panneau C2 connu"),
(r"X-Mailer:\s*PHPMailer\s*5\.2\.1", "Version spécifique de PHPMailer utilisée par le kit"),
],
TECH_SIGNATURES — détection de technologiesSignatures analysées sur le HTML, les en-têtes de réponse, les cookies et l'URL finale. Les technologies détectées apparaissent dans le panneau Technologies et sont consultables dans toutes les collections.
TECH_SIGNATURES: dict[str, dict] = {
"WordPress": {
"html": [r"wp-content", r"wp-includes"],
"url": [r"/wp-login\.php"],
"cookies": ["wordpress_"],
},
# Ajoutez tout ce que vous voulez suivre :
"GoPhish": {
"html": [r"rid=[a-zA-Z0-9]{20}"],
"url": [r"/track\?rid="],
},
"Evilginx": {
"url": [r"phishlets"],
"html": [r"__utmz.*evilginx"],
},
}
Chaque clé de signature (le nom de la technologie) devient une chaîne consultable via GET /search?technology=GoPhish.
La liste de mots par défaut de l'explorateur se trouve dans wordlists/phishing_paths.txt — un chemin par ligne, # pour les commentaires. Elle contient des chemins courants de kits de phishing (gate.php, send.php, result.php, panneaux d'administration, etc.). Ajoutez des chemins pour les kits que vous rencontrez régulièrement :
# Chemins de kits nouvellement observés
/panel/send.php
/b374k.php
/uploads/gate.php
Content-Type: text/plain et Content-Disposition: attachment — le navigateur le télécharge au lieu de l'afficher.hmac.compare_digest pour prévenir les attaques temporelles.X-Frame-Options: DENY et Referrer-Policy: no-referrer.Les artefacts sont écrits dans PHISH_DATA_DIR (par défaut /data, volume monté Docker) :
/data/
screenshots/ <collection-id>.png
html/ <collection-id>.html
assets/
<collection-id>/
<sha256-prefix>.js
<sha256-prefix>.css
Tout le reste (empreintes numériques, journaux HTTP, résultats d'exploration, résultats de plugins, tags, notes) réside dans PostgreSQL.
phishcollector/
collector/
browser.py # Capture Playwright, JS furtif, rotation UA
fingerprint.py # Toutes les sondes d'empreinte + PHISHING_PATTERNS + TECH_SIGNATURES
spider.py # Extraction de liens, robots.txt, sitemap, fuzzing de liste de mots
orchestrator.py # Cycle de vie des tâches : assemble tous les modules
plugins/
__init__.py # Dataclass CheckResult
urlhaus.py # Plugin URLhaus de abuse.ch
virustotal.py # Plugin VirusTotal v3
runner.py # Exécute les plugins activés en parallèle
api/
routes.py # Points de terminaison FastAPI
main.py # Point d'entrée de l'application, CORS, middleware d'authentification
models.py # Modèles ORM SQLAlchemy
config.py # Paramètres Pydantic (variables d'environnement)
database.py # Moteur, fabrique de sessions, migrations de schéma
frontend/
app.js # SPA vanilla JS
style.css # Interface utilisateur cyber terminal
nginx.conf # Proxy inverse + en-têtes de sécurité
wordlists/
phishing_paths.txt # Liste de mots par défaut de l'explorateur
# Démarrer uniquement la base de données
docker compose up db -d
# Exécuter l'API localement
pip install -r requirements.txt
playwright install chromium
uvicorn phishcollector.main:app --reload
# Exécuter les tests (si présents)
pytest
| Variable | Défaut | Description |
|---|
PHISH_DATABASE_URL | postgres://… | DSN PostgreSQL |
PHISH_API_KEY | (vide) | Si défini, toutes les requêtes nécessitent X-API-Key: <valeur> |
PHISH_DATA_DIR | /data | Racine de stockage pour les captures d'écran, HTML, ressources |
PHISH_BROWSER_TIMEOUT | 30000 | Délai d'attente de chargement de page en ms |
PHISH_REQUEST_TIMEOUT | 15 | Délai d'attente des sous-requêtes HTTP en secondes |
PHISH_MAX_SPIDER_PAGES | 50 | Nombre max d'URLs visitées par l'explorateur par tâche |
PHISH_MAX_ASSET_SIZE | 10485760 | Taille max de fichier JS/CSS à stocker (octets) |
PHISH_PROXY_URL | (vide) | Proxy sortant — voir ci-dessous |
PHISH_PROXY_SSL_VERIFY | true | Mettre à false pour les proxys d'interception — voir ci-dessous |
PHISH_URLHAUS_ENABLED | false | Activer la vérification de réputation URLhaus |
PHISH_VIRUSTOTAL_API_KEY | (vide) | Clé API VirusTotal v3 (laisser vide pour désactiver) |
| Méthode | Chemin | Description |
|---|
POST | /collections | Soumettre une URL pour collecte |
GET | /collections | Lister toutes les collectes |
GET | /collections/{id} | Détail complet + empreinte numérique |
GET | /collections/{id}/screenshot | PNG pleine page |
GET | /collections/{id}/html | HTML capturé (téléchargé en texte brut) |
GET | /collections/{id}/requests | Journal des requêtes réseau |
GET | /collections/{id}/spider | Résultats de l'explorateur |
GET | /collections/{id}/plugins | Résultats des plugins de renseignement sur les menaces |
POST | /collections/{id}/plugins/refresh | Relancer les plugins (ex. récupérer un résultat VT en attente) |
POST | /collections/{id}/rescan | Re-collecter la même URL (l'original est conservé) |
PATCH | /collections/{id} | Mettre à jour les tags et notes |
GET | /collections/{id}/export?format=json|csv | Exporter les données de la collecte |
DELETE | /collections/{id} | Supprimer une collecte et tous ses artefacts |
GET | /search | Rechercher des empreintes numériques par IP, hash de favicon, technologie, pays, titre |