Validate hostname if it was found in SNI

This commit is contained in:
9seconds
2021-03-26 17:23:30 +03:00
parent ce30e128e5
commit 5eca6ecb05
5 changed files with 64 additions and 8 deletions
+1 -1
View File
@@ -13,7 +13,7 @@
# Debug starts application in debug mode. It starts to be quite verbose
# in output. Actually, the idea is that you run it in debug mode only if
# you have any issue.
debug = false
debug = true
# A secret. Please remember that mtg supports only FakeTLS mode, legacy
# simple and secured mode are prohibited. For you it means that secret
+52 -5
View File
@@ -14,6 +14,7 @@ type ClientHello struct {
Time time.Time
Random [RandomLen]byte
SessionID []byte
Host string
CipherSuite uint16
}
@@ -28,6 +29,15 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
}
handshakeSizeBytes := [4]byte{0, handshake[1], handshake[2], handshake[3]}
handshakeLength := binary.BigEndian.Uint32(handshakeSizeBytes[:])
if len(handshake)-4 != int(handshakeLength) {
return hello,
fmt.Errorf("incorrect handshake size. manifested=%d, real=%d",
handshakeLength, len(handshake)-4) // nolint: gomnd
}
copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
@@ -61,11 +71,48 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
hello.Time = time.Unix(timestamp, 0)
hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3 // nolint: gomnd
hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
parseSessionID(&hello, handshake)
parseCipherSuite(&hello, handshake)
parseSNI(&hello, handshake)
return hello, nil
}
func parseSessionID(hello *ClientHello, handshake []byte) {
hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
}
func parseCipherSuite(hello *ClientHello, handshake []byte) {
cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3 // nolint: gomnd
hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
}
func parseSNI(hello *ClientHello, handshake []byte) {
cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 1
handshake = handshake[cipherSuiteOffset:]
cipherSuiteLength := binary.BigEndian.Uint16(handshake[:2])
handshake = handshake[2+cipherSuiteLength:]
compressionMethodsLength := int(handshake[0])
handshake = handshake[1+compressionMethodsLength:]
extensionsLength := binary.BigEndian.Uint16(handshake[:2])
handshake = handshake[2 : 2+extensionsLength]
for len(handshake) > 0 {
if binary.BigEndian.Uint16(handshake[:2]) != ExtensionSNI {
extensionsLength := binary.BigEndian.Uint16(handshake[2:4])
handshake = handshake[4+extensionsLength:]
continue
}
hostnameLength := binary.BigEndian.Uint16(handshake[7:9])
handshake = handshake[9:]
hello.Host = string(handshake[:int(hostnameLength)])
return
}
}
+3 -1
View File
@@ -7,7 +7,7 @@ const (
ClientHelloRandomOffset = 6
ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen
ClientHelloMinLen = ClientHelloSessionIDOffset + 1
ClientHelloMinLen = 4
WelcomePacketRandomOffset = 11
@@ -15,6 +15,8 @@ const (
HandshakeTypeServer = 0x02
ChangeCipherValue = 0x01
ExtensionSNI = 0x00
)
var (
+1 -1
View File
@@ -36,7 +36,7 @@ var (
{network: "tcp4", address: "149.154.167.91:443"},
},
{
{network: "tcp4", address: "149.154.171.5:443"},
{network: "tcp4", address: "149.154.171.5:443"},
},
}
v6Addresses = [5]tgAddr{
+7
View File
@@ -144,6 +144,13 @@ func (p *Proxy) doFakeTLSHandshake(ctx *streamContext) bool {
return false
}
if hello.Host != "" && hello.Host != p.secret.Host {
p.logger.BindStr("hostname", hello.Host).Info("incorrect domain was found in SNI")
p.doDomainFronting(ctx, rewind)
return false
}
if err := p.timeAttackDetector.Valid(hello.Time); err != nil {
p.logger.InfoError("invalid faketls time", err)
p.doDomainFronting(ctx, rewind)