mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-09-01 00:54:01 +03:00
Add base faketls processing
This commit is contained in:
@@ -22,6 +22,7 @@ require (
|
|||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/tylertreat/BoomFilters v0.0.0-20200520150052-42a7b4300c0c
|
github.com/tylertreat/BoomFilters v0.0.0-20200520150052-42a7b4300c0c
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
|
||||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect
|
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -324,6 +324,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||||
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ClientHello struct {
|
type ClientHello struct {
|
||||||
Time time.Time
|
Time time.Time
|
||||||
Digest [RandomLen]byte
|
Random [RandomLen]byte
|
||||||
SessionID []byte
|
SessionID []byte
|
||||||
|
CipherSuite uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
|
func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
|
||||||
@@ -27,7 +28,7 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
|
|||||||
return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
|
return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(hello.Digest[:], handshake[ClientHelloRandomOffset:])
|
copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
|
||||||
|
|
||||||
for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
|
for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
|
||||||
handshake[i] = 0
|
handshake[i] = 0
|
||||||
@@ -45,23 +46,26 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
|
|||||||
mac := hmac.New(sha256.New, secret)
|
mac := hmac.New(sha256.New, secret)
|
||||||
rec.Dump(mac)
|
rec.Dump(mac)
|
||||||
|
|
||||||
computedDigest := mac.Sum(nil)
|
computedRandom := mac.Sum(nil)
|
||||||
|
|
||||||
for i := 0; i < RandomLen; i++ {
|
for i := 0; i < RandomLen; i++ {
|
||||||
computedDigest[i] ^= hello.Digest[i]
|
computedRandom[i] ^= hello.Random[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < RandomLen-4; i++ {
|
for i := 0; i < RandomLen-4; i++ {
|
||||||
if computedDigest[i] != 0 {
|
if computedRandom[i] != 0 {
|
||||||
return hello, ErrBadDigest
|
return hello, ErrBadDigest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp := int64(binary.LittleEndian.Uint32(computedDigest[RandomLen-4:]))
|
timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
|
||||||
hello.Time = time.Unix(timestamp, 0)
|
hello.Time = time.Unix(timestamp, 0)
|
||||||
|
|
||||||
hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
|
hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
|
||||||
copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
|
copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
|
||||||
|
|
||||||
|
cipherSuiteOffset := ClientHelloSessionIDOffset + 1 + len(hello.SessionID) + 2
|
||||||
|
hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
|
||||||
|
|
||||||
return hello, nil
|
return hello, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,27 @@ const (
|
|||||||
|
|
||||||
ClientHelloRandomOffset = 6
|
ClientHelloRandomOffset = 6
|
||||||
ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen
|
ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen
|
||||||
ClientHelloMinLen = ClientHelloSessionIDOffset + 1
|
ClientHelloMinLen = ClientHelloSessionIDOffset + 1
|
||||||
|
|
||||||
|
WelcomePacketRandomOffset = 11
|
||||||
|
|
||||||
HandshakeTypeClient = 0x01
|
HandshakeTypeClient = 0x01
|
||||||
|
HandshakeTypeServer = 0x02
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrBadDigest = errors.New("bad digest")
|
ErrBadDigest = errors.New("bad digest")
|
||||||
ErrAntiReplayAttack = errors.New("antireplay attack was detected")
|
ErrAntiReplayAttack = errors.New("antireplay attack was detected")
|
||||||
|
|
||||||
|
serverHelloSuffix = []byte{
|
||||||
|
0x00, // no compression
|
||||||
|
0x00, 0x2e, // 46 bytes of data
|
||||||
|
0x00, 0x2b, // Extension - Supported Versions
|
||||||
|
0x00, 0x02, // 2 bytes are following
|
||||||
|
0x03, 0x04, // TLS 1.3
|
||||||
|
0x00, 0x33, // Extension - Key Share
|
||||||
|
0x00, 0x24, // 36 bytes
|
||||||
|
0x00, 0x1d, // x25519 curve
|
||||||
|
0x00, 0x20, // 32 bytes of key
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package faketls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var bytesBufferPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return &bytes.Buffer{}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func acquireBytesBuffer() *bytes.Buffer {
|
||||||
|
return bytesBufferPool.Get().(*bytes.Buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func releaseBytesBuffer(b *bytes.Buffer) {
|
||||||
|
b.Reset()
|
||||||
|
bytesBufferPool.Put(b)
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package faketls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
mrand "math/rand"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/v2/mtglib/internal/faketls/record"
|
||||||
|
"golang.org/x/crypto/curve25519"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SendWelcomePacket(writer io.Writer, secret []byte, clientHello ClientHello) error {
|
||||||
|
buf := acquireBytesBuffer()
|
||||||
|
defer releaseBytesBuffer(buf)
|
||||||
|
|
||||||
|
rec := record.AcquireRecord()
|
||||||
|
defer record.ReleaseRecord(rec)
|
||||||
|
|
||||||
|
rec.Type = record.TypeHandshake
|
||||||
|
rec.Version = record.Version12
|
||||||
|
|
||||||
|
generateServerHello(&rec.Payload, clientHello)
|
||||||
|
rec.Dump(buf)
|
||||||
|
rec.Reset()
|
||||||
|
|
||||||
|
rec.Type = record.TypeChangeCipherSpec
|
||||||
|
rec.Version = record.Version12
|
||||||
|
rec.Payload.WriteByte(0x01)
|
||||||
|
|
||||||
|
rec.Dump(buf)
|
||||||
|
rec.Reset()
|
||||||
|
|
||||||
|
rec.Type = record.TypeApplicationData
|
||||||
|
rec.Version = record.Version12
|
||||||
|
|
||||||
|
if _, err := io.CopyN(&rec.Payload, rand.Reader, int64(1024+mrand.Intn(3092))); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rec.Dump(buf)
|
||||||
|
|
||||||
|
packet := buf.Bytes()
|
||||||
|
mac := hmac.New(sha256.New, secret)
|
||||||
|
|
||||||
|
mac.Write(clientHello.Random[:])
|
||||||
|
mac.Write(packet)
|
||||||
|
|
||||||
|
copy(packet[WelcomePacketRandomOffset:], mac.Sum(nil))
|
||||||
|
|
||||||
|
if _, err := writer.Write(packet); err != nil {
|
||||||
|
return err // nolint: wrapcheck
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateServerHello(writer io.Writer, clientHello ClientHello) {
|
||||||
|
bodyBuf := acquireBytesBuffer()
|
||||||
|
defer releaseBytesBuffer(bodyBuf)
|
||||||
|
|
||||||
|
sliceBuf := [2]byte{}
|
||||||
|
digest := [RandomLen]byte{}
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint16(sliceBuf[:], uint16(record.Version12))
|
||||||
|
bodyBuf.Write(sliceBuf[:])
|
||||||
|
bodyBuf.Write(digest[:])
|
||||||
|
bodyBuf.WriteByte(byte(len(clientHello.SessionID)))
|
||||||
|
bodyBuf.Write(clientHello.SessionID)
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint16(sliceBuf[:], clientHello.CipherSuite)
|
||||||
|
bodyBuf.Write(sliceBuf[:])
|
||||||
|
bodyBuf.Write(serverHelloSuffix)
|
||||||
|
|
||||||
|
scalar := [32]byte{}
|
||||||
|
rand.Read(scalar[:])
|
||||||
|
curve, _ := curve25519.X25519(scalar[:], curve25519.Basepoint)
|
||||||
|
bodyBuf.Write(curve)
|
||||||
|
|
||||||
|
header := [4]byte{0, 0, 0, 0}
|
||||||
|
binary.BigEndian.PutUint32(header[:], uint32(bodyBuf.Len()))
|
||||||
|
header[0] = HandshakeTypeServer
|
||||||
|
|
||||||
|
writer.Write(header[:])
|
||||||
|
bodyBuf.WriteTo(writer)
|
||||||
|
}
|
||||||
+10
-6
@@ -122,15 +122,14 @@ func (p *Proxy) Shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proxy) doFakeTLSHandshake(ctx *streamContext, conn net.Conn) error {
|
func (p *Proxy) doFakeTLSHandshake(ctx *streamContext, conn net.Conn) error {
|
||||||
clientHelloRecord := record.AcquireRecord()
|
rec := record.AcquireRecord()
|
||||||
defer record.ReleaseRecord(clientHelloRecord)
|
defer record.ReleaseRecord(rec)
|
||||||
|
|
||||||
if err := clientHelloRecord.Read(conn); err != nil {
|
if err := rec.Read(conn); err != nil {
|
||||||
return fmt.Errorf("cannot read client hello: %w", err)
|
return fmt.Errorf("cannot read client hello: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hello, err := faketls.ParseClientHello(p.secret.Key[:],
|
hello, err := faketls.ParseClientHello(p.secret.Key[:], rec.Payload.Bytes())
|
||||||
clientHelloRecord.Payload.Bytes())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot parse client hello: %w", err)
|
return fmt.Errorf("cannot parse client hello: %w", err)
|
||||||
}
|
}
|
||||||
@@ -138,13 +137,18 @@ func (p *Proxy) doFakeTLSHandshake(ctx *streamContext, conn net.Conn) error {
|
|||||||
if err := p.timeAttackDetector.Valid(hello.Time); err != nil {
|
if err := p.timeAttackDetector.Valid(hello.Time); err != nil {
|
||||||
return fmt.Errorf("invalid time: %w", err)
|
return fmt.Errorf("invalid time: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.antiReplayCache.SeenBefore(hello.SessionID) {
|
if p.antiReplayCache.SeenBefore(hello.SessionID) {
|
||||||
p.logger.Warning("anti replay attack was detected")
|
p.logger.Warning("anti replay attack was detected")
|
||||||
|
|
||||||
return fmt.Errorf("anti replay attack from %s", ctx.ClientIP().String())
|
return fmt.Errorf("anti replay attack from %s", ctx.ClientIP().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("SUCCESS")
|
if err := faketls.SendWelcomePacket(conn, p.secret.Key[:], hello); err != nil {
|
||||||
|
return fmt.Errorf("cannot send a welcome packet: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error {
|
func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user