
Scanner ad alta fedeltà per CVE-2026-41940 (bypass dell'autenticazione di cPanel & WHM)
Uno scanner ad alta fedeltà per il bypass dell'autenticazione cPanel/WHM tracciato come CVE-2026-41940. Identifica gli host vulnerabili senza produrre i falsi negativi comuni nei proof-of-concept e nelle rilevazioni pubbliche, e senza innescare i meccanismi di blocco dell'account e di allowlist degli IP root che interferiscono con la scansione ingenua.
Il tool include anche una catena exploit separata e opzionale per un bug di path traversal CalDAV della stessa famiglia su cpdavd (porte 2079 in chiaro / 2080 TLS) — CVE-2026-29205 — che consente a un attaccante remoto di leggere file arbitrari come root una volta che un breve passaggio di configurazione guidato da SMTP ha successo. cPanel 11.134.0.26 corregge il bug di durata RAII sottostante, quindi la lettura ora viene eseguita come proprietario dell'account senza privilegi; la traversal stessa raggiunge ancora cpdavd ma non può elevarsi oltre ciò che quell'account può già leggere. La catena CalDAV è controllata da --exploit ed è disattivata di default perché invia email reali e legge file da target confermati — vedere la sezione Modalità exploit (attiva).
La maggior parte delle rilevazioni pubbliche per CVE-2026-41940 presenta tre problemi. Questo scanner li affronta tutti.
Puoi leggere il nostro post sul blog su questa tecnica di rilevazione qui: https://slcyber.io/research-center/high-fidelity-check-for-the-cpanel-authentication-bypass-cve-2026-41940/
La configurazione Apache per-vhost di cPanel installa una ProxyPass che inoltra /___proxy_subdomain_whm a 127.0.0.1:2086 e /___proxy_subdomain_cpanel a 127.0.0.1:2080 indipendentemente dall'header Host della richiesta. La RewriteCond vincola solo la riscrittura che mappa il sottodominio di gestione sul percorso proxy; la ProxyPass stessa è incondizionata. Colpire questi percorsi su qualsiasi vhost servito da un Apache gestito da cPanel raggiunge lo stesso backend vulnerabile delle porte di gestione.
Gli scanner che sondano solo le porte 2082/2083/2086/2087 segnaleranno un host come non vulnerabile quando quelle porte sono filtrate da firewall, anche se il bug è pienamente raggiungibile tramite la 443. Questo scanner sonda 2087, 2083 e i due percorsi proxy sulla 443 di default.
cPanel include cphulkd, che blocca gli account dopo un piccolo numero di tentativi di autenticazione falliti, e authorized_whm_root_ips, che limita i login di root a un elenco configurato di indirizzi sorgente. Uno scanner che sfrutta il bypass tentando di iniettare una sessione per root:
Questo scanner evita entrambi i problemi sul lato WHM iniettando expired=1 nel payload della sessione con un nome utente generato casualmente. L'iniezione della sessione viene verificata visitando l'URL cpsessXXXX risultante e cercando msg_code:[expired_session] nel corpo della risposta, che è presente solo quando l'iniezione ha avuto successo. Nessun account reale viene preso di mira, quindi nessun account reale può essere bloccato, e l'allowlist di root è irrilevante perché non viene tentato alcun login di root.
Il demone cPanel (cpaneld, porte 2083 e percorso /___proxy_subdomain_cpanel) richiede che il nome utente fornito corrisponda a un account cPanel esistente su disco (-f /var/cpanel/users/$user). Un nome utente root non soddisferà mai questo controllo perché root è un utente di sistema, non un utente cPanel. Le rilevazioni che provano solo root producono falsi negativi su questa superficie. Questo scanner usa una wordlist configurabile di nomi utente cPanel comuni contro la superficie cPanel e ripiega sul percorso con nome utente casuale sulla superficie WHM, che non ha tale restrizione.
Per ogni target lo scanner esegue i seguenti passaggi per ogni superficie:
GET /login e legge l'header Set-Cookie per whostmgrsession (WHM) o cpsession (cPanel). Il cookie contiene un componente del nome di sessione separato da virgole.GET / con un header Authorization: Basic il cui valore decodificato è <user>:\xff\nexpired=1. Il \nexpired=1 finale è il payload dell'iniezione di sessione. Il cookie di sessione del passaggio 1 viene riproposto senza modifiche.Location dalla risposta ed estrae il token cpsessXXXX.GET /<cpsessXXXX>/ con il cookie originale e cerca msg_code:[expired_session] nel corpo. La sua presenza dimostra che l'iniezione di sessione è riuscita e che l'host è vulnerabile.Sulla WHM (porta 2087 e percorso /___proxy_subdomain_whm sulla 443) il nome utente è una u casuale seguita da dieci caratteri esadecimali. Su cPanel (porta 2083 e percorso /___proxy_subdomain_cpanel sulla 443) lo scanner scorre la sua wordlist di nomi utente e si ferma alla prima corrispondenza.
Di default lo scanner sonda 2087, 2083 e 443 in quest'ordine e si ferma non appena una qualsiasi superficie conferma la vulnerabilità.
--exploit)CVE-2026-29205 — Aggiornamento di sicurezza cPanel/WHM WP2, 13 maggio 2026. Corretto in cPanel 11.134.0.26. L'avviso traccia la stessa regressione del privilege drop di
cpdavdche questa catena exploit sfrutta.
Analisi completa del bug e della catena di sfruttamento: https://slcyber.io/research-center/new-age-of-collisions-reading-arbitrary-files-pre-auth-as-root-in-cpanel-cve-2026-29205
cpdavd sulle porte 2079 (HTTP in chiaro) e 2080 (TLS) si fida del percorso <principal>/<collection>/... che costruisce quando serve risorse CalDAV/CardDAV. Creando una richiesta il cui componente del percorso codifica segmenti .. e puntandola a una cartella maildir il cui nome su disco codifica anch'esso una traversal (x-attachment-1-y), cpdavd può essere costretto a leggere qualsiasi file su disco come root, indipendentemente da proprietario o permessi — inclusi /etc/shadow, /etc/passwd e le mailbox per utente.
La difesa in profondità che avrebbe dovuto ridurre i privilegi al proprietario dell'account prima della lettura è fallita silenziosamente: l'oggetto Cpanel::AccessIds::ReducedPrivileges veniva costruito in contesto void, quindi il suo distruttore ripristinava i privilegi di root prima che la lettura venisse eseguita. cPanel 11.134.0.26 lega l'oggetto a una variabile lessicale my $privs così che viva per tutta la catena -f / stat / open / read; sugli host corretti la lettura viene quindi eseguita come proprietario dell'account senza privilegi invece che come root.
La cartella vulnerabile deve esistere su disco prima che la lettura funzioni. cPanel crea automaticamente una cartella denominata .x-attachment-1-y per il destinatario <user>+x-attachment-1-y@<domain> la prima volta che un'email arriva a quel sotto-indirizzo. La catena è quindi:
info, admin, webmaster).<prefix>+x-attachment-1-y@<domain> a ogni candidato. Vengono tracciate le risposte RCPT TO accettate.GET di path traversal contro cpdavd sulle porte 2080 (TLS) e 2079 (in chiaro), con entrambi i prefissi di raccolta /calendar/ e /addressbook/.Un successo restituisce i byte del file; il finding registra l'email usata, la raccolta, il numero di byte e i primi 200 byte come anteprima.
Questo controllo è disabilitato a meno che non venga passato --exploit. Quando è abilitato richiede un relay SMTP di uscita funzionante (vedi File di configurazione sotto) perché il passaggio di creazione della cartella non può essere saltato.
L'exploit funziona solo contro veri account di posta virtuale configurati tramite la funzionalità Email Accounts di cPanel. Gli indirizzi catch-all non funzionano: un catch-all viene instradato tramite il router system_aliases di Exim, non raggiunge mai il transport dovecot_virtual_delivery e quindi non innesca mai il percorso lda_mailbox_autocreate che produce la cartella .x-attachment-1-y/.
Quando conosci già un'email virtuale valida sul target, passala con --email:
python scanner.py --config scanner.ini --email [email protected] target.com
--email salta completamente l'enumerazione dei SAN del certificato e la wordlist dei prefissi e invia esattamente un messaggio all'indirizzo fornito. Può essere ripetuto per prendere di mira più account noti. Il percorso mirato è molto più affidabile del percorso spray.
Senza --email, lo scanner ripiega su uno spray di ~15 prefissi comuni (info, admin, webmaster, ecc.) per ogni dominio estratto dal certificato TLS dell'host. La misurazione di Assetnote su un campione di 200 host esposti a cpdavd ha mostrato un tasso di successo dello spray di ~10%: un risultato pulito dalla modalità spray è una prova debole che l'host è stato patchato, e rieseguire con --email contro un account reale è l'unico modo affidabile per confermarlo.
La modalità exploit legge un file INI tramite --config:
python scanner.py --config scanner.ini --exploit example.com
Copia scanner.ini.example in scanner.ini, inserisci le credenziali SMTP e, opzionalmente, regola i valori predefiniti CalDAV. scanner.ini è in .gitignore, quindi la copia compilata rimane in locale. La password SMTP può essere fornita anche tramite la variabile d'ambiente SCANNER_SMTP_PASSWORD, che ha precedenza solo quando il campo password nel file è vuoto.
pip install -r requirements.txt
È richiesto Python 3.8 o successivo.
Target singolo:
python scanner.py example.com
Più target tramite argomenti posizionali:
python scanner.py host-a.example.com host-b.example.com:2083
Un file di target, uno per riga. Le righe che iniziano con # vengono ignorate:
python scanner.py -f targets.txt
Lettura dei target da stdin:
cat targets.txt | python scanner.py
Un target può essere un nome host o host:porta. Quando viene specificata una porta, lo scanner sonda solo quella porta; altrimenti sonda 2087, 2083 e 443.
-u, --users — nomi utente cPanel separati da virgola da provare sulla superficie
cPanel. Il default è una piccola lista integrata.-U, --users-file — file con un nome utente cPanel per riga.-p, --ports — porte separate da virgola da sondare quando nessuna porta è specificata
sul target. Il default è 2087,2083,443.-t, --threads — thread per target usati per scorrere l'elenco di nomi utente
contro la superficie cPanel. Il default è 10.-c, --concurrency — numero di target scansionati in parallelo. Il default è 20.-T, --timeout — timeout per richiesta in secondi. Il default è 15.-o, --output — aggiunge i target vulnerabili, uno per riga, a questo file
man mano che vengono scoperti.--json — scrive un record JSON Lines per target in questo file.-q, --quiet — stampa solo i target vulnerabili su stdout. I fallimenti di connessione
e i target puliti vengono comunque registrati in --json e contati nel riepilogo.Una riga viene scritta su stdout per ogni finding, quindi un target che esegue entrambi i controlli stamperà due volte:
[!] host cve-2026-41940 VULNERABLE (port 443)
[!] host caldav-traversal VULNERABLE via admin@host (read 1842b from /etc/passwd)
[+] host cve-2026-41940 NOT VULNERABLE
[?] host cve-2026-41940 CONNECTION FAILED
L'output --json è un record per target con un array findings:
{"target": "host", "status": "VULNERABLE", "findings": [
{"check": "cve-2026-41940", "status": "VULNERABLE", "detail": {"port": 443}},
{"check": "caldav-traversal", "status": "VULNERABLE",
"detail": {"email": "admin@host", "domain": "host", "collection": "calendar",
"file": "/etc/shadow", "bytes": 1218, "preview": "root:$6$..."}}
]}
status al livello superiore è il caso peggiore tra tutti i finding.
Alla fine viene scritta su stderr una riga di riepilogo con i totali. La barra di avanzamento viene renderizzata su stderr e viene automaticamente soppressa quando stderr non è un terminale.
Il codice di uscita è 0 se un qualsiasi target è vulnerabile, 1 se ogni target raggiungibile era pulito e 2 se nessun target può essere raggiunto.
Scansiona un elenco di target, scrivi i risultati su un file e resta silenzioso su stdout:
python scanner.py -f targets.txt -o vulnerable.txt -q
Scansiona con un elenco di nomi utente personalizzato contro la superficie cPanel, parallelismo aumentato e output JSON per l'elaborazione a valle:
python scanner.py -f targets.txt -U cpanel-users.txt -c 100 --json results.jsonl
Sonda un set di porte non predefinito:
python scanner.py -p 2083,2087,8443 -f targets.txt
Esegui la catena CalDAV end-to-end contro un singolo target con il fallback dell'email spray (richiede uno scanner.ini compilato):
python scanner.py --config scanner.ini --exploit example.com
Sfruttamento mirato contro un'email virtuale nota — tasso di successo molto più alto dello spray:
python scanner.py --config scanner.ini --email [email protected] example.com
Esegui solo la catena CalDAV contro un elenco di host cpdavd confermati, scaricando le anteprime di /etc/passwd in JSON:
python scanner.py --config scanner.ini --caldav-only \
-f cpdavd-hosts.txt --json caldav-results.jsonl
L'invocazione predefinita scanner.py <target> esegue solo il rilevatore CVE-2026-41940. Invia le richieste necessarie per confermare l'iniezione di sessione e nient'altro. Non accede come alcun utente reale, non prende di mira l'account root, non esegue l'escalation a una shell e non accumula eventi di password errata contro alcun account valido su un sistema target. Il marcatore che cerca (msg_code:[expired_session]) è generato dall'applicazione stessa in risposta al campo di sessione iniettato expired=1 ed è lo stesso indicatore che la pagina di login cPanel upstream usa quando viene riproposta una sessione legittimamente scaduta.
Passare --exploit (o --caldav-only) sblocca la catena di path traversal CalDAV. Questo non è più un rilevatore — è un exploit funzionante. Quando è abilitato, lo scanner, per ogni target in cui l'enumerazione dei domini ha successo:
scanner.ini e
invia un messaggio breve per ogni destinatario candidato (in genere 10–15 per
dominio, 3 domini per target);--read-file configurato da ogni target confermato.Il file predefinito è /etc/shadow. Una lettura riuscita restituisce i byte del file; un corpo vuoto indica un target non raggiungibile o un host in cui è presente la correzione del privilege drop (cPanel 11.134.0.26, my $privs = …). La rilevazione confronta la lunghezza del corpo ricevuto con zero, non con il Content-Length pubblicizzato nella risposta (che deriva da stat() sul percorso scelto dall'attaccante e sarà popolato anche quando la successiva open() viene negata).
Per testare la raggiungibilità della traversal indipendentemente dalla correzione del privilege drop — ad esempio quando vuoi sapere se cpdavd è raggiungibile e se il prerequisito maildir è stato soddisfatto su un host patchato — riesegui con --read-file /etc/passwd. /etc/passwd è leggibile da tutti, quindi restituisce byte sia sugli host pre-patch che post-patch; combinando i due segnali (/etc/shadow con corpo presente = lettura root pre-patch; /etc/shadow vuoto + /etc/passwd presente = traversal raggiungibile ma correzione del priv-drop applicata) classifica un host in modo inequivocabile.
I contenuti e un'anteprima di 200 byte vengono scritti nell'output JSONL e stampati su stdout. Lo sfruttamento CalDAV per dominio può richiedere un minuto o più — questa è la scala di ritentativi in attesa della consegna della posta, non un blocco.
Esegui --exploit solo contro asset che possiedi o per cui hai un'autorizzazione scritta esplicita a testare. Il traffico SMTP viene registrato dal relay configurato e da ogni sistema di posta del destinatario; le letture dei file vengono registrate da cpdavd.
--no-progress — disabilita la barra di avanzamento.--exploit — abilita la catena di path traversal CalDAV. Disabilitata di default;
vedere Modalità exploit (attiva) per gli effetti collaterali
che questo flag sblocca.--config — file INI con le credenziali del relay SMTP e i parametri CalDAV.
Vedere scanner.ini.example.--read-file — file da esfiltrare quando la catena CalDAV ha successo.
Sostituisce il valore nel file di configurazione. Il default è /etc/shadow — un
file accessibile solo a root, quindi una lettura riuscita distingue pre-patch
(restituisce il contenuto di shadow) da post-patch (open negato, corpo vuoto →
segnalato NON VULNERABILE). Usa --read-file /etc/passwd per testare la raggiungibilità
della traversal senza distinguere tra patchato e non patchato.--caldav-only — salta il controllo 41940 ed esegue solo la catena CalDAV.
Implica --exploit. Utile per rieseguire la catena contro un elenco di target
già noti come raggiungibili via CalDAV.--email ADDR — account di posta virtuale noto sul target. Salta l'enumerazione
dei SAN del certificato e la wordlist di spray; invia esattamente un messaggio a
ADDR ed esegue la lettura contro quel principal. Può essere ripetuto. Implica
--exploit. Vedere Sfruttamento mirato vs spray.-v, --verbose — emette l'avanzamento per dominio per la catena CalDAV
(elenco SAN del certificato, conteggio spray, scala di ritentativi).