mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
154 lines
4.7 KiB
Go
154 lines
4.7 KiB
Go
//go:build plugin_mongodb || !plugin_selective
|
|
|
|
package services
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"encoding/binary"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestReadMongoMsgRejectsTooLargeResponse(t *testing.T) {
|
|
header := make([]byte, 16)
|
|
binary.LittleEndian.PutUint32(header[:4], uint32(16+maxMongoMessageBody+1))
|
|
|
|
_, err := readMongoMsg(bytes.NewReader(header), time.Second)
|
|
if err == nil {
|
|
t.Fatal("readMongoMsg() error = nil, want too-large response error")
|
|
}
|
|
if !strings.Contains(err.Error(), "too large") {
|
|
t.Fatalf("readMongoMsg() error = %v, want too large", err)
|
|
}
|
|
}
|
|
|
|
func TestReadMongoMsgHandlesEmptyBody(t *testing.T) {
|
|
header := make([]byte, 16)
|
|
binary.LittleEndian.PutUint32(header[:4], 16)
|
|
|
|
got, err := readMongoMsg(bytes.NewReader(header), time.Second)
|
|
if err != nil {
|
|
t.Fatalf("readMongoMsg() error = %v", err)
|
|
}
|
|
if len(got) != 0 {
|
|
t.Fatalf("readMongoMsg() len = %d, want 0", len(got))
|
|
}
|
|
}
|
|
|
|
func TestBuildBSONEncodesFullStringAndBinaryLengths(t *testing.T) {
|
|
longString := strings.Repeat("a", 300)
|
|
longBinary := bytes.Repeat([]byte{0x42}, 300)
|
|
|
|
doc := buildBSON(mongoDoc{"s": longString})
|
|
pos := 4
|
|
if doc[pos] != 0x02 {
|
|
t.Fatalf("first bson type = 0x%02x, want string", doc[pos])
|
|
}
|
|
pos += 1 + len("s") + 1
|
|
if got := binary.LittleEndian.Uint32(doc[pos : pos+4]); got != uint32(len(longString)+1) {
|
|
t.Fatalf("string length = %d, want %d", got, len(longString)+1)
|
|
}
|
|
|
|
doc = buildBSON(mongoDoc{"b": longBinary})
|
|
pos = 4
|
|
if doc[pos] != 0x05 {
|
|
t.Fatalf("first bson type = 0x%02x, want binary", doc[pos])
|
|
}
|
|
pos += 1 + len("b") + 1
|
|
if got := binary.LittleEndian.Uint32(doc[pos : pos+4]); got != uint32(len(longBinary)) {
|
|
t.Fatalf("binary length = %d, want %d", got, len(longBinary))
|
|
}
|
|
}
|
|
|
|
func TestBuildBSONEncodesFloat64Bits(t *testing.T) {
|
|
doc := buildBSON(mongoDoc{"ok": 1.5})
|
|
pos := 4
|
|
if doc[pos] != 0x01 {
|
|
t.Fatalf("bson type = 0x%02x, want double", doc[pos])
|
|
}
|
|
pos += 1 + len("ok") + 1
|
|
if got := binary.LittleEndian.Uint64(doc[pos : pos+8]); got != 0x3ff8000000000000 {
|
|
t.Fatalf("double bits = 0x%x, want 1.5 bits", got)
|
|
}
|
|
}
|
|
|
|
func TestParseMongoCommandReplyReadsSCRAMFields(t *testing.T) {
|
|
payload := []byte("r=clientserver,s=" + base64.StdEncoding.EncodeToString([]byte("salt")) + ",i=4096")
|
|
doc := buildBSON(mongoDoc{
|
|
"ok": 1,
|
|
"conversationId": 7,
|
|
"payload": payload,
|
|
"done": false,
|
|
})
|
|
|
|
reply, err := parseMongoCommandReply(doc)
|
|
if err != nil {
|
|
t.Fatalf("parseMongoCommandReply() error = %v", err)
|
|
}
|
|
if !reply.ok || !reply.conversationSet || reply.conversationID != 7 || string(reply.payload) != string(payload) {
|
|
t.Fatalf("unexpected reply: %+v", reply)
|
|
}
|
|
}
|
|
|
|
func TestParseMongoCommandReplySkipsExtraBSONFields(t *testing.T) {
|
|
payload := []byte("r=clientserver,s=" + base64.StdEncoding.EncodeToString([]byte("salt")) + ",i=4096")
|
|
doc := buildBSON(mongoDoc{
|
|
"$clusterTime": mongoDoc{"clusterTime": 1},
|
|
"operationTime": int64(123),
|
|
"ok": 1,
|
|
"conversationId": 9,
|
|
"payload": payload,
|
|
})
|
|
|
|
reply, err := parseMongoCommandReply(doc)
|
|
if err != nil {
|
|
t.Fatalf("parseMongoCommandReply() error = %v", err)
|
|
}
|
|
if !reply.ok || reply.conversationID != 9 || string(reply.payload) != string(payload) {
|
|
t.Fatalf("unexpected reply: %+v", reply)
|
|
}
|
|
}
|
|
|
|
func TestBuildMongoSCRAMClientFinalRejectsBadNonce(t *testing.T) {
|
|
serverFirst := "r=othernonce,s=" + base64.StdEncoding.EncodeToString([]byte("salt")) + ",i=4096"
|
|
if _, err := buildMongoSCRAMClientFinal("user", "pass", "n=user,r=client", serverFirst); err == nil {
|
|
t.Fatal("buildMongoSCRAMClientFinal() error = nil, want nonce error")
|
|
}
|
|
}
|
|
|
|
func TestBuildMongoSCRAMClientFinalBuildsProof(t *testing.T) {
|
|
serverFirst := "r=clientserver,s=" + base64.StdEncoding.EncodeToString([]byte("salt")) + ",i=4096"
|
|
got, err := buildMongoSCRAMClientFinal("user", "pass", "n=user,r=client", serverFirst)
|
|
if err != nil {
|
|
t.Fatalf("buildMongoSCRAMClientFinal() error = %v", err)
|
|
}
|
|
if !strings.HasPrefix(got, "c=biws,r=clientserver,p=") {
|
|
t.Fatalf("client final = %q", got)
|
|
}
|
|
}
|
|
|
|
func TestClassifyMongoDBErrorType(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
err error
|
|
want ErrorType
|
|
}{
|
|
{"nil", nil, ErrorTypeUnknown},
|
|
{"authentication failed", errors.New("authentication failed"), ErrorTypeAuth},
|
|
{"bad auth", errors.New("bad auth"), ErrorTypeAuth},
|
|
{"dial tcp", errors.New("dial tcp connection refused"), ErrorTypeNetwork},
|
|
{"eof", errors.New("eof"), ErrorTypeNetwork},
|
|
{"unknown", errors.New("random mongodb error"), ErrorTypeUnknown},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := classifyMongoDBErrorType(tt.err); got != tt.want {
|
|
t.Errorf("classifyMongoDBErrorType() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|