From 66c45dc83bc52005b4e31dfa8238105d55c3a47e Mon Sep 17 00:00:00 2001 From: 9seconds Date: Tue, 23 Mar 2021 10:27:22 +0300 Subject: [PATCH] Add obfuscated2 server handshake --- mtglib/conns.go | 58 ++-------------- .../internal/obfuscated2/client_handshake.go | 27 ++++++++ .../obfuscated2/client_handshake_frame.go | 30 -------- mtglib/internal/obfuscated2/conn.go | 6 +- .../internal/obfuscated2/server_handshake.go | 68 +++++++++++++++++++ mtglib/proxy.go | 33 +++++---- 6 files changed, 123 insertions(+), 99 deletions(-) delete mode 100644 mtglib/internal/obfuscated2/client_handshake_frame.go create mode 100644 mtglib/internal/obfuscated2/server_handshake.go diff --git a/mtglib/conns.go b/mtglib/conns.go index 6793daf..985cad0 100644 --- a/mtglib/conns.go +++ b/mtglib/conns.go @@ -2,66 +2,20 @@ package mtglib import ( "context" - "fmt" "net" "time" ) -type connStandard struct { - conn net.Conn - idleTimeout time.Duration -} - -func (c connStandard) Read(b []byte) (int, error) { - if err := c.conn.SetReadDeadline(time.Now().Add(c.idleTimeout)); err != nil { - return 0, fmt.Errorf("cannot set read deadline: %w", err) - } - - return c.conn.Read(b) -} - -func (c connStandard) Write(b []byte) (int, error) { - if err := c.conn.SetWriteDeadline(time.Now().Add(c.idleTimeout)); err != nil { - return 0, fmt.Errorf("cannot set write deadline: %w", err) - } - - return c.conn.Write(b) -} - -func (c connStandard) Close() error { - return c.conn.Close() -} - -func (c connStandard) LocalAddr() net.Addr { - return c.conn.LocalAddr() -} - -func (c connStandard) RemoteAddr() net.Addr { - return c.conn.RemoteAddr() -} - -func (c connStandard) SetDeadline(t time.Time) error { - return c.conn.SetDeadline(t) -} - -func (c connStandard) SetReadDeadline(t time.Time) error { - return c.conn.SetReadDeadline(t) -} - -func (c connStandard) SetWriteDeadline(t time.Time) error { - return c.conn.SetWriteDeadline(t) -} - -type connEventTraffic struct { - connStandard +type connTelegramTraffic struct { + net.Conn connID string stream EventStream ctx context.Context } -func (c connEventTraffic) Read(b []byte) (int, error) { - n, err := c.connStandard.Read(b) +func (c connTelegramTraffic) Read(b []byte) (int, error) { + n, err := c.Conn.Read(b) if n > 0 { c.stream.Send(c.ctx, EventTraffic{ @@ -75,8 +29,8 @@ func (c connEventTraffic) Read(b []byte) (int, error) { return n, err } -func (c connEventTraffic) Write(b []byte) (int, error) { - n, err := c.connStandard.Write(b) +func (c connTelegramTraffic) Write(b []byte) (int, error) { + n, err := c.Conn.Write(b) if n > 0 { c.stream.Send(c.ctx, EventTraffic{ diff --git a/mtglib/internal/obfuscated2/client_handshake.go b/mtglib/internal/obfuscated2/client_handshake.go index 93a164e..8601766 100644 --- a/mtglib/internal/obfuscated2/client_handshake.go +++ b/mtglib/internal/obfuscated2/client_handshake.go @@ -8,6 +8,33 @@ import ( "io" ) +type clientHandhakeFrame struct { + handshakeFrame +} + +func (c *clientHandhakeFrame) decryptor(secret []byte) cipher.Stream { + hasher := acquireSha256Hasher() + defer releaseSha256Hasher(hasher) + + hasher.Write(c.key()) // nolint: errcheck + hasher.Write(secret) // nolint: errcheck + + return makeAesCtr(hasher.Sum(nil), c.iv()) +} + +func (c *clientHandhakeFrame) encryptor(secret []byte) cipher.Stream { + arr := clientHandhakeFrame{} + invertByteSlices(arr.data[:], c.data[:]) + + hasher := acquireSha256Hasher() + defer releaseSha256Hasher(hasher) + + hasher.Write(arr.key()) // nolint: errcheck + hasher.Write(secret) // nolint: errcheck + + return makeAesCtr(hasher.Sum(nil), arr.iv()) +} + func ClientHandshake(secret []byte, reader io.Reader) (int, cipher.Stream, cipher.Stream, error) { handshake := clientHandhakeFrame{} diff --git a/mtglib/internal/obfuscated2/client_handshake_frame.go b/mtglib/internal/obfuscated2/client_handshake_frame.go deleted file mode 100644 index 4d238f8..0000000 --- a/mtglib/internal/obfuscated2/client_handshake_frame.go +++ /dev/null @@ -1,30 +0,0 @@ -package obfuscated2 - -import "crypto/cipher" - -type clientHandhakeFrame struct { - handshakeFrame -} - -func (c *clientHandhakeFrame) decryptor(secret []byte) cipher.Stream { - hasher := acquireSha256Hasher() - defer releaseSha256Hasher(hasher) - - hasher.Write(c.key()) // nolint: errcheck - hasher.Write(secret) // nolint: errcheck - - return makeAesCtr(hasher.Sum(nil), c.iv()) -} - -func (c *clientHandhakeFrame) encryptor(secret []byte) cipher.Stream { - arr := clientHandhakeFrame{} - invertByteSlices(arr.data[:], c.data[:]) - - hasher := acquireSha256Hasher() - defer releaseSha256Hasher(hasher) - - hasher.Write(arr.key()) // nolint: errcheck - hasher.Write(secret) // nolint: errcheck - - return makeAesCtr(hasher.Sum(nil), arr.iv()) -} diff --git a/mtglib/internal/obfuscated2/conn.go b/mtglib/internal/obfuscated2/conn.go index 7e25d47..24b5a81 100644 --- a/mtglib/internal/obfuscated2/conn.go +++ b/mtglib/internal/obfuscated2/conn.go @@ -14,7 +14,7 @@ type Conn struct { writeBuf []byte } -func (c Conn) Read(p []byte) (int, error) { +func (c *Conn) Read(p []byte) (int, error) { n, err := c.Conn.Read(p) if err != nil { return n, err // nolint: wrapcheck @@ -25,9 +25,9 @@ func (c Conn) Read(p []byte) (int, error) { return n, nil } -func (c Conn) Write(p []byte) (int, error) { +func (c *Conn) Write(p []byte) (int, error) { c.writeBuf = append(c.writeBuf[:0], p...) - c.Encryptor.XORKeyStream(c.writeBuf, c.writeBuf) + c.Encryptor.XORKeyStream(c.writeBuf, p) return c.Conn.Write(c.writeBuf) } diff --git a/mtglib/internal/obfuscated2/server_handshake.go b/mtglib/internal/obfuscated2/server_handshake.go new file mode 100644 index 0000000..3b69d6a --- /dev/null +++ b/mtglib/internal/obfuscated2/server_handshake.go @@ -0,0 +1,68 @@ +package obfuscated2 + +import ( + "crypto/cipher" + "crypto/rand" + "encoding/binary" + "fmt" + "net" +) + +type serverHandshakeFrame struct { + handshakeFrame +} + +func (s *serverHandshakeFrame) decryptor() cipher.Stream { + return makeAesCtr(s.key(), s.iv()) +} + +func (s *serverHandshakeFrame) encryptor() cipher.Stream { + arr := serverHandshakeFrame{} + invertByteSlices(arr.data[:], s.data[:]) + + return makeAesCtr(arr.key(), arr.iv()) +} + +func ServerHandshake(conn net.Conn) (cipher.Stream, cipher.Stream, error) { + handshake := generateServerHanshakeFrame() + copyHandshake := handshake + encryptor := handshake.encryptor() + decryptor := handshake.decryptor() + + encryptor.XORKeyStream(handshake.data[:], handshake.data[:]) + copy(handshake.key(), copyHandshake.key()) + copy(handshake.iv(), copyHandshake.iv()) + + if _, err := conn.Write(handshake.data[:]); err != nil { + return nil, nil, fmt.Errorf("cannot send a handshake frame to telegram: %w", err) + } + + return encryptor, decryptor, nil +} + +func generateServerHanshakeFrame() serverHandshakeFrame { + frame := serverHandshakeFrame{} + + for { + if _, err := rand.Read(frame.data[:]); err != nil { + panic(err) + } + + if frame.data[0] == 0xef { + continue + } + + switch binary.LittleEndian.Uint32(frame.data[:4]) { + case 0x44414548, 0x54534f50, 0x20544547, 0x4954504f, 0xeeeeeeee: + continue + } + + if (frame.data[4] | frame.data[5] | frame.data[6] | frame.data[7]) == 0 { + continue + } + + copy(frame.connectionType(), handshakeConnectionType) + + return frame + } +} diff --git a/mtglib/proxy.go b/mtglib/proxy.go index d25f3c9..6678513 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -111,13 +111,10 @@ func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error { ctx.dc = dc ctx.logger = ctx.logger.BindInt("dc", dc) - ctx.clientConn = connStandard{ - conn: obfuscated2.Conn{ - Conn: ctx.clientConn, - Encryptor: encryptor, - Decryptor: decryptor, - }, - idleTimeout: p.idleTimeout, + ctx.clientConn = &obfuscated2.Conn{ + Conn: ctx.clientConn, + Encryptor: encryptor, + Decryptor: decryptor, } return nil @@ -129,14 +126,22 @@ func (p *Proxy) doTelegramCall(ctx *streamContext) error { return fmt.Errorf("cannot dial to Telegram: %w", err) } - ctx.telegramConn = connEventTraffic{ - connStandard: connStandard{ - conn: conn, - idleTimeout: p.idleTimeout, + encryptor, decryptor, err := obfuscated2.ServerHandshake(conn) + if err != nil { + conn.Close() + + return fmt.Errorf("cannot perform obfuscated2 handshake: %w", err) + } + + ctx.telegramConn = &obfuscated2.Conn{ + Conn: connTelegramTraffic{ + Conn: conn, + connID: ctx.connID, + stream: p.eventStream, + ctx: ctx, }, - connID: ctx.connID, - stream: p.eventStream, - ctx: ctx, + Encryptor: encryptor, + Decryptor: decryptor, } p.eventStream.Send(ctx, EventConnectedToDC{