Explorer
KNOW-PAT-056

OSINT web - Investigation avec Hunchly et scraping de navigateurs

Domaine
cybersecu
Type
pattern
Priorité
P2

Parent : [[INDEX-CYBERSECU]]

OSINT web - Investigation avec Hunchly et scraping de navigateurs

Problème

L'archive Ygg contient une base de données Hunchly (hunchly.db) et des exports Scooby (scooby.csv) qui documentent une investigation web approfondie. Les opérateurs du site surveillaient activement les utilisateurs et les concurrences via scraping de navigateurs et outils d'investigation.

Contexte archive Ygg

  • Fichier : 02_SERVEUR_PRE_PROD/forensics/hunchly.db
  • Fichier : 02_SERVEUR_PRE_PROD/forensics/scooby.csv
  • Fichier : 02_SERVEUR_PRE_PROD/forensics/hunchlylog.txt
  • Navigateurs : Chrome History, Login Data, Preferences, Web Data
  • Extension : Hunchly (outil d'investigation web pour OSINT)

Technique d'investigation

1. Hunchly Database

Hunchly capture automatiquement :

  • Pages web visitées (HTML complet)
  • Sélecteurs (éléments DOM ciblés)
  • Notes de l'investigateur
  • Timestamps de visite
  • Screenshots de pages
  • PDFs téléchargés

L'opérateur du site l'utilisait pour :

  • Tracker les utilisateurs suspects
  • Documenter les preuves d'abus
  • Archiver les communications externes

2. Scraping de navigateurs (Chrome)

navigateurs/chrome/
├── History              → Historique de navigation complet
├── Login Data         → Identifiants sauvegardés (chiffrés)
├── Preferences        → Settings, extensions, cookies
├── Web Data           → Autofill, cartes de crédit, adresses
├── Local State        → État local, profils
├── Cookies            → Sessions de tous les sites visités
├── Bookmarks          → Signets
├── metamask_idb       → Vault MetaMask (IndexedDB)
├── phantom_vault      → Vault Phantom
└── tornadocash_idb   → Données Tornado Cash

Solution protectif — Défendre contre l'OSINT adverse

1. Détection d'outils d'investigation

// detect-osint-tools.js — Détecter les outils d'investigation
function detectOSINTTools() {
  const indicators = {
    // Hunchly
    hunchly: () => document.querySelector('[data-hunchly]') !== null,
    
    // Autres outils OSINT
    maltego: () => navigator.userAgent.includes('Maltego'),
    spiderfoot: () => document.querySelector('.spiderfoot') !== null,
    
    // Screenshot tools
    screenshot: () => {
      const w = window.outerWidth;
      const h = window.outerHeight;
      // Résolutions anormales = screenshot tools
      return (w > 4000 || h > 4000) || (w < 800 && h < 600);
    }
  };
  
  const detected = Object.entries(indicators)
    .filter(([name, check]) => check())
    .map(([name]) => name);
  
  if (detected.length > 0) {
    reportSecurityEvent('osint_tool_detected', { tools: detected });
  }
  
  return detected;
}

2. Protection contre le scraping navigateur

// anti-scraping.js — Protection navigateur
class BrowserDataProtector {
  // Effacer les données sensibles avant fermeture
  static clearSensitiveData() {
    // IndexedDB
    const dbs = ['metamask', 'phantom', 'tornado'];
    dbs.forEach(db => {
      indexedDB.deleteDatabase(db);
    });
    
    // localStorage/sessionStorage
    Object.keys(localStorage).forEach(key => {
      if (key.includes('wallet') || key.includes('vault') || key.includes('seed')) {
        localStorage.removeItem(key);
      }
    });
    
    // Cookies sensibles
    document.cookie.split(';').forEach(cookie => {
      const [name] = cookie.split('=');
      if (name.trim().includes('session') || name.trim().includes('auth')) {
        document.cookie = `${name.trim()}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
      }
    });
  }
  
  // Détecter l'accès aux données
  static setupProtection() {
    // Surveiller l'accès à localStorage
    const original = Storage.prototype.getItem;
    Storage.prototype.getItem = function(key) {
      if (key.includes('wallet') || key.includes('vault')) {
        console.warn(`🚨 Accès aux données sensibles: ${key}`);
      }
      return original.call(this, key);
    };
  }
}

// Au unload
window.addEventListener('beforeunload', () => {
  BrowserDataProtector.clearSensitiveData();
});

3. Pour les utilisateurs — OPSEC basique

## Règles d'or

1. **Navigateur dédié** : Un navigateur pour les activités sensibles, un autre pour le quotidien
2. **Containers** : Firefox Multi-Account Containers (isolation par site)
3. **VPN + DNS** : Jamais de DNS du FAI pour les sites sensibles
4. **Pas d'autofill** : Désactiver l'autofill de mots de passe et cartes
5. **Extensions minimales** : Uniquement uBlock Origin + HTTPS Everywhere
6. **Session courte** : Fermer le navigateur après chaque session sensible
7. **Mode privé** : Utiliser le mode privé pour les recherches sensibles
8. **Pas de sync** : Désactiver la synchronisation Chrome/Firefox
9. **User-Agent** : Utiliser un User-Agent commun (pas de personnalisation)
10. **Canvas blocker** : Bloquer le fingerprinting canvas/WebGL

4. Pour les développeurs — Détection de scraping

# anti_scraping.py — Détection de scraping sur un site web
from flask import request, abort
import redis
import time

class ScrapingDetector:
    def __init__(self):
        self.redis = redis.Redis()
    
    def detect_scraping(self):
        ip = request.remote_addr
        user_agent = request.headers.get('User-Agent', '')
        
        # Signaux de scraping
        signals = []
        
        # 1. User-Agent vide ou générique
        if not user_agent or user_agent in ['Mozilla/5.0', 'curl', 'wget']:
            signals.append('suspicious_ua')
        
        # 2. Trop de requêtes rapides
        key = f"req_count:{ip}"
        count = self.redis.incr(key)
        self.redis.expire(key, 60)
        
        if count > 100:
            signals.append('rate_abuse')
        
        # 3. Pas de Referer
        if not request.headers.get('Referer'):
            signals.append('no_referer')
        
        # 4. Header Accept manquant ou générique
        accept = request.headers.get('Accept', '')
        if '*/*' in accept and len(accept) < 20:
            signals.append('generic_accept')
        
        # 5. Pas de JavaScript (détection par challenge)
        # Vérifier si le client a résolu un challenge JS
        js_challenge = request.cookies.get('js_challenge')
        if not js_challenge:
            signals.append('no_js_challenge')
        
        # Score
        score = len(signals) * 25
        
        if score >= 75:
            # Probable scraping
            log_security_event('scraping_detected', {
                'ip': ip,
                'signals': signals,
                'score': score,
                'path': request.path
            })
            
            if score >= 100:
                abort(429, 'Too many requests')
        
        return score < 75

Checklist de validation

  • Navigateur dédié aux activités sensibles
  • Containers/isolation par site
  • Autofill désactivé
  • Sync désactivée
  • Cookies effacés après session
  • IndexedDB/localStorage nettoyés
  • VPN actif pour les sites sensibles
  • User-Agent standard (pas personnalisé)
  • Canvas/WebGL fingerprinting bloqué
  • Pas d'extensions inconnues

Comment se prot[ée]ger (c[ot[ee] cible)

  • Minimiser la surface d'information publique (OSINT hygiene)
  • Supprimer les metadata EXIF des photos publi[ée]es
  • Utiliser des alias s[ée]par[ée]s pour diff[ée]rents contextes
  • Monitoring de sa propre empreinte (Google alerts, Mention)

Références