Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mongodb: Use OP_QUERY for buildinfo for wire proto < 6 #330

Merged
merged 1 commit into from
Oct 13, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 10 additions & 43 deletions modules/mongodb/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,6 @@ func (scan *scan) Close() {
defer scan.close()
}

// getCommandMsg returns a mongodb message containing the specified BSON-encoded command.
// metdata and commandArgs expected to be BSON byte arrays.
func getCommandMsg(database string, commandName string, metadata []byte, commandArgs []byte) []byte {
dblen := len(database) + 1
cnlen := len(commandName) + 1
mdlen := len(metadata)
calen := len(commandArgs)

msglen := MSGHEADER_LEN + dblen + cnlen + len(metadata) + len(commandArgs)
out := make([]byte, msglen)
// msg header
binary.LittleEndian.PutUint32(out[0:], uint32(msglen))
binary.LittleEndian.PutUint32(out[12:], OP_COMMAND)
// command msg
idx := MSGHEADER_LEN
copy(out[idx:idx+dblen], []byte(database))
idx += dblen
copy(out[idx:idx+cnlen], []byte(commandName))
idx += cnlen
copy(out[idx:idx+mdlen], metadata)
idx += mdlen
copy(out[idx:idx+calen], commandArgs)
return out
}

// getIsMasterMsg returns a mongodb message containing isMaster command.
// https://docs.mongodb.com/manual/reference/command/isMaster/
func getIsMasterMsg() []byte {
Expand All @@ -78,21 +53,15 @@ func getIsMasterMsg() []byte {
return query_msg
}

// getBuildInfoCommandMsg returns a mongodb message containing a command to retrieve MongoDB build info.
func getBuildInfoCommandMsg() []byte {
metaData, err := bson.Marshal(bson.M{"buildInfo": 1})
// getBuildInfoQuery returns a mongodb message containing a command to retrieve MongoDB build info.
func getBuildInfoQuery() []byte {
query, err := bson.Marshal(bson.M{"buildinfo": 1})
if err != nil {
// programmer error
log.Fatalf("Invalid BSON: %v", err)
}
commandArgs, err := bson.Marshal(bson.M{})
if err != nil {
// programmer error
log.Fatalf("Invalid BSON: %v", err)
}
// "test" collection gleaned from tshark
command_msg := getCommandMsg("test", "buildInfo", metaData, commandArgs)
return command_msg
query_msg := getOpQuery("admin.$cmd", query)
return query_msg
}

// getOpQuery returns a mongodb OP_QUERY message containing the specified BSON-encoded query.
Expand Down Expand Up @@ -191,7 +160,7 @@ func (scanner *Scanner) Init(flags zgrab2.ScanFlags) error {
f, _ := flags.(*Flags)
scanner.config = f
scanner.isMasterMsg = getIsMasterMsg()
scanner.buildInfoCommandMsg = getBuildInfoCommandMsg()
scanner.buildInfoCommandMsg = getBuildInfoQuery()
scanner.buildInfoOpMsg = getBuildInfoOpMsg()
return nil
}
Expand Down Expand Up @@ -313,14 +282,12 @@ func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, inter
var resplen_offset int
var resp_offset int

// Gleaned from wireshark - if "MaxWireVersion" is less than 7, then
// "build info" command should be sent in an OP_COMMAND with the query sent
// and response retrieved at "metadata" offset. At 7 and above, should
// be sent as an OP_MSG in the "section" field, and response is at "body" offset
if result.IsMaster.MaxWireVersion < 7 {
// See: https://github.com/mongodb/specifications/blob/master/source/message/OP_MSG.rst
// "OP_MSG is only available in MongoDB 3.6 (maxWireVersion >= 6) and later."
if result.IsMaster.MaxWireVersion < 6 {
query = scanner.buildInfoCommandMsg
resplen_offset = 4
resp_offset = 0
resp_offset = 20
} else {
query = scanner.buildInfoOpMsg
resplen_offset = 5
Expand Down