# SECURITY-07 — Incident : webshell résiduel `aioseo.php` (remédiation complète)

**Date** : 2026-06-25
**Statut** : ✅ REMÉDIÉ ET VÉRIFIÉ
**Découverte** : scan sécurité multi-agents (malware / backups orphelins / PHP suspects) + revue perf.
**Gravité** : 🔴 CRITIQUE — le site était **encore compromis** (la remédiation de SECURITY-01 du 24/06 était incomplète).

## Ce qui a été trouvé
### 🔴 Webshell d'upload actif — `/var/www/toulouse/aioseo.php`
- 980 o, racine docroot, **HTTP 200 public**. Présent depuis **2024-03-02**, manqué au nettoyage du 24/06
  (nom déguisé en plugin « AIOSEO »).
- Uploader protégé par mot de passe `AsAjfkel!@` : `?pw=...&path=...` + POST `$_FILES['xaxa']` →
  `mkdir` arbitraire + `move_uploaded_file` n'importe où ; `?del` = auto-suppression.
- = porte d'entrée pour redéployer du malware. Très probablement l'outil derrière la réinjection de spam de sept. 2025.

### 🔴 Fichiers exposés — nos propres `.bak` de remédiation
- `wp-config.php.bak-20260624-{rotation,wpsc,redis}` (×3) **téléchargeables HTTP 200** → fuite des identifiants DB
  **rotés** + salts. Cause : le vhost protège `wp-config.php$` mais pas `wp-config.php.bak-…`.
- + `wp-cache-config.php.bak-…`, theme `functions.php.bak / single-artiste.php.bak ×2`, plugin pepille `*.bak ×3` (10 au total).

### 🟠 Résidus inertes
- `functions.php` (racine, 0 o, sept 2025) = stub vide. `aios-bootstrap.php` = bootstrap du plugin AIOS **supprimé**
  (inerte : `auto_prepend_file` vide, vérifié). `alfacgiapi/` (dossier vide, IOC). `uploads/2022/04/validationEngine.jquery.zip`
  (archive du malware BD-04 quarantiné). `uploads/aios/` (résidu AIOS).

## Remédiation appliquée (consentement utilisateur « GO remédiation complète »)
1. **Quarantaine locale forensique** AVANT suppression : `backup/incident-20260625/quarantine-prod-files.tar.gz`
   (15 fichiers) + `db-pre-cleanup-20260625.sql.gz`. Rien laissé sur le serveur.
2. **Suppression prod** : webshell + 2 stubs + 2 dossiers orphelins + archive malware + 10 `.bak`.
   → `aioseo.php` et `wp-config.bak` = **HTTP 404**, site 200.
3. **Durcissement vhost** : `<FilesMatch "(\.(bak|old|orig|save|swp|swo|sql|tmp|log|inc)([-.].*)?$)|(~$)"> Require all denied`.
   Testé : `.bak-DATE`, `.sql`, `.sql.gz` → 403 ; pages/sitemap → 200. Snapshot `snapshots/apache/toulouse.conf.after-bakdeny`.
4. **Rotation des secrets** (creds rotés ayant été exposés) : mot de passe DB (MySQL + wp-config atomiques) + `wp config shuffle-salts`.
   wp-config rechowné `www-data:www-data 644`. `wp db check` OK, site 200, cache purgé.

## Vérifications post-remédiation (toutes ✅)
- Racine = **core WP uniquement** (14 fichiers légitimes).
- Sweep signatures (move_uploaded_file / eval $_ / $_ as func / shells connus) : **0 webshell** hors code légitime (core, vendors PSR/guzzle/mpdf, Divi).
- **Aucun frère du webshell** (fenêtre mars 2024 vide). PHP dans uploads = uniquement cache Twig WPML orphelin (inerte, deny PHP actif).
- **Pas d'injection DB** : options autoload propres ; matchs posts (casino/cialis) = faux positifs (« spécialisé », sponsor « Casino »).
- **Aucun admin rogue** (les 5 légitimes : bastienhkt747, Communication, LRGD, refonte26, ResponsableTLO31). Cron www-data propre.
- **Aucun contenu pirate résiduel** (vérif 2026-06-25) : 0 page/post de spam publié (85 pages légitimes, 1 seul post = "article test" 2019), 0 spam en brouillon/corbeille (20 brouillons légitimes), 6 comptes tous connus (pas d'auteur 13 résiduel), 0 commentaire spam, aucun lien caché/doorway injecté. Curiosité bénigne : contenu réel attribué à "auteur 0" (artefact d'import, pas du spam).
- `auto_prepend_file` vide (pas de persistance). Aucun dump SQL / `.git` / `.env` exposé.

## Reste (non bloquant)
- ✅ FAIT (2026-06-25) : résidu WPML nettoyé (cache Twig + languages/wpml + 24 tables icl_ + 62 options). Cf SECURITY-06.
- Logs Apache ne remontent que ~3 mois → exploitation historique de `aioseo.php` (avant mars 2026) non vérifiable.
- Surveiller : si réapparition d'un fichier suspect en racine → re-auditer le vecteur (toute MAJ plugin tierce).

## Leçon
La remédiation initiale a quarantiné les backdoors connus mais a manqué `aioseo.php` (nom mimétique + date ancienne).
→ Toujours scanner par **signatures comportementales** (uploader/RCE) en plus des fichiers connus, et auditer **tous** les `.php` à la racine.
