Repository navigation
vnc: fix RFB 3.7/3.8 handshake broken by the short-read check - #1116
Merged
vanhauser-thc merged 3 commits intoNov 7, 2026
Merged
Conversation
d78db4b made start_vnc() require 20 bytes from the first recv(), but an RFB 3.7/3.8 server only sends the security type list (1 + n bytes) and then waits for the client to pick one, so every attempt against such a server failed with "short read". The same change turned the security type loop into i < buf2[0], which skips the last type. Require only the bytes the protocol version actually sends, bound the type loop by the bytes received, and in the RFB 3.3 VNC auth path read the rest of the challenge if it arrives in a separate segment instead of failing.
protonnegativo
force-pushed
the
fix/vnc-rfb37-handshake
branch
from
October 26, 2026 02:34
6a661ae to
7001683
Compare
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Fragmented RFB 3.7/3.8 security-type lists still cause valid handshakes to fail.
1 open issue
What changed in this PR
This PR addresses short-read regressions in the VNC module’s RFB security negotiation, restoring support for common RFB 3.7/3.8 handshakes and split RFB 3.3 challenges.
Changes:
- Apply protocol-specific minimum lengths to the initial security read.
- Include the last received security type while bounding the scan by received bytes.
- Accumulate the remaining RFB 3.3 authentication challenge before encryption.
| File | Description |
|---|---|
| hydra-vnc.c | Updates security negotiation checks, type scanning, and RFB 3.3 challenge reads. |
Review effort: Balanced
With RFB 3.7+ the server may send the type count and the types in separate segments. Keep reading until all advertised types are in, and size the buffer for the largest accepted count.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Blocking receives in both new handshake loops can leave workers waiting beyond the configured timeout when a server sends incomplete data and keeps the connection open.
1 open issue
1 resolved since last review
Review effort: Balanced
The loops that read the rest of the security type list and the rest of the RFB 3.3 challenge used a blocking recv(), so a server that sent an incomplete list or challenge and kept the connection open left the child waiting forever. Use hydra_recv_nb() so these reads honour the -w wait time and fail the handshake on timeout.
Owner
|
thanks |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Since d78db4b ("security fixes") the vnc module fails against every RFB 3.7/3.8 server (i.e. most current VNC servers): each attempt ends with
[ERROR] VNC server connection failed (short read)and no password is found.Cause
start_vnc()now requires the firstrecv()to return 20 bytes. That is only true for RFB 3.3 with VNC auth (4-byte type + 16-byte challenge). With 3.7/3.8 the server sends just the security type list (1 + n bytes) and then waits for the client to choose a type, so the read is always short. The same commit also changed the type loop fromi <= buf2[0]toi < buf2[0], which skips the last offered type (a server offering only type 2 never matches).Fix
recv()result and require only what the protocol version sends at that point: 1 byte for 3.7+, 4 for 3.3 (an RFB 3.3 server with no auth sends only those 4 bytes and was broken too).i <= buf2[0], and read the rest of the type list if it arrives in more than one segment (fail only if the connection closes). The buffer gets one more byte so the largest accepted count (20) fits.Testing
Mock RFB server (Python, pycryptodome for the DES check), password
secret, wordlista b secret c:Before (master):
(3.3 still worked; with
hydra-vnc.cfrom d78db4b~1 all three were found.)After:
Same for 47302 and 47303. With a wordlist without the password:
0 valid password foundon all three. A 3.8 server offering only type 1 still reports "VNC server does not require authentication."With
SPLIT=1the mock sends the first field in its own write, 50 ms before the rest (RFB 3.8: the type count, then the types; RFB 3.3: the type, then the challenge). Both failed on master ("short read"); the password is found after, also for 3.8 with16,2. A 3.8 server that announces 3 types, sends one and closes gives "short read" instead of hanging.vnc_server.py