TLS : tls spoofing#6103
Open
codewithtamim wants to merge 16 commits into
Open
Conversation
…im/Xray-core into feature/tls-spoofing
Contributor
Author
Member
|
应当加到 finalmask |
Member
|
将它添加为一个tcpmask(以避免需要修改其他传输) |
Member
|
|
Contributor
Author
|
Contributor
Author
|
@Fangliding @RPRX new changes are ready |
Member
Contributor
Author
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.


fix #5964
So basically when you make a TLS outbound connection, the code checks if you set a "spoof" field or not. If you did, it genrates a fake TLS ClientHello using the SNI you gave for spoofing, then wraps the connection with tlsspoof.Conn. On the first Write() call (which is what triggers the real TLS ClientHello), it shoves the fake ClientHello in as a raw tcp/ip packet first, then immediatly sends the real one normally.
the fake packet is then intentionaly broken depending on which method you picked (spoof_method), so censors can parse it and think theyre seeing a connection to allowed.site.com, but the real destination rejects the fake packet and only process the real one.
how to configure in outbound tls settings:
{ "tlsSettings": { "serverName": "real.site.com", "spoof": "allowed.site.com", "spoof_method": "wrong-sequence", "spoof_count": 1 } }spoof(string) : the fake sni to inject, has to be a domain, ip adresses are rejected automaticalyspoof_method(string) : which corruption method to use, see belowspoof_count(int32) : how many Write() calls trigger the injection, 0 or 1 both mean single injection (default)works with:
tcp,websocket,http upgrade,grpc,splithttp,mkcpruns before the actual tls handshake happends
available methods:
wrong-sequence(default) : offsets the tcp sequence number by -len(payload) so the server see it as out of windowwrong-checksum: bitwise inverts the tcp checksum (^0xFFFF), server drops itwrong-ack: sets a wrong tcp acknowledgement number, server sends RSTwrong-md5: appends a bogus tcp md5 signature option, servers withouth md5 support drop itwrong-timestamp: backdates the tcp timestamp by 1 hour so server rejects it (not supported on mac)platform support:
linux : fully supported, needs
CAP_NET_RAW+CAP_NET_ADMINor rootmac : full support excpet
wrong-timestamp, needs sudo/rootfreebsd : full support excpet
wrong-timestamp, needs rootwindows amd64/x86 : full support, needs admin, windivert kernel driver loaded via scm on first run
not supported: windows arm64, android, ios, openwrt
NEW WAY (final mask)
after maintainer review the pr was rebuilt as a tcpmask under finalmask instead of a tls setting.
so basically after the tcp connection is dialed, the rawpacket wrapper sits on top. on the first Write() call (which is what triggers the real TLS ClientHello), it crafts a fake TCP/IP packet with your payload, corrupts it so the server drops it, injects it via raw socket, then lets the real Write() go through normally.
the big difference is you provide the exact fake bytes yourself as base64. before the code auto generate a fake ClientHello from the spoof SNI. now you generate whatever fake payload you want,, could be a ClientHello, could be HTTP headers, could be anything ,and base64 it, and pass it in.
the other big difference is the TTL. before it was hardcoded to 64. now it defaults to 3 and you can change it. the idea is the fake packet should reach the censor but die before it hits the destination server, exactly what RPRX said in the original issue.
how to configure as a tcpmask:
{ "finalmask": { "tcp": [ { "type": "rawpacket", "settings": { "payload": "FgQDBxo...base64...", "method": "wrong-sequence", "ttl": 3, "count": 1 } } ] } }payload (string, base64) : the exact fake bytes to inject. you generate this yourself.
method (string) : which corruption method to use, see below
ttl (uint32) : IP TTL of the fake packet. default is 3. low values mean it dies before the CDN.
count (int32) : how many Write() calls trigger the injection, 0 or 1 both mean single injection (default)
works with any TCP based transport (tcp, websocket, http upgrade, grpc, splithttp, mkcp)
runs before the actual tls handshake because it intercepts the first Write() is done.
available methods :
wrong-sequence(default): offsets the tcp sequence number by -len(payload) so the server see it as out of windowwrong-checksum: bitwise inverts the tcp checksum (^0xFFFF), server drops itwrong-ack: sets a wrong tcp acknowledgement number, server sends RSTwrong-md5: appends a bogus tcp md5 signature option, servers withouth md5 support drop itwrong-timestamp: backdates the tcp timestamp by 1 hour so server rejects it (not supported on mac/freebsd)platform support:
linux : fully supported, needs CAP_NET_RAW + CAP_NET_ADMIN or root
mac : full support excpet wrong-timestamp, needs sudo/root
freebsd : full support excpet wrong-timestamp, needs root
windows amd64/x86 : full support, needs admin, windivert kernel driver loaded via scm on first run
not supported:
windows arm64, android, ios, openwrt