
Detection, mitigation, and reverse-engineering tooling for CVE-2026-41940 (SessionScribe): the cPanel/WHM unauthenticated session-forgery vulnerability disclosed 2026-04-28. Defense-in-depth active mitigation shim, ModSec rule pack, remote probe, on-host IOC scanner, and per-tier RE snapshot collector. GPL v2.
RCE critique non authentifié dans cPanel & WHM. Quatre requêtes HTTP forgent une session root via une injection CRLF dans le champ mot de passe d'une session de pré-authentification. Aucune authentification, aucune précondition, tous les tiers supportés affectés. Divulgué le 2026-04-28 par Sina Kheirkhah / watchTowr Labs.
Démarrage rapide · ioc-scan · mitigate · remote-probe · Versions affectées · Ordre de priorité
[!IMPORTANT] Les tiers 112, 114, 116, 120, 122, 128 n'ont pas de correctif éditeur. Chaque version sur ces tiers est vulnérable ; la mise à niveau ou la migration est la seule solution durable. En attendant : pare-feu TCP/2082, 2083, 2086, 2087, 2095, 2096 vers les CIDRs de gestion (
mitigate.sh --applyle fait) et protéger la surface restante avec le pack de règles ModSec.
Trois one-liners, dans l'ordre de priorité de l'opérateur :```bash
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-ioc-scan.sh | bash
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh | bash -s -- --apply
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-remote-probe.sh | bash -s -- --target HOST
Les codes de sortie sont conçus pour l'automatisation des flottes : `ioc-scan` renvoie `4` en cas de COMPROMIS, `1` en cas de VULNÉRABLE ; `mitigate` renvoie `0` (propre) / `1` (appliqué) / `2` (manuel) / `3` (erreur outil) ; `remote-probe` renvoie `2` si une cible est VULN.
---
## Outils
Par ordre de priorité opérationnelle. Chaque artefact produit une sortie structurée
(`--json` / `--jsonl` / `--csv`) indexée sur `host`, `os`, `cpanel_version`,
`ts` pour le regroupement de flotte.
| Outil | Rôle | Lieu d'exécution |
|---|---|---|
| **[`sessionscribe-ioc-scan.sh`](#sessionscribe-ioc-scansh---ioc-ladder--kill-chain)** | Triage de premier ordre. Échelle IOC, verdicts état-code + état-hôte, reconstruction de la chaîne de compromission, bundle IR. | sur l'hôte cPanel |
| **[`sessionscribe-mitigate.sh`](#sessionscribe-mitigatesh---mitigation-orchestrator)** | Fermer la fenêtre. Atténuation par phases : vérification des correctifs, pare-feu, proxysub, ModSec. | sur l'hôte cPanel |
| **[`sessionscribe-remote-probe.sh`](#sessionscribe-remote-probesh---non-destructive-fleet-probe)** | Collatéral de support. Sondage non destructif en 4 étapes → VULN/SAFE par hôte. | partout où `curl` est disponible |
| [`modsec-sessionscribe.conf`](#supporting-collateral) | Paquet de règles ModSec déployé par `mitigate`. | serveur frontal Apache |
| [`sessionscribe-revsnap.sh`](#supporting-collateral) | Collecteur d'instantanés RE par niveau pour le diffing binaire. | sur l'hôte cPanel, autour de `upcp` |
GPL v2. Tous les artefacts sont prêts pour `curl` via les URLs brutes ci-dessus.
---
## `sessionscribe-ioc-scan.sh` - Échelle IOC + chaîne de compromission
**Exécutez-le en premier.** Détection uniquement par défaut (rapide, adapté aux flottes) ;
ajoutez `--full` pour exécuter les phases forensiques en ligne (chronologie défensive, ingestion offensive,
réconciliation, rendu de la chaîne de compromission, bundle IR).```bash
# fast triage (detection only)
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-ioc-scan.sh | bash
# full kill-chain reconstruction inline
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-ioc-scan.sh | bash -s -- --full
# full + ship IR bundle to intake
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-ioc-scan.sh | bash -s -- --full --upload
# JSONL for SIEM ingest
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-ioc-scan.sh | bash -s -- --jsonl --quiet > host.jsonl
# host IOCs only - periodic post-patch sweep, last 7 days
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-ioc-scan.sh | bash -s -- --ioc-only --since 7
# replay forensic phases against a saved envelope (no re-scan)
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-ioc-scan.sh | bash -s -- --replay /var/cpanel/sessionscribe-ioc/<run_id>.json
Deux axes rapportent indépendamment. code_verdict (PATCHED /
VULNERABLE / INCONCLUSIVE) vient de la version, des motifs du source Perl,
et de l'empreinte du binaire cpsrvd. host_verdict (CLEAN /
SUSPICIOUS / COMPROMISED) vient de l'échelle d'IOC des fichiers de session,
de l'analyse des journaux d'accès, et des sondes de destruction Patterns A–G.
Un hôte patché peut toujours sortir avec le code 4 si une exploitation
antérieure a laissé des IOCs sur le disque.
Les sessions marquées avec nxesec_canary_<nonce> (laissées par la sonde
distante) sont classées comme PROBE_ARTIFACT et ne sont pas escaladées vers
COMPROMISED.
--full compile chaque IOC par rapport aux activations de défense et classifie
chacun comme PRE-DEFENSE, POST-DEFENSE, POST-PARTIAL, ou
UNDEFENDED, puis résume avec un verdict et un titre de retard de défense.
PRE-DEFENSE = l'hôte était ouvert à l'exploit lorsque l'indicateur est arrivé ;
POST-DEFENSE = dégâts collatéraux ou bruit de pré-atténuation.```
+-- CVE-2026-41940 / IC-5790 --------------------------------------------
| host cpanel.example.com ()
| cpanel unknown os unknown
| verdict COMPROMISED score 315 ioc-scan v2.5.0
| defenses patch x absent modsec + up csf + clean mitigate + ran
+------------------------------------------------------------------------
| -- PRE-DEFENSE (32 events) -- | 2026-03-25T09:43:19Z ! pattern X ioc_attacker_ip_2xx_on_cpsess 57 hit(s) (last 90d) from IC-5790 IPs returned 2xx on /cpsess/ paths - real exploitation | 2026-04-28T14:35:56Z ! pattern X ioc_cve_2026_41940_crlf_access_chain 15 CRLF-bypass chain(s) — POST /login 401 then GET /cpsess 2xx as root within 2s | 2026-04-28T16:38:45Z ! pattern E ioc_pattern_e_websocket_shell_hits 45 external IP(s) reached /cpsess*/websocket/Shell with 2xx | 2026-04-29T08:41:22Z ! pattern F ioc_pattern_f_smark_envelope S_MARK/E_MARK harvester envelope in /root/.bash_history | 2026-04-29T16:41:24Z ! pattern A ioc_pattern_a_ransom_readme /home/user1/README.md | … (22 more Pattern A ransom_readme events across customer homedirs) | 2026-04-29T16:42:09Z ! pattern A ioc_pattern_a_sorry_files_present 608 .sorry-encrypted files present | 2026-04-29T17:52:58Z ! pattern D ioc_pattern_d_acctlog_encrypted /var/cpanel/accounting.log.sorry
| -- DEFENSES -- | 2026-04-29T23:48:21Z + DEFENSE mitigate_first sessionscribe-mitigate.sh first run | 2026-04-29T23:48:21Z + DEFENSE csf csf.conf cpsrvd ports stripped | 2026-04-29T23:48:46Z + DEFENSE modsec modsec rule 1500030 installed
| -- POST-PARTIAL (1 event) -- | 2026-04-30T12:23:42Z ! pattern E ioc_pattern_e_handoff_burst_present 3 distinct external IPs each minted cpsess + reached websocket Shell within 15-min window
| HEADLINE | verdict COMPROMISED (score 315) | defense lag 37d 9h LATE (first IOC 2026-03-25T09:43:19Z, defense up 37d 9h later)
<details>
<summary><b>Référence des vérifications + phases forensiques + disposition du bundle</b> (cliquez pour développer)</summary>
| Vérification | Ce qu'elle fait |
|---|---|
| `version` | `cpanel -V` vs la liste des builds corrigés publiés - pilote `code_verdict` |
| `static-pattern` | Recherche dans `Cpanel/Session/*.pm` les motifs sentinelles post-correction (branche de décodage `no-ob:`) |
| `cpsrvd-fingerprint` | Inspection du binaire cpsrvd par rapport aux signatures des builds corrigés |
| `access-log` | Journaux Apache + cpsrvd pour les formes de trafic d'exploitation (`--no-logs` pour ignorer) |
| `session-store` | Parcours de `/var/cpanel/sessions/raw/` : IOCs du fournisseur + co-occurrence quadruple + heuristique d'horodatage falsifié (`--no-sessions` pour ignorer) |
| `destruction` | Sondages des motifs A à G : encrypteur `/root/sshd`, wipe mysql, index BTC, `nuclear.x86`, revendeur `sptadm`, moissonneur `__S_MARK__`, clés SSH suspectes (`--no-destruction-iocs` pour ignorer) |
| `probe` (opt-in) | GET marqueur unique vers `127.0.0.1:2087` - confirme que cpsrvd répond. **Ne** tente **pas** le contournement |
**Phases forensiques `--full`** (exécutées en ligne après la détection) :
| Phase | Ce qu'elle fait |
|---|---|
| `defense` | Horodate chaque couche de défense mise en place : patch cpanel, redémarrage de cpsrvd après patch, exécutions de mitigate, règles ModSec, fermetures de ports CSF/APF, proxysub, résumé `upcp` |
| `offense` | Horodate chaque indicateur de compromission observé (Motifs A–G + chaîne de contournement CRLF du Motif X) |
| `reconcile` | Par indicateur : la défense pertinente était-elle active lors de sa première apparition ? PRÉ-DÉFENSE / POST-DÉFENSE / POST-PARTIEL / NON DÉFENDU + delta temporel |
| `bundle` | Archive tar des artefacts bruts sous `/root/.ic5790-forensic/<TS>-<RUN_ID>/`, mode `0700` |
**Disposition du bundle** (`/root/.ic5790-forensic/<TS>-<RUN_ID>/`) :```
manifest.txt host/uid/cpv/run_id/window/cap
sessions.tgz /var/cpanel/sessions/{raw,preauth} (filtered)
access-logs.tgz cpsrvd access + incoming_http_requests + error_log
+ global Apache access/error (NO domlogs)
system-logs.tgz /var/log/{secure,messages,audit/audit.log,auth.log}*
cpanel-state.tgz accounting.log + resellers + cpanel.config + api_tokens_v2
cpanel-users.tgz /var/cpanel/users/ (split out, per-account state)
persistence.tgz ssh keys + all cron tiers + systemd/init.d/profile.d
+ rc.local + root histories + passwd/group + sudoers
defense-state.tgz mitigate backups + csf/apf/modsec configs + updatelogs
ps.txt / connections.txt / iptables.txt
pattern-a-binary-metadata.txt only if /root/sshd present (metadata; binary NOT bundled)
user-histories/ per-user .bash_history (gated on --no-history)
Bundle typique sur un hôte actif avec la fenêtre de 90 jours : ~250 Mo – 2 Go compressé.
Limite de 2 Go par tarball (--max-bundle-mb) supprime individuellement les candidats trop volumineux.
Un journal d'exécution est écrit dans /var/cpanel/sessionscribe-ioc/ par défaut (--no-ledger pour désactiver). --chain-forensic / --chain-on-critical / --chain-upload sont conservés comme alias de rétrocompatibilité v1.x.
Remplacements pour les tests d'instantanés pour l'analyse médico-légale hors ligne sur les tarballs extraits : --root DIR, --version-string S, --cpsrvd-path P. Voir --help pour la liste complète des options.
sessionscribe-mitigate.sh - orchestrateur de mitigationLecture seule par défaut (--check). Ajoutez --apply pour modifier l'état.
Idempotent : réexécuter sur un hôte sain ne fait rien. Les mutations écrivent des sauvegardes horodatées sous /var/cpanel/sessionscribe-mitigation/ avant de toucher à tout fichier.```bash
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh | bash
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh | bash -s -- --apply
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh | bash -s -- --apply --only modsec --probe curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh | bash -s -- --only patch,preflight # pre-upcp gate
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh | bash -s -- --csv > host.csv curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh | bash -s -- --jsonl > host.jsonl
| Phase | What it does |
|---|---|
| `patch` | `cpanel -V` par rapport à la liste publiée des builds patchés (incl. EL6 11.86.0.41, EL6/CL6 110.0.103, tier 124, WP² 136.1.7) |
| `preflight` | Supprime `/etc/yum.repos.d/threatdown.repo` ; s'assure que `epel-release` est présent ; désactive les dépôts non-base cassés pour que `upcp` ne meure pas en plein vol |
| `upcp` | Si non patché, lance `/scripts/upcp --force --bg` |
| `proxysub` | Active `proxysubdomains` + variante new-account ; reconstruit la configuration httpd |
| `csf` / `apf` / `runfw` | Supprime les ports cpsrvd (2082/2083/2086/2087/2095/2096) de `TCP_IN`/`TCP6_IN`/`IG_TCP_CPORTS` ; vérifie la chaîne INPUT iptables en direct |
| `apache` | `httpd` en cours d'exécution + `security2_module` chargé |
| `modsec` | `modsec2.user.conf` contient les règles `1500030` + `1500031` ; déployer si absent (sauvegarde horodatée, validation `httpd -t`, rechargement graceful) |
| `probe` (opt-in) | Exécute `sessionscribe-remote-probe.sh` contre `127.0.0.1` pour confirmer les refus en pratique |
Les dépôts CentOS / Alma / Rocky base/appstream/extras/updates/powertools ne sont **jamais** désactivés par `preflight`, même s'ils sont actuellement inaccessibles.
### Codes de sortie
| Exit | Meaning |
|---|---|
| 0 | propre - patché + posture ok, aucune action nécessaire |
| 1 | correction appliquée avec succès (`--apply` a effectué des modifications) |
| 2 | intervention manuelle requise (avertit dans `--check`, échoue dans `--apply`) |
| 3 | erreur de l'outil (mauvais arguments, dépendances manquantes, pas root pour `--apply`) |
Sélection de phase : `--only LIST`, `--no-PHASE`, `--no-fw` (abréviation pour `--no-csf --no-apf --no-runfw`). Sortie : `--json` / `--jsonl` / `--csv`, `-o FILE`. Voir `--help` pour la liste complète des options.
### Vérification rapide soixante secondes```bash
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh | bash -s -- --list-phases # surface the phase API
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh | bash -s -- --check # safe read-only audit
echo "exit=$?" # 0 on a non-cPanel host
L'orchestrateur détecte un hôte non-cPanel et se termine proprement — prouvant l'idempotence sans besoin d'un laboratoire.
sessionscribe-remote-probe.sh - sonde de flotte non destructiveDocumentation complémentaire. Exécute la chaîne en quatre étapes de manière non destructive contre une cible : mint preauth → CRLF inject → propagate raw→cache → verify via /json-api/version, puis se déconnecte activement. Le signal déterminant le verdict est le code HTTP à l'étape 4 : 200 ou 5xx avec un corps de licence, est VULN ; 401 ou 403 est SAFE.
Chaque session de test est étiquetée avec un attribut nxesec_canary_<nonce> pour le nettoyage forensique, et aucun appel API modifiant l'état n'est effectué. Les sessions forgées sont équivalentes à root pendant ~1–3s entre l'étape 3 et la déconnexion de l'étape 5 — consultez l'en-tête du script pour le modèle de sécurité complet.```bash
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-remote-probe.sh | bash -s -- --target 1.2.3.4
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-remote-probe.sh | bash -s -- --target 1.2.3.4 --proxy example.com
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-remote-probe.sh
| bash -s -- --csv $(awk '{print "--target "$1}' fleet.txt) > fleet.csv
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-remote-probe.sh | bash -s -- --target 1.2.3.4 --fingerprint-only
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-remote-probe.sh | bash -s -- --cleanup
Modes de sortie : pretty (par défaut), `-q`/`--quiet`, `--oneline`, `--csv`,
`--json`. Codes de sortie : `0` aucune VULN trouvée, `1` uniquement non concluant, `2`
une ou plusieurs VULN. Voir `--help` pour la liste complète des options incluant les
sémantiques de `--auto-host-discover`, `--all`, `--fingerprint-only`, et
le mode `--no-verify` réservé à la deuxième étape (hérité, produit des faux positifs sur les hôtes
corrigés).
---
## Documentation complémentaire
### `modsec-sessionscribe.conf` - Pack de règles ModSecurity
Déployé automatiquement par `mitigate.sh --apply --only modsec`. Installation manuelle :```bash
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/modsec-sessionscribe.conf \
| sudo tee /etc/apache2/conf.d/modsec/modsec2.user.conf >/dev/null
sudo apachectl -t && sudo /usr/local/cpanel/scripts/restartsrv_httpd
Plage d'ID réservée : 1500000–1500099. Les règles de jeton WHM utilisent @ipMatch
contre une liste de confiance définie par l'opérateur — modifiez les CIDR en haut du
fichier avant le déploiement.
[!IMPORTANT] Ces règles s'exécutent dans Apache.
cpsrvdécoute directement sur 2082/2083/2086/2087/2095/2096 et est accessible indépendamment d'Apache. Associez le pack de règles au pare-feu des ports cpsrvd vers les CIDR d'administration.
sessionscribe-revsnap.sh - Collecteur d'instantanés RECapture une archive par palier (binaires, chaînes, dynsym, désassemblage, modules Perl,
disposition d'exécution) pour la différenciation binaire entre les mises à niveau de cPanel.
Construit autour de upcp pour capturer des paires pré/post-correctif.```bash
curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-revsnap.sh | bash
/scripts/upcp --force curl -fsSL https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-revsnap.sh | bash
Generalises beyond SessionScribe: every future cpsrvd CVE will land in
roughly the same surface, and a tarball pair for the pre-patch and
patched build is the difference between hours and days of analysis.
See the [research article](https://rfxn.com/research/cpanel-sessionscribe-cve-2026-41940)
for the full RE walkthrough.
---
## Fleet usage
> [!TIP]
> Chaque artefact émet une sortie structurée (`--json`, `--jsonl`, `--csv`)
> avec `host`, `os`, `cpanel_version`, `ts` sur chaque enregistrement. Conçu
> pour `pdsh | jq` ou `ansible -m script` un regroupement sur des centaines de
> hôtes en une seule passe.
Même primitive curl-piped-bash — laissez chaque hôte récupérer et exécuter le dernier
script directement :```bash
IOC=https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-ioc-scan.sh
MIT=https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-mitigate.sh
PRB=https://raw.githubusercontent.com/rfxn/cpanel-sessionscribe/main/sessionscribe-remote-probe.sh
# IOC scan across fleet, JSONL to SIEM
for h in $(cat fleet.txt); do
ssh "$h" "curl -fsSL $IOC | bash -s -- --jsonl --quiet"
done | jq -c '.' > fleet-ioc.jsonl
# kill-chain reconciliation across fleet (no bundles on broad sweep)
ansible -i hosts cpanel -m shell \
-a "curl -fsSL $IOC | bash -s -- --full --no-bundle --jsonl" > fleet-forensic.jsonl
jq -r 'select(.phase=="summary" and .key=="verdict"
and .note=="COMPROMISED_PRE_DEFENSE") | .host' \
fleet-forensic.jsonl > pre-defense-hosts.txt
# bundle collection on the pre-defense subset
ansible -i pre-defense-hosts.txt all -m shell \
-a "curl -fsSL $IOC | bash -s -- --full --jsonl --bundle-dir /root/.ic5790-forensic"
# mitigation posture roll-up
pdsh -w cpanel-fleet "curl -fsSL $MIT | bash -s -- --jsonl --quiet" \
| jq -c 'select(.severity != "info")' > fleet-mitigate.jsonl
# remote probe sweep - exit 2 on any VULN (run from operator workstation)
curl -fsSL $PRB | bash -s -- --csv --quiet \
$(awk '{print "--target "$1}' fleet.txt) > fleet-probe.csv
La sonde est indépendamment sûre pour les flottes (sessions marquées canary, déconnexion active, aucun appel API modifiant l'état). Les scripts sur l'hôte respectent les indicateurs --quiet + sortie structurée afin que stdout soit propre pour l'analyseur.
Quatre requêtes HTTP, sans authentification, sans préconditions :```mermaid sequenceDiagram autonumber actor A as attacker participant C as cpsrvd participant S as session file A->>C: POST /login/?login_only=1 with user=root, pass=wrong C-->>A: Set-Cookie · whostmgrsession=NAME,OBHEX A->>C: GET / · Authorization Basic b64(root:x + CRLF payload) · Cookie minus OBHEX C->>S: writes pass=x, user=root, hasroot=1, ... (CRLFs land verbatim) C-->>A: HTTP 307 · Location /cpsess[10digits]/ A->>C: GET /scripts2/listaccts · cookie only C->>S: propagate raw to cache · forged keys now readable C-->>A: 401 token denied (side-effect already done) A->>C: GET /cpsess[token]/json-api/version C-->>A: 200 OK means VULN · 403 means SAFE
Le verdict est le code HTTP à la requête 4. Le fichier de session sur disque à
`/var/cpanel/sessions/raw/<sessname>` est le seul artefact médico-légal
a posteriori. La primitive complète (les deux asymétries constitutives —
`filter_sessiondata` pas sur tous les chemins d'écriture, l'encodeur
court-circuite en l'absence de `ob_part`) et l'argument architectural pour
l'application du point de terminaison proxy sont dans
l'[article de recherche](https://rfxn.com/research/cpanel-sessionscribe-cve-2026-41940).
---
## Indicateurs de compromission
Forme du fichier de session forgé (`/var/cpanel/sessions/raw/<sessname>` après
exploitation) :```
local_port=2087
hasroot=1
hulk_registered=1
pass=x
origin_as_string=address=127.0.0.1,app=whostmgrd,method=badpass
token_denied=1
local_ip_address=127.0.0.1
external_validation_token=cS9C19OfV0hCA4uD
cp_security_token=/cpsess6844364556
ip_address=127.0.0.1
user=root
tfa_verified=1
successful_internal_auth_with_timestamp=9999999999
port=39040
login_theme=cpanel
Une session de pré-authentification normale ne contient jamais pass=, hasroot=1, user=root, tfa_verified=1, ou successful_internal_auth_with_timestamp=. Toute combinaison de ces éléments avec origin_as_string=…method=badpass est un indicateur. Une valeur de timestamp falsifiée au-delà de now+365d (ex. 9999999999) est un indicateur indépendant.```bash
for f in /var/cpanel/sessions/raw/*; do
[ -f "$f" ] || continue
if grep -q '^token_denied=' "$f"
&& grep -q '^cp_security_token=' "$f"
&& grep -q '^origin_as_string=.*method=badpass' "$f"; then
echo "IOC0 hit: $f"
fi
done
Signal de journal d'accès : réponses réussies `200`/`302`/`307` sur
les chemins `/json-api/`, `/execute/` ou `/scripts2/` provenant d'IP sources
non de base sans `/login/` 200 précédent dans la même fenêtre de session.
---
## Versions concernées```
11.86.0.41 (EL6/CL7) 11.110.0.97 11.118.0.63 11.124.0.35
11.126.0.54 11.130.0.19 11.132.0.29 11.134.0.20
11.136.0.5 110.0.103 (EL6/CL6 from .50)
WP Squared: 136.1.7
Les niveaux exclus de la liste des correctifs du fournisseur n'ont aucun correctif sur place : 112, 114, 116, 120, 122, 128. Les hôtes de ces niveaux doivent être mis à niveau vers une version majeure corrigée, migrés, ou leurs écouteurs cpsrvd doivent être placés derrière un pare-feu jusqu'à ce qu'ils le soient.
11.86.0.41 (EL6/CL7) a été ajouté dans la révision de l'avis du 29/04 ; 11.130 est passé de .18 à .19 dans la même révision. Une révision ultérieure a ajouté 11.124.0.35 (comblant le précédent écart sur le niveau 124) et 110.0.103 comme cible de mise à niveau directe pour les hôtes EL6/CL6 encore sur v110.0.50.
Immédiat
sessionscribe-ioc-scan.sh sur l'ensemble du parc. Un hôte patché peut encore être compromis.À venir
modsec-sessionscribe.conf dans modsec2.user.conf avec la liste de confiance @ipMatch définie.Le cas architectural pour l'application du proxy-endpoint est le dernier tiers de l'article de recherche.
cpsrvd, cpsrvd.so, ou Cpanel/Session/*.pm. Le rétroportage fourni par cPanel pour votre niveau est le vrai correctif.proxysub + pare-feu de l'orchestrateur ainsi que le pack de règles ModSec réduisent le rayon d'explosion ; la mise à niveau ou la migration est la seule réponse durable.nxesec_canary_<nonce> pour le nettoyage, et se déconnecte activement.ioc-scan trouve des artefacts d'exploitation antérieure ; il ne les corrige pas. Considérez son verdict COMPROMISED comme un déclencheur pour une réponse complète, pas comme une conclusion.[!TIP] Vous avez trouvé un bug, un IOC manqué, un faux positif, ou avez des retours d'exploitation ? Ouvrez un ticket GitHub - les rapports de bugs, les variantes d'IOC observées sur le terrain, les détections manquées sur les hôtes patchés/non patchés, les faux positifs des règles ModSec et les retours généraux des opérateurs sont les bienvenus.
Les divulgations sensibles (preuves d'exploitation en cours, données clients, chaînes d'exploitation inédites non encore publiques) doivent être envoyées via Keybase ou email, pas via les tickets GitHub.
GPL v2. Voir les en-têtes de fichiers individuels.
Forgé lors de la réponse à l'incident SessionScribe - Ryan MacDonald, R-fx Networks.
| Sortie | État du code | État de l'hôte | Action de triage |
|---|
| 0 | CLEAN/PATCHED | CLEAN | aucun |
| 1 | VULNERABLE | (quelconque) | patcher cpsrvd |
| 2 | INCONCLUSIVE | (quelconque) | révision manuelle de l'état du code (aussi : erreur d'outil) |
| 3 | (quelconque) | SUSPICIOUS | examiner les journaux de session/d'accès |
| 4 | (quelconque) | COMPROMISED | IR complet ; bundle + upload |
| Règle | Surface | Action |
|---|
1500030 | CRLF dans le payload décodé Authorization: Basic | refuser, toutes les sources, tous les chemins |
1500031 | Cookie whostmgrsession sans suffixe ,OBHEX valide | refuser (défense en profondeur) |
1500010 | Authorization: WHM sur /json-api/, /execute/, /acctxfer*/ | refuser lorsque la source n'est pas dans la liste de confiance |
1500020 | Authorization: WHM sur la famille de dispatch WebSocket | refuser lorsque la source n'est pas dans la liste de confiance |
1500021 | Authorization: WHM sur le chemin de dispatch SSE | refuser lorsque la source n'est pas dans la liste de confiance |