
Safely rileva il bypass dell'autenticazione di Veeam Service Provider Console CVE-2026-58073
Un rilevatore sicuro e non autenticato per le vulnerabilità KB4893 in Veeam Service Provider Console (pubblicato il 04-08-2026). Risponde a una domanda per ogni target, prima di qualsiasi autenticazione o TLS: le correzioni KB4893 sono presenti su questa console?
La coppia principale è una catena. CVE-2026-58073 (CVSS 9.5) consente a un peer di rete non autenticato di impersonare un agente di gestione connesso e di ricevere il certificato reale di quell'agente, perché l'handshake dell'agente decide l'autorizzazione in base al GUID che il peer ha scritto nel proprio certificato. CVE-2026-58072 (CVSS 9.0) è una scrittura arbitraria di file raggiungibile una volta che si possiede un'identità di agente. Collegate, costituiscono un'esecuzione remota di codice non autenticata sulla console che gestisce i backup di ogni tenant. Lo stesso advisory corregge anche CVE-2026-58071 (CVSS 8.2, API dell'appliance proxata come Portal Administrator) e CVE-2026-58067 (CVSS 8.7, DoS non autenticato per esaurimento della memoria). CVE-2026-58073 e CVE-2026-58072 sono state segnalate a Veeam tramite HackerOne; l'advisory non menziona il nome del segnalatore.
Questo script non tenta l'impersonificazione, non richiede un certificato e non scrive file. Legge solo la generazione del protocollo pubblicizzata dal router e nient'altro.
Sì. Il rilevatore è progettato per uso in produzione e per valutazioni:
ConnectorSaveFilesChannelHostProxy.m_multiplexers. Nessun receiver viene registrato, nessun canale o
multiplexer viene creato, nessun record di agente viene toccato. Un handshake di tipo Receiver
registrerebbe un nome; questo strumento non ne invia mai uno.ConnectionHub.log, ciascuna con il nome del receiver bf-probe-<uuid4> così che un difensore possa
distinguere una scansione da un attacco. Le righe esatte sono riportate sotto.VULNERABLE solo dopo aver
dimostrato di essere un ConnectionHub VSPC (vedi sotto), quindi un servizio TCP silenzioso non può
essere scambiato per una console non patchata.Per ogni target lo strumento apre due connessioni TCP e invia un handshake ConnectionHub su ciascuna,
nominando un receiver bf-probe-<uuid4> che non esisterà.
Con il default --transport auto, un target il cui trasporto non è quello implicito dalla sua porta
costa una connessione extra: la sonda con il trasporto sbagliato viene rifiutata durante l'handshake,
prima che venga letto qualsiasi nome di receiver, e il trasporto corretto viene poi usato per entrambe
le sonde reali. Fissa --transport direct o --transport gateway per mantenerlo esattamente su due
connessioni — utile se hai preventivato un numero di connessioni in una richiesta di modifica.
Stato modificato sul server: nessuno. Il percorso di codice Connector esegue una ricerca nel
dizionario in ChannelHostProxy.m_multiplexers, non trova nulla e restituisce un errore. Nessun
receiver viene registrato, nessun multiplexer o canale viene creato, nessuna sessione TLS viene
negoziata, nessun record di agente viene toccato. Questo strumento non invia mai un handshake di tipo
Receiver, che è quello che registrerebbe un nome.
Le voci di log vengono scritte in
%ProgramData%\Veeam\Veeam Availability Console\Log\Server\ConnectionHub.log. Verbatim da un
ConnectionHub 9.2.1.33875 live, con timestamp e JSON di scope troncati:
sonda 1 (versione 6), sia build patchate che non patchate:
[INFO] ChannelHostProxy: Accept connection begin {"RemoteEndPoint":"<ip>:<port>","Line":"1"}
[INFO] ChannelHostProxy: Accept connection end {"RemoteEndPoint":"<ip>:<port>","Line":"2",...}
[WARN] ChannelHostProxy: Cannot connect transmitter. Requested receiver not found
(receiver name:bf-probe-<uuid>) {"RemoteEndPoint":"<ip>:<port>","Line":"3",...}
sonda 2 (versione 7), solo build patchate:
le stesse tre righe
sonda 2 (versione 7), build non patchate:
[INFO] ChannelHostProxy: Accept connection begin
[WARN] ChannelHostProxy: Handshake failed. Reason:Unsupported client version "7"
[INFO] ChannelHostProxy: Accept connection end
Due connessioni, sei righe, nessun'altra voce e nessuna modifica di stato — confermato su un host live.
La stringa letterale bf-probe- in ConnectionHub.log identifica il traffico di questo strumento,
quindi un difensore può attribuirlo e un team di scansione può dimostrare cosa ha inviato. Modifica
RECEIVER_PREFIX nel sorgente se hai bisogno di un marcatore diverso.
Il router degli agenti di gestione ConnectionHub legge un handshake del client prima di qualsiasi
autenticazione o TLS, e Request.Read valida la versione del protocollo pubblicizzata dal client
contro un intervallo hardcoded. La correzione ha ampliato quell'intervallo nella stessa build che ha
corretto le CVE:
| Build | Controllo | Accetta |
|---|---|---|
<= 9.2.1.33875 (vulnerabile) | (uint)(versionByte - 3) <= 3 | 3, 4, 5, 6 |
>= 9.3.0.35057 (patchata) | (uint)(versionByte - 3) <= 4 | 3, 4, 5, 6, 7 |
Quindi un handshake che pubblicizza la versione 7 è un discriminatore binario pulito. Il rilevatore invia due sonde per target, in questo ordine per un motivo (il rilevamento del trasporto può aggiungerne una terza — vedi sotto):
| Sonda | Pubblicizza | Scopo |
|---|---|---|
| 1 | versione 6 | Deve restituire Requested receiver not found, dimostrando che il target è davvero un ConnectionHub VSPC |
| 2 | versione 7 | Una risposta significa PATCHED; il silenzio significa VULNERABLE |
Senza il gate della prima fase, il silenzio nella sonda 2 corrisponderebbe anche a qualsiasi servizio TCP silenzioso su internet, e i firewall verrebbero segnalati come console Veeam vulnerabili.
Funziona su entrambi i percorsi che un agente di gestione usa:
| Trasporto | Porta | Esposizione |
|---|---|---|
| Diretto al ConnectionHub | 9999 | di solito interno |
| Tramite un gateway Veeam Cloud Connect | 6180 | esposto a internet per progettazione |
Il percorso del gateway richiede un prologo di relay che il percorso diretto non deve avere, quindi la
sonda 1 funge anche da rilevamento del trasporto. Con il default --transport auto prova un trasporto
e, se il gate dell'impronta non passa, prova l'altro. Qualunque passi viene agganciato (latched), e
la sonda 2 lo riusa — un file di target misto non richiede annotazioni per host.
L'aggancio è portante. Se la sonda 2 potesse riprovare sull'altro trasporto, il silenzio non sarebbe più
attribuibile al controllo della versione, ma solo a "uno dei due percorsi di byte non ha risposto", che
è il modo in cui viene prodotto un falso VULNERABLE.
Quale trasporto viene provato per primo è deciso dalla porta, e non è una questione estetica — i due disallineamenti falliscono a velocità molto diverse:
| Disallineamento | Come lo legge l'estremità remota | Costo |
|---|---|---|
| Prologo di relay → hub diretto | meta int16 di hostType 44 / versionByte 0, fallisce il controllo dell'intervallo di Request.Read | smaltito in un round trip |
| Handshake diretto → gateway | lunghezza frame int32 di 1,012,729,346 | il gateway attende byte che non arrivano mai; consuma l'intero timeout |
Quindi auto inizia con il servizio che possiede la porta: gateway per primo su 6180, diretto ovunque
altrimenti. Questo mantiene il caso comune a un singolo tentativo e il disallineamento costoso fuori dal
percorso veloce. Una sonda che non riesce ad aprire affatto TCP si interrompe senza provare il secondo
trasporto, quindi gli host morti in una scansione ampia costano un timeout, non due.
VULNERABLE significa "le correzioni KB4893 non sono presenti", non "questa è la 9.2.1.33875". Le build
più vecchie della 9.2.1 condividono lo stesso controllo della versione, quindi dovrebbero segnalare il
protocollo 6 ed essere segnalate come vulnerabili anch'esse (dedotto dal codice, non misurato — vedi
Limitazioni), ma lo strumento non può distinguere la 9.2.1 dalla 9.1 o dalla 8.1. Conferma la build
esatta nell'interfaccia della console se ti serve.
# host singolo (TCP/9999 di default)
./cve_2026_58073_check.py vspc.example.com
# porta esplicita, più host
./cve_2026_58073_check.py vspc.example.com:9999 10.0.0.5
# scansiona una lista, un target per riga (commenti '#' consentiti), output compatto
./cve_2026_58073_check.py -f targets.txt --brief
# output leggibile dalle macchine per le pipeline
./cve_2026_58073_check.py -f targets.txt --json > results.json
# un gateway Veeam Cloud Connect — il trasporto relay viene rilevato automaticamente
./cve_2026_58073_check.py cc-gw.example.com:6180
# fissa il trasporto per saltare il rilevamento (la porta poi diventa 6180 di default)
./cve_2026_58073_check.py --transport gateway cc-gw.example.com
# valida i codec wire senza accesso alla rete
./cve_2026_58073_check.py --self-test
| Flag | Descrizione |
|---|---|
targets | Uno o più HOST[:PORT] (la porta predefinita è 9999, o 6180 con --transport gateway) |
-f, --targets-file FILE | Legge i target da un file (uno per riga; commenti #) |
--transport {auto,direct,gateway} | Come raggiungere il ConnectionHub. auto (default) lo rileva per target; gateway antepone il prologo di relay Cloud Connect e imposta la porta predefinita a 6180 |
-p, --port PORT | Sovrascrive la porta predefinita |
--timeout SECS | Timeout per sonda (default: 8) |
--workers N | Target concorrenti (default: 16); l'output resta nell'ordine di input |
-b, --brief | Una singola riga allineata per target — ideale per scansionare molti host |
--json | Emette JSON strutturato, inclusa ogni sonda inviata per target |
--no-color | Disabilita l'output colorato (rispetta anche NO_COLOR e i non-TTY) |
--self-test | Valida i codec wire .NET ed esce; nessun accesso alla rete |
Una console non patchata (l'output predefinito a due righe). Il marcatore [!] e VULNERABLE
vengono resi in rosso su un TTY:
$ ./cve_2026_58073_check.py vspc.example.com
[!] vspc.example.com:9999: VULNERABLE [protocol-7-rejected]
ConnectionHub rejects protocol 7 but accepts 6, so the KB4893 fixes are absent (<= 9.2.1.33875)
Una console patchata:
$ ./cve_2026_58073_check.py patched.example.com
[+] patched.example.com:9999: PATCHED [protocol-7-accepted]
ConnectionHub accepts protocol 7, so the KB4893 fixes are present (>= 9.3.0.35057)
Un target gateway, con il trasporto relay rilevato automaticamente. Il suffisso (gateway) indica
il trasporto su cui è stato raggiunto il verdetto:
$ ./cve_2026_58073_check.py cc-gw.example.com:6180
[!] cc-gw.example.com:6180 (gateway): VULNERABLE [protocol-7-rejected]
ConnectionHub rejects protocol 7 but accepts 6, so the KB4893 fixes are absent (<= 9.2.1.33875)
Scansione di un parco macchine, una riga allineata per host (--brief). Lo stato di uscita è 1
se un qualsiasi host è VULNERABLE, altrimenti 0 — utile negli script:
$ ./cve_2026_58073_check.py -f targets.txt --brief; echo "exit: $?"
VULNERABLE vspc.example.com:9999 protocol-7-rejected
PATCHED patched.example.com:9999 protocol-7-accepted
UNAFFECTED fileserver.example.com:9999 not-vspc
ERROR unused.example.com:9999 unreachable
exit: 1
Output leggibile dalle macchine per le pipeline (--json). Ogni sonda è inclusa per target, quindi
un risultato può essere derivato di nuovo dalle evidenze piuttosto che fidarsi. transport è quello su
cui è stato raggiunto il verdetto, e ogni sonda riporta il trasporto che ha usato — quindi un target
rilevato automaticamente mostra anche il tentativo rifiutato:
$ ./cve_2026_58073_check.py vspc.example.com --json
[
{
"target": "vspc.example.com:9999",
"host": "vspc.example.com",
"port": 9999,
"transport": "direct",
"verdict": "VULNERABLE",
"reason": "protocol-7-rejected",
"detail": "ConnectionHub rejects protocol 7 but accepts 6, so the KB4893 fixes are absent (<= 9.2.1.33875)",
"protocol_version": 6,
"affected_cves": [
"CVE-2026-58073",
"CVE-2026-58072",
"CVE-2026-58071",
"CVE-2026-58067"
],
"probes": [
{
"version_byte": 6,
"transport": "direct",
"connected": true,
"responded": true,
"status": "Error",
"message": "Cannot connect transmitter. Requested receiver not found (receiver name:bf-probe-b7c40be0-e2e8-41dc-9fc3-cbbd7345954a)",
"error": ""
},
{
"version_byte": 7,
"transport": "direct",
"connected": true,
"responded": false,
"status": "",
"message": "",
"error": ""
}
]
}
]
| Verdetto | Tag del motivo | Significato |
|---|---|---|
VULNERABLE | protocol-7-rejected | ConnectionHub VSPC confermato che accetta il protocollo 6 e rifiuta il 7. Le correzioni KB4893 sono assenti (<= 9.2.1.33875). |
PATCHED | protocol-7-accepted | ConnectionHub VSPC confermato che accetta il protocollo 7. Le correzioni KB4893 sono presenti (>= 9.3.0.35057). |
UNAFFECTED | not-vspc | Ha accettato TCP ma non ha risposto a un handshake ConnectionHub valido su nessun trasporto provato, quindi non è un ConnectionHub VSPC. |
INCONCLUSIVE | unexpected-reply | Ha risposto alla sonda dell'impronta con qualcosa di diverso da Requested receiver not found. |
INCONCLUSIVE | inconclusive-discriminator | Ha superato il gate dell'impronta, poi ha risposto alla sonda della versione 7 in un modo che non è né un passaggio né un fallimento — oppure quella seconda connessione è fallita del tutto. Riprova. |
ERROR | unreachable | Impossibile connettersi, oppure il gateway Cloud Connect ha rifiutato il prologo di relay sul primo trasporto provato (che sotto auto significa qualsiasi target sulla porta 6180). |
| Codice | Significato |
|---|---|
0 | Nessun target era VULNERABLE |
1 | Almeno un target è VULNERABLE |
2 | Errore di utilizzo (argomenti non validi / file dei target illeggibile) |
--transport auto; fissa --transport direct
per tenere il percorso non testato completamente fuori da una scansione.VULNERABLE riguarda lo stato di patch, non se qualcuno ha
sfruttato la console. Lo sfruttamento lascia le proprie tracce nei log della console sia su build
patchate che non patchate; cerca quelle separatamente.Aggiorna a Veeam Service Provider Console 9.3.0.35057 o successiva (KB4893). Tutti e quattro i problemi sono corretti in quella singola build, e non esiste un backport 9.2.x, quindi il rimedio è un aggiornamento di versione piuttosto che un hotfix.
Due cose che l'aggiornamento non fa. Non limita chi può raggiungere TCP/9999, che dovrebbe rispondere solo alle sottoreti in cui vivono i tuoi agenti di gestione. E non revoca un certificato di agente che la console ha già emesso, incluso uno emesso a un attaccante mentre era non patchata. Se trovi evidenze di sfruttamento, apri un caso di supporto Veeam per una guida sui certificati di agente compromessi: ruotarli non è una procedura documentata, e i certificati che puoi gestire nel portale non sono la CA che firma i certificati degli agenti.
Questo codice è distribuito sotto una licenza MIT.
L'uso di questo strumento per attaccare target senza previo consenso reciproco è illegale. È responsabilità dell'utente finale rispettare tutte le leggi locali, statali e federali applicabili. Gli sviluppatori non si assumono alcuna responsabilità e non sono responsabili per qualsiasi uso improprio o danno causato da questo programma.