What this actually is.
Technical background, root cause, and affected surface.
UltraVNC through 1.8.2.2 uses inadequate cryptography in the MS-Logon II authentication scheme (rfbUltraVNC_MsLogonIIAuth). In rfb/dh.cpp the Diffie-Hellman key exchange is performed with parameters that fit in an unsigned 64-bit integer (DH_MAX_BITS controls the prime size). A 64-bit DH key can be broken by Pollard's rho algorithm in under one second on current hardware. Additionally, the private exponent is generated by the rng() function, which multiplies three libc rand() values seeded from time(NULL). With approximately 31 bits of internal state and a time-based seed, the private exponent is recoverable in under a minute by a passive observer. A network attacker who can observe the MS-Logon II handshake (via sniffing, recording, or man-in-the-middle) can derive the shared DH key and decrypt the encapsulated username and password, resulting in full credential disclosure. This affects legacy MS-Logon II connections; MS-Logon III (X25519 + AES-256-GCM) is unaffected.
- Vendor
- UltraVNC
- Product
- UltraVNC
- Severity
- High
- CVSS Score
- 7.4
- Status
- Fixed
- Vector
- CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
- CWE
- CWE-326: Inadequate Encryption Strength, CWE-338: Use of Cryptographically Weak PRNG
From one request
to root shell.
Reproduced in a sandboxed environment. Requires only LAN or WiFi adjacency.
BSGS key recovery tool: live confirmed gen=1628590949 mod=2119336411 pub=480274997 → private key 983298996 recovered in 0.010s and verified. predict_challenge.py (private) demonstrates deterministic exponent prediction.
The bug, and the fix.
unsigned __int64 rng(unsigned __int64 limit) { return ((((unsigned __int64) rand()) * rand() * rand()) % limit); // dh.cpp:63 } // DH_MAX_BITS=31 (dh.h:44); srand(time(NULL)) at dh.cpp:53 unsigned __int64 maxNum = ((unsigned __int64) 1) << DH_MAX_BITS; // 2^31
Root cause: DH_MAX_BITS set to 31 (not 2048+). RNG uses libc rand() with time-based seed. Design acknowledged as insufficient by original author in 2006. libsodium is already pinned in vcpkg.json.
When does this fire?
All conditions must be true for the exploit to succeed.
Target authenticates using MS-Logon II. 2. Attacker captures DH handshake (generator, modulus, public key) on the wire. 3. BSGS algorithm recovers private exponent in <1 second. 4. Shared key derived; MS-Logon II challenge/response decrypted → plaintext credentials.
What an attacker does to you.
Post-exploitation outcomes mapped to CVSS impact metrics.
Plaintext Windows domain username and password exposed to any passive network observer or MITM. Affects all UltraVNC deployments using MS-Logon II on non-encrypted networks.
C:H · I:H · A:N
CWE-326: Inadequate Encryption Strength, CWE-338: Use of Cryptographically Weak PRNG
Fix it. In this order.
A runbook, not a checklist. Sequence matters — assume compromise before you act.
Upgrade to MS-Logon III (X25519+AES-256-GCM via libsodium). Vendor fix: MS-Logon III introduced as preferred path; MS-Logon II retained as backward-compat fallback with runtime security warning when activated.
disclose@securin.ioVendors moved in days.
Attackers in hours.
Reconstructed from vendor advisories, CISA bulletins, and Securin research records.
Discovered
BSGS key recovery live-confirmed in 0.010s
Reported to vendor
MS-Logon III fix validated
Planned public disclosure
Timeline recorded · Disclosure coordinated by Securin
Cite, verify, go deeper.
Primary sources — NVD, CISA KEV, and machine-readable IoC feed.