Browse Source

Add base faketls processing

tags/v2.0.0-rc1
9seconds 5 years ago
parent
commit
c3e8e8b1fe

+ 1
- 0
go.mod View File

@@ -22,6 +22,7 @@ require (
22 22
 	github.com/stretchr/testify v1.7.0
23 23
 	github.com/tylertreat/BoomFilters v0.0.0-20200520150052-42a7b4300c0c
24 24
 	github.com/xeipuuv/gojsonschema v1.2.0
25
+	golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
25 26
 	golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
26 27
 	golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect
27 28
 )

+ 2
- 0
go.sum View File

@@ -324,6 +324,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
324 324
 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
325 325
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
326 326
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
327
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
328
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
327 329
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
328 330
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
329 331
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=

+ 12
- 8
mtglib/internal/faketls/client_hello.go View File

@@ -11,9 +11,10 @@ import (
11 11
 )
12 12
 
13 13
 type ClientHello struct {
14
-	Time      time.Time
15
-	Digest    [RandomLen]byte
16
-	SessionID []byte
14
+	Time        time.Time
15
+	Random      [RandomLen]byte
16
+	SessionID   []byte
17
+	CipherSuite uint16
17 18
 }
18 19
 
19 20
 func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
@@ -27,7 +28,7 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
27 28
 		return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
28 29
 	}
29 30
 
30
-	copy(hello.Digest[:], handshake[ClientHelloRandomOffset:])
31
+	copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
31 32
 
32 33
 	for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
33 34
 		handshake[i] = 0
@@ -45,23 +46,26 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
45 46
 	mac := hmac.New(sha256.New, secret)
46 47
 	rec.Dump(mac)
47 48
 
48
-	computedDigest := mac.Sum(nil)
49
+	computedRandom := mac.Sum(nil)
49 50
 
50 51
 	for i := 0; i < RandomLen; i++ {
51
-		computedDigest[i] ^= hello.Digest[i]
52
+		computedRandom[i] ^= hello.Random[i]
52 53
 	}
53 54
 
54 55
 	for i := 0; i < RandomLen-4; i++ {
55
-		if computedDigest[i] != 0 {
56
+		if computedRandom[i] != 0 {
56 57
 			return hello, ErrBadDigest
57 58
 		}
58 59
 	}
59 60
 
60
-	timestamp := int64(binary.LittleEndian.Uint32(computedDigest[RandomLen-4:]))
61
+	timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
61 62
 	hello.Time = time.Unix(timestamp, 0)
62 63
 
63 64
 	hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
64 65
 	copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
65 66
 
67
+	cipherSuiteOffset := ClientHelloSessionIDOffset + 1 + len(hello.SessionID) + 2
68
+	hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
69
+
66 70
 	return hello, nil
67 71
 }

+ 16
- 1
mtglib/internal/faketls/init.go View File

@@ -7,12 +7,27 @@ const (
7 7
 
8 8
 	ClientHelloRandomOffset    = 6
9 9
 	ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen
10
-	ClientHelloMinLen      = ClientHelloSessionIDOffset + 1
10
+	ClientHelloMinLen          = ClientHelloSessionIDOffset + 1
11
+
12
+	WelcomePacketRandomOffset = 11
11 13
 
12 14
 	HandshakeTypeClient = 0x01
15
+	HandshakeTypeServer = 0x02
13 16
 )
14 17
 
15 18
 var (
16 19
 	ErrBadDigest        = errors.New("bad digest")
17 20
 	ErrAntiReplayAttack = errors.New("antireplay attack was detected")
21
+
22
+	serverHelloSuffix = []byte{
23
+		0x00,       // no compression
24
+		0x00, 0x2e, // 46 bytes of data
25
+		0x00, 0x2b, // Extension - Supported Versions
26
+		0x00, 0x02, // 2 bytes are following
27
+		0x03, 0x04, // TLS 1.3
28
+		0x00, 0x33, // Extension - Key Share
29
+		0x00, 0x24, // 36 bytes
30
+		0x00, 0x1d, // x25519 curve
31
+		0x00, 0x20, // 32 bytes of key
32
+	}
18 33
 )

+ 21
- 0
mtglib/internal/faketls/pools.go View File

@@ -0,0 +1,21 @@
1
+package faketls
2
+
3
+import (
4
+	"bytes"
5
+	"sync"
6
+)
7
+
8
+var bytesBufferPool = sync.Pool{
9
+	New: func() interface{} {
10
+		return &bytes.Buffer{}
11
+	},
12
+}
13
+
14
+func acquireBytesBuffer() *bytes.Buffer {
15
+    return bytesBufferPool.Get().(*bytes.Buffer)
16
+}
17
+
18
+func releaseBytesBuffer(b *bytes.Buffer) {
19
+    b.Reset()
20
+    bytesBufferPool.Put(b)
21
+}

+ 88
- 0
mtglib/internal/faketls/welcome.go View File

@@ -0,0 +1,88 @@
1
+package faketls
2
+
3
+import (
4
+	"crypto/hmac"
5
+	"crypto/rand"
6
+	"crypto/sha256"
7
+	"encoding/binary"
8
+	"io"
9
+	mrand "math/rand"
10
+
11
+	"github.com/9seconds/mtg/v2/mtglib/internal/faketls/record"
12
+	"golang.org/x/crypto/curve25519"
13
+)
14
+
15
+func SendWelcomePacket(writer io.Writer, secret []byte, clientHello ClientHello) error {
16
+	buf := acquireBytesBuffer()
17
+	defer releaseBytesBuffer(buf)
18
+
19
+	rec := record.AcquireRecord()
20
+	defer record.ReleaseRecord(rec)
21
+
22
+	rec.Type = record.TypeHandshake
23
+	rec.Version = record.Version12
24
+
25
+	generateServerHello(&rec.Payload, clientHello)
26
+	rec.Dump(buf)
27
+	rec.Reset()
28
+
29
+	rec.Type = record.TypeChangeCipherSpec
30
+	rec.Version = record.Version12
31
+	rec.Payload.WriteByte(0x01)
32
+
33
+	rec.Dump(buf)
34
+	rec.Reset()
35
+
36
+	rec.Type = record.TypeApplicationData
37
+	rec.Version = record.Version12
38
+
39
+	if _, err := io.CopyN(&rec.Payload, rand.Reader, int64(1024+mrand.Intn(3092))); err != nil {
40
+		panic(err)
41
+	}
42
+
43
+	rec.Dump(buf)
44
+
45
+	packet := buf.Bytes()
46
+	mac := hmac.New(sha256.New, secret)
47
+
48
+	mac.Write(clientHello.Random[:])
49
+	mac.Write(packet)
50
+
51
+	copy(packet[WelcomePacketRandomOffset:], mac.Sum(nil))
52
+
53
+	if _, err := writer.Write(packet); err != nil {
54
+		return err // nolint: wrapcheck
55
+	}
56
+
57
+	return nil
58
+}
59
+
60
+func generateServerHello(writer io.Writer, clientHello ClientHello) {
61
+	bodyBuf := acquireBytesBuffer()
62
+	defer releaseBytesBuffer(bodyBuf)
63
+
64
+	sliceBuf := [2]byte{}
65
+	digest := [RandomLen]byte{}
66
+
67
+	binary.BigEndian.PutUint16(sliceBuf[:], uint16(record.Version12))
68
+	bodyBuf.Write(sliceBuf[:])
69
+	bodyBuf.Write(digest[:])
70
+	bodyBuf.WriteByte(byte(len(clientHello.SessionID)))
71
+	bodyBuf.Write(clientHello.SessionID)
72
+
73
+	binary.BigEndian.PutUint16(sliceBuf[:], clientHello.CipherSuite)
74
+	bodyBuf.Write(sliceBuf[:])
75
+	bodyBuf.Write(serverHelloSuffix)
76
+
77
+	scalar := [32]byte{}
78
+	rand.Read(scalar[:])
79
+	curve, _ := curve25519.X25519(scalar[:], curve25519.Basepoint)
80
+	bodyBuf.Write(curve)
81
+
82
+	header := [4]byte{0, 0, 0, 0}
83
+	binary.BigEndian.PutUint32(header[:], uint32(bodyBuf.Len()))
84
+	header[0] = HandshakeTypeServer
85
+
86
+	writer.Write(header[:])
87
+	bodyBuf.WriteTo(writer)
88
+}

+ 10
- 6
mtglib/proxy.go View File

@@ -122,15 +122,14 @@ func (p *Proxy) Shutdown() {
122 122
 }
123 123
 
124 124
 func (p *Proxy) doFakeTLSHandshake(ctx *streamContext, conn net.Conn) error {
125
-	clientHelloRecord := record.AcquireRecord()
126
-	defer record.ReleaseRecord(clientHelloRecord)
125
+	rec := record.AcquireRecord()
126
+	defer record.ReleaseRecord(rec)
127 127
 
128
-	if err := clientHelloRecord.Read(conn); err != nil {
128
+	if err := rec.Read(conn); err != nil {
129 129
 		return fmt.Errorf("cannot read client hello: %w", err)
130 130
 	}
131 131
 
132
-	hello, err := faketls.ParseClientHello(p.secret.Key[:],
133
-		clientHelloRecord.Payload.Bytes())
132
+	hello, err := faketls.ParseClientHello(p.secret.Key[:], rec.Payload.Bytes())
134 133
 	if err != nil {
135 134
 		return fmt.Errorf("cannot parse client hello: %w", err)
136 135
 	}
@@ -138,13 +137,18 @@ func (p *Proxy) doFakeTLSHandshake(ctx *streamContext, conn net.Conn) error {
138 137
 	if err := p.timeAttackDetector.Valid(hello.Time); err != nil {
139 138
 		return fmt.Errorf("invalid time: %w", err)
140 139
 	}
140
+
141 141
 	if p.antiReplayCache.SeenBefore(hello.SessionID) {
142 142
 		p.logger.Warning("anti replay attack was detected")
143 143
 
144 144
 		return fmt.Errorf("anti replay attack from %s", ctx.ClientIP().String())
145 145
 	}
146 146
 
147
-	return fmt.Errorf("SUCCESS")
147
+	if err := faketls.SendWelcomePacket(conn, p.secret.Key[:], hello); err != nil {
148
+		return fmt.Errorf("cannot send a welcome packet: %w", err)
149
+	}
150
+
151
+	return nil
148 152
 }
149 153
 
150 154
 func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error {

Loading…
Cancel
Save