From 93755521805271544c0abdc53e7a10d22c777be6 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Fri, 18 Mar 2022 14:58:03 +0300 Subject: [PATCH] Add fuzz tests for obfuscated2 --- .../client_handshake_fuzz_internal_test.go | 32 ++++++++++ mtglib/internal/obfuscated2/init_test.go | 54 +++++++++++++++++ .../server_handshake_fuzz_internal_test.go | 30 ++++++++++ .../obfuscated2/server_handshake_fuzz_test.go | 58 +++++++++++++++++++ .../obfuscated2/server_handshake_test.go | 57 +++--------------- 5 files changed, 183 insertions(+), 48 deletions(-) create mode 100644 mtglib/internal/obfuscated2/client_handshake_fuzz_internal_test.go create mode 100644 mtglib/internal/obfuscated2/server_handshake_fuzz_internal_test.go create mode 100644 mtglib/internal/obfuscated2/server_handshake_fuzz_test.go diff --git a/mtglib/internal/obfuscated2/client_handshake_fuzz_internal_test.go b/mtglib/internal/obfuscated2/client_handshake_fuzz_internal_test.go new file mode 100644 index 0000000..1c9685d --- /dev/null +++ b/mtglib/internal/obfuscated2/client_handshake_fuzz_internal_test.go @@ -0,0 +1,32 @@ +package obfuscated2 + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" +) + +var FuzzClientHandshakeSecret = []byte{1,2,3} + +func FuzzClientHandshake(f *testing.F) { + f.Add([]byte{1,2,3}) + + f.Fuzz(func(t *testing.T, frame []byte) { + data := bytes.NewReader(frame) + + if _, _, _, err := ClientHandshake(FuzzClientHandshakeSecret, data); err != nil { + return + } + + handshake := clientHandhakeFrame{} + require.Len(t, frame, handshakeFrameLen) + + copy(handshake.data[:], frame) + + decryptor := handshake.decryptor(FuzzClientHandshakeSecret) + decryptor.XORKeyStream(handshake.data[:], handshake.data[:]) + + require.Equal(t, handshakeConnectionType, handshake.connectionType()) + }) +} diff --git a/mtglib/internal/obfuscated2/init_test.go b/mtglib/internal/obfuscated2/init_test.go index 001c84b..0cc5c17 100644 --- a/mtglib/internal/obfuscated2/init_test.go +++ b/mtglib/internal/obfuscated2/init_test.go @@ -1,12 +1,20 @@ package obfuscated2_test import ( + "bytes" + "crypto/aes" + "crypto/cipher" "encoding/base64" "encoding/json" "fmt" "os" "path/filepath" "strings" + "testing" + + "github.com/9seconds/mtg/v2/internal/testlib" + "github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2" + "github.com/stretchr/testify/require" ) type snapshotBytes struct { @@ -50,6 +58,14 @@ type SnapshotTestSuite struct { snapshots map[string]*Obfuscated2Snapshot } +type ServerHandshakeTestData struct { + connMock *testlib.EssentialsConnMock + + proxyConn obfuscated2.Conn + encryptor cipher.Stream + decryptor cipher.Stream +} + func (suite *SnapshotTestSuite) IngestSnapshots(dirname, namePrefix string) error { suite.snapshots = map[string]*Obfuscated2Snapshot{} @@ -81,3 +97,41 @@ func (suite *SnapshotTestSuite) IngestSnapshots(dirname, namePrefix string) erro return nil } + +func NewServerHandshakeTestData(t *testing.T) ServerHandshakeTestData { + buf := &bytes.Buffer{} + connMock := &testlib.EssentialsConnMock{} + + handshakeEnc, handshakeDec, err := obfuscated2.ServerHandshake(buf) + require.NoError(t, err) + + serverEncrypted := buf.Bytes() + decBlock, _ := aes.NewCipher(serverEncrypted[8 : 8+32]) + decryptor := cipher.NewCTR(decBlock, serverEncrypted[8+32:8+32+16]) + + serverDecrypted := make([]byte, len(serverEncrypted)) + decryptor.XORKeyStream(serverDecrypted, serverEncrypted) + + require.Equal(t, "3d3d3Q", + base64.RawStdEncoding.EncodeToString(serverDecrypted[8+32+16:8+32+16+4])) + + serverEncryptedReverted := make([]byte, len(serverEncrypted)) + + for i := 0; i < 32+16; i++ { + serverEncryptedReverted[8+i] = serverEncrypted[8+32+16-1-i] + } + + encBlock, _ := aes.NewCipher(serverEncryptedReverted[8 : 8+32]) + encryptor := cipher.NewCTR(encBlock, serverEncryptedReverted[8+32:8+32+16]) + + return ServerHandshakeTestData{ + connMock: connMock, + proxyConn: obfuscated2.Conn{ + Conn: connMock, + Encryptor: handshakeEnc, + Decryptor: handshakeDec, + }, + encryptor: encryptor, + decryptor: decryptor, + } +} diff --git a/mtglib/internal/obfuscated2/server_handshake_fuzz_internal_test.go b/mtglib/internal/obfuscated2/server_handshake_fuzz_internal_test.go new file mode 100644 index 0000000..ca9ad09 --- /dev/null +++ b/mtglib/internal/obfuscated2/server_handshake_fuzz_internal_test.go @@ -0,0 +1,30 @@ +package obfuscated2 + +import ( + "encoding/binary" + "testing" + + "github.com/stretchr/testify/assert" +) + +func FuzzServerGenerateHandshakeFrame(f *testing.F) { + f.Fuzz(func(t *testing.T, arg int) { + frame := generateServerHanshakeFrame() + + assert.NotEqualValues(t, 0xef, frame.data[0]) + + firstBytes := binary.LittleEndian.Uint32(frame.data[:4]) + assert.NotEqualValues(t, 0x44414548, firstBytes) + assert.NotEqualValues(t, 0x54534f50, firstBytes) + assert.NotEqualValues(t, 0x20544547, firstBytes) + assert.NotEqualValues(t, 0x4954504f, firstBytes) + assert.NotEqualValues(t, 0xeeeeeeee, firstBytes) + + assert.NotEqualValues( + t, + 0, + frame.data[4] | frame.data[5] | frame.data[6] | frame.data[7]) + + assert.Equal(t, handshakeConnectionType, frame.connectionType()) + }) +} diff --git a/mtglib/internal/obfuscated2/server_handshake_fuzz_test.go b/mtglib/internal/obfuscated2/server_handshake_fuzz_test.go new file mode 100644 index 0000000..be1cea6 --- /dev/null +++ b/mtglib/internal/obfuscated2/server_handshake_fuzz_test.go @@ -0,0 +1,58 @@ +package obfuscated2_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func FuzzServerSend(f *testing.F) { + f.Add([]byte{1,2,3,4,5}) + + f.Fuzz(func(t *testing.T, data []byte) { + handshakeData := NewServerHandshakeTestData(t) + + handshakeData.connMock. + On("Write", mock.Anything). + Return(len(data), nil). + Once(). + Run(func(args mock.Arguments) { + message := make([]byte, len(data)) + handshakeData.decryptor.XORKeyStream(message, args.Get(0).([]byte)) + assert.Equal(t, message, data) + }) + + n, err := handshakeData.proxyConn.Write(data) + + assert.EqualValues(t, len(data), n) + assert.NoError(t, err) + handshakeData.connMock.AssertExpectations(t) + }) +} + +func FuzzServerReceive(f *testing.F) { + f.Add([]byte{1,2,3,4,5}) + + f.Fuzz(func(t *testing.T, data []byte) { + handshakeData := NewServerHandshakeTestData(t) + buffer := make([]byte, len(data)) + + handshakeData.connMock. + On("Read", mock.Anything). + Return(len(data), nil). + Once(). + Run(func(args mock.Arguments) { + message := make([]byte, len(data)) + handshakeData.encryptor.XORKeyStream(message, data) + copy(args.Get(0).([]byte), message) + }) + + n, err := handshakeData.proxyConn.Read(buffer) + + assert.EqualValues(t, len(data), n) + assert.NoError(t, err) + assert.Equal(t, data, buffer) + handshakeData.connMock.AssertExpectations(t) + }) +} diff --git a/mtglib/internal/obfuscated2/server_handshake_test.go b/mtglib/internal/obfuscated2/server_handshake_test.go index 5321c9a..09943ae 100644 --- a/mtglib/internal/obfuscated2/server_handshake_test.go +++ b/mtglib/internal/obfuscated2/server_handshake_test.go @@ -1,14 +1,8 @@ package obfuscated2_test import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "encoding/base64" "testing" - "github.com/9seconds/mtg/v2/internal/testlib" - "github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" ) @@ -16,64 +10,31 @@ import ( type ServerHandshakeTestSuite struct { suite.Suite - connMock *testlib.EssentialsConnMock - proxyConn obfuscated2.Conn - encryptor cipher.Stream - decryptor cipher.Stream + data ServerHandshakeTestData } func (suite *ServerHandshakeTestSuite) SetupTest() { - buf := &bytes.Buffer{} - suite.connMock = &testlib.EssentialsConnMock{} - - encryptor, decryptor, err := obfuscated2.ServerHandshake(buf) - suite.NoError(err) - - suite.proxyConn = obfuscated2.Conn{ - Conn: suite.connMock, - Encryptor: encryptor, - Decryptor: decryptor, - } - - serverEncrypted := buf.Bytes() - - decBlock, _ := aes.NewCipher(serverEncrypted[8 : 8+32]) - suite.decryptor = cipher.NewCTR(decBlock, serverEncrypted[8+32:8+32+16]) - - serverDecrypted := make([]byte, len(serverEncrypted)) - suite.decryptor.XORKeyStream(serverDecrypted, serverEncrypted) - - suite.Equal("3d3d3Q", - base64.RawStdEncoding.EncodeToString(serverDecrypted[8+32+16:8+32+16+4])) - - serverEncryptedReverted := make([]byte, len(serverEncrypted)) - - for i := 0; i < 32+16; i++ { - serverEncryptedReverted[8+i] = serverEncrypted[8+32+16-1-i] - } - - encBlock, _ := aes.NewCipher(serverEncryptedReverted[8 : 8+32]) - suite.encryptor = cipher.NewCTR(encBlock, serverEncryptedReverted[8+32:8+32+16]) + suite.data = NewServerHandshakeTestData(suite.T()) } func (suite *ServerHandshakeTestSuite) TearDownTest() { - suite.connMock.AssertExpectations(suite.T()) + suite.data.connMock.AssertExpectations(suite.T()) } func (suite *ServerHandshakeTestSuite) TestSendToTelegram() { messageToTelegram := []byte{10, 11, 12, 13, 14, 'a'} - suite.connMock. + suite.data.connMock. On("Write", mock.Anything). Return(len(messageToTelegram), nil). Once(). Run(func(args mock.Arguments) { message := make([]byte, len(messageToTelegram)) - suite.decryptor.XORKeyStream(message, args.Get(0).([]byte)) // nolint: forcetypeassert + suite.data.decryptor.XORKeyStream(message, args.Get(0).([]byte)) // nolint: forcetypeassert suite.Equal(messageToTelegram, message) }) - n, err := suite.proxyConn.Write(messageToTelegram) + n, err := suite.data.proxyConn.Write(messageToTelegram) suite.EqualValues(len(messageToTelegram), n) suite.NoError(err) } @@ -82,17 +43,17 @@ func (suite *ServerHandshakeTestSuite) TestRecieveFromTelegram() { messageFromTelegram := []byte{10, 11, 12, 13, 14, 'a'} buffer := make([]byte, len(messageFromTelegram)) - suite.connMock. + suite.data.connMock. On("Read", mock.Anything). Return(len(messageFromTelegram), nil). Once(). Run(func(args mock.Arguments) { message := make([]byte, len(messageFromTelegram)) - suite.encryptor.XORKeyStream(message, messageFromTelegram) + suite.data.encryptor.XORKeyStream(message, messageFromTelegram) copy(args.Get(0).([]byte), message) // nolint: forcetypeassert }) - n, err := suite.proxyConn.Read(buffer) + n, err := suite.data.proxyConn.Read(buffer) suite.EqualValues(len(messageFromTelegram), n) suite.NoError(err) suite.Equal(messageFromTelegram, buffer)