v2ray-core Before v4.23.2 Has a Major Security Vulnerability That Lets Servers Be Actively Probed and Fingerprinted — Update ASAP

v2ray-core before v4.23.2 has a major security vulnerability consisting mainly of two flaws: HTTP camouflage has a potential fingerprinting risk (#2537), and a vmess protocol design and implementation flaw that lets servers be actively probed and fingerprinted (with PoC) (#2523). As of this writing, the latest version is v4.23.4, which has fixed both flaws. Please update as soon as possible.

v2ray-core before v4.23.2 has a major security vulnerability consisting mainly of two flaws: HTTP camouflage has a potential fingerprinting risk #2537, vmess protocol design and implementation flaw lets servers be actively probed and fingerprinted (with PoC) #2523. As of this writing, the latest version is v4.23.4, which has fixed both flaws. Please update as soon as possible.

HTTP Camouflage Has a Potential Fingerprinting Risk

This issue isn’t very serious. The problem mainly lies in the HTTP camouflage server, which can be distinguished from a normal server using active probing, and the camouflaged HTTP traffic may be subject to passive detection.

If v2ray’s HTTP camouflage is enabled, the server’s handling of inbound requests is too coarse, and on failure it responds with a hardcoded reply:

func (a HttpAuthenticator) Server(conn net.Conn) net.Conn {
    if a.config.Request == nil && a.config.Response == nil {
        return conn
    }
    return NewHttpConn(conn, new(HeaderReader), a.GetServerWriter(), formResponseHeader(&ResponseConfig{
        Version: &Version{
            Value: "1.1",
        },
        Status: &Status{
            Code:   "500",
            Reason: "Internal Server Error",
        },
        Header: []*Header{
            {
                Name:  "Connection",
                Value: []string{"close"},
            },
            {
                Name:  "Cache-Control",
                Value: []string{"private"},
            },
            {
                Name:  "Content-Length",
                Value: []string{"0"},
            },
        },
    }))
}

Any non-conforming header is answered with a hardcoded 500 reply.

We can imagine a detection method to distinguish a normal HTTP server from a camouflaged v2ray server:

v2ray’s HTTP camouflage adds an HTTP header at the start of the TCP stream, and then no more HTTP headers are added. Server-to-client communication is the same. This strange TCP connection may arouse a firewall’s suspicion.

For such traffic, the firewall can craft a standard HTTP request plus a random payload and actively probe the server.

If both the standard HTTP request and the random payload get a response shaped like

HTTP/1.1 500 Internal Server Error
Connection: close
Cache-Control: private
Content-Length: 0
Date: Tue, 02 Jun 2020 17:15:26 GMT

then the server is a v2ray server using HTTP camouflage.

If the standard HTTP request gets a 404/403/200/500 reply and the random payload gets a 400 reply, then it’s a normal HTTP server.

vmess Protocol Design and Implementation Flaw Lets Servers Be Actively Probed and Fingerprinted

v4.23.4 and later adopt random multi-byte reads to block the side-channel leak from P; the PoC below (16 probes) and the probabilistic-probe (brute-force packet probing) PoC are now invalid and can no longer accurately detect the vmess service. But since this is a protocol-design-level problem, a complete fix requires introducing AEAD and other non-backward-compatible designs. The good news is that this mitigation buys us a lot of time to discuss and formulate a new protocol. The vmess+tcp combination still carries some risk and is not recommended.

Conclusion first: for a server with tcp+vmess enabled, an attacker can accurately determine whether it’s a vmess service through a replay attack during communication with the client.

This flaw’s exploitation is based on replay attacks and ciphertext padding attacks, requiring the following conditions (after discussion, combined with the earlier replay attacks on ss, we believe these conditions aren’t harsh for the GFW):

The attacker can perform a man-in-the-middle attack, capturing the first 16 + 38 bytes of the vmess TCP stream.

The attacker can send 16 probe packets within 30 seconds based on that.

All current mitigation approaches can be bypassed; the only solution is to modify the protocol implementation.

In my opinion, the best solution is to use an authenticated encryption mode like GCM (aead) to encrypt the command portion instead of CFB. This conflicts with the existing vmess design and isn’t backward compatible, and may require redesigning the vmess protocol.

mkcp+vmess and tls+vmess, which don’t use tcp as the underlying transport, aren’t directly affected by this problem, but may be impacted.