mirror of
https://github.com/nmap/nmap.git
synced 2025-12-09 14:11:29 +00:00
o [NSE] Added authentication support to MongoDB library and modified existing
scripts to support it. Added the script mongodb-brute to perform password brute force guessing. [Patrik]
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# Nmap Changelog ($Id$); -*-text-*-
|
# Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [NSE] Added authentication support to MongoDB library and modified existing
|
||||||
|
scripts to support it. Added the script mongodb-brute to perform password
|
||||||
|
brute force guessing. [Patrik]
|
||||||
|
|
||||||
o Added a --nsock-engine option to nmap, nping and ncat to enforce use of a
|
o Added a --nsock-engine option to nmap, nping and ncat to enforce use of a
|
||||||
given nsock IO engine. [Henri]
|
given nsock IO engine. [Henri]
|
||||||
|
|
||||||
|
|||||||
@@ -4,17 +4,27 @@
|
|||||||
-- @author Martin Holst Swende
|
-- @author Martin Holst Swende
|
||||||
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
|
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
|
||||||
--
|
--
|
||||||
-- Version 0.1
|
-- Version 0.2
|
||||||
|
--
|
||||||
|
-- @args mongodb.db - the database to use for authentication
|
||||||
|
|
||||||
-- Created 01/13/2010 - v0.1 - created by Martin Holst Swende <martin@swende.se>
|
-- Created 01/13/2010 - v0.1 - created by Martin Holst Swende <martin@swende.se>
|
||||||
|
-- Revised 01/03/2012 - v0.2 - added authentication support <patrik@cqure.net>
|
||||||
|
|
||||||
module("mongodb", package.seeall)
|
module("mongodb", package.seeall)
|
||||||
require("bin")
|
require("bin")
|
||||||
--require("bson")
|
stdnse.silent_require "openssl"
|
||||||
|
|
||||||
|
|
||||||
|
-- this is not yet widely implemented but at least used for authentication
|
||||||
|
-- ideally, it would be used to set the database against which operations,
|
||||||
|
-- that do not require a specific database, should run
|
||||||
|
local arg_DB = stdnse.get_script_args("mongodb.db")
|
||||||
|
|
||||||
-- Some lazy shortcuts
|
-- Some lazy shortcuts
|
||||||
|
|
||||||
local function dbg(str,...)
|
local function dbg(str,...)
|
||||||
stdnse.print_debug("MngoDb:"..str, unpack(arg))
|
stdnse.print_debug(3, "MngoDb:"..str, unpack(arg))
|
||||||
end
|
end
|
||||||
--local dbg =stdnse.print_debug
|
--local dbg =stdnse.print_debug
|
||||||
|
|
||||||
@@ -96,17 +106,23 @@ end
|
|||||||
--@return result : a string of binary data OR error message
|
--@return result : a string of binary data OR error message
|
||||||
function toBson(dict)
|
function toBson(dict)
|
||||||
|
|
||||||
local elements = ""
|
local elements = ""
|
||||||
--Put id first
|
--Put id first
|
||||||
if dict._id then
|
if dict._id then
|
||||||
local status,res = _element_to_bson("_id", dict._id)
|
local status,res = _element_to_bson("_id", dict._id)
|
||||||
if not status then return false, res end
|
if not status then return false, res end
|
||||||
elements = elements..res
|
elements = elements..res
|
||||||
|
elseif ( dict._cmd ) then
|
||||||
|
for k, v in pairs(dict._cmd) do
|
||||||
|
local status,res = _element_to_bson(k, v)
|
||||||
|
if not status then return false, res end
|
||||||
|
elements = elements..res
|
||||||
|
end
|
||||||
end
|
end
|
||||||
--Concatenate binary values
|
--Concatenate binary values
|
||||||
for key, value in pairs( dict ) do
|
for key, value in pairs( dict ) do
|
||||||
dbg("dictionary to bson : key,value =(%s,%s)",key,value)
|
if key ~= "_id" and key ~= "_cmd" then
|
||||||
if key ~= "_id" then
|
dbg("dictionary to bson : key,value =(%s,%s)",key,value)
|
||||||
local status,res = _element_to_bson(key,value)
|
local status,res = _element_to_bson(key,value)
|
||||||
if not status then return false, res end
|
if not status then return false, res end
|
||||||
elements = elements..res
|
elements = elements..res
|
||||||
@@ -463,7 +479,6 @@ function buildInfoQuery(responseTo)
|
|||||||
local query = {buildinfo = 1}
|
local query = {buildinfo = 1}
|
||||||
return createQuery(collectionName, query)
|
return createQuery(collectionName, query)
|
||||||
end
|
end
|
||||||
|
|
||||||
--Reads an int32 from data
|
--Reads an int32 from data
|
||||||
--@return int32 value
|
--@return int32 value
|
||||||
--@return data unread
|
--@return data unread
|
||||||
@@ -578,6 +593,38 @@ function query(socket, data)
|
|||||||
end
|
end
|
||||||
return true,result, residualData
|
return true,result, residualData
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function login(socket, db, username, password)
|
||||||
|
|
||||||
|
local collectionName = ("%s.$cmd"):format(arg_DB or db)
|
||||||
|
local query = { getnonce = 1 }
|
||||||
|
local status, packet = createQuery(collectionName, query)
|
||||||
|
local response
|
||||||
|
status, response = mongodb.query(socket, packet)
|
||||||
|
if ( not(status) or not(response.nonce) ) then
|
||||||
|
return false, "Failed to retrieve nonce"
|
||||||
|
end
|
||||||
|
|
||||||
|
local nonce = response.nonce
|
||||||
|
local pwdigest = stdnse.tohex(openssl.md5(username .. ':mongo:' ..password))
|
||||||
|
local digest = stdnse.tohex(openssl.md5(nonce .. username .. pwdigest))
|
||||||
|
|
||||||
|
query = { user = username, nonce = nonce, key = digest }
|
||||||
|
query._cmd = { authenticate = 1 }
|
||||||
|
|
||||||
|
local status, packet = createQuery(collectionName, query)
|
||||||
|
status, response = mongodb.query(socket, packet)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return status, response
|
||||||
|
elseif ( response.errmsg == "auth fails" ) then
|
||||||
|
return false, "Authentication failed"
|
||||||
|
elseif ( response.errmsg ) then
|
||||||
|
return false, response.errmsg
|
||||||
|
end
|
||||||
|
return status, response
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Converts a quert result as received from MongoDB query into nmap "result" table
|
--- Converts a quert result as received from MongoDB query into nmap "result" table
|
||||||
-- @param resultTable table as returned from a quer
|
-- @param resultTable table as returned from a quer
|
||||||
-- @return table suitable for <code>stdnse.format_output</code>
|
-- @return table suitable for <code>stdnse.format_output</code>
|
||||||
|
|||||||
101
scripts/mongodb-brute.nse
Normal file
101
scripts/mongodb-brute.nse
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
description = [[
|
||||||
|
Performs brute force password guessing against the MongoDB database.
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @usage
|
||||||
|
-- nmap -p 27017 <ip> --script mongodb-brute
|
||||||
|
--
|
||||||
|
-- @output
|
||||||
|
-- PORT STATE SERVICE
|
||||||
|
-- 27017/tcp open mongodb
|
||||||
|
-- | mongodb-brute:
|
||||||
|
-- | Accounts
|
||||||
|
-- | root:Password1 - Valid credentials
|
||||||
|
-- | Statistics
|
||||||
|
-- |_ Performed 3542 guesses in 9 seconds, average tps: 393
|
||||||
|
--
|
||||||
|
|
||||||
|
require 'brute'
|
||||||
|
require 'mongodb'
|
||||||
|
require 'shortport'
|
||||||
|
|
||||||
|
author = "Patrik Karlsson"
|
||||||
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"intrusive", "brute"}
|
||||||
|
|
||||||
|
local arg_db = stdnse.get_script_args(SCRIPT_NAME .. ".db") or "admin"
|
||||||
|
|
||||||
|
portrule = shortport.port_or_service({27017}, {"mongodb"})
|
||||||
|
|
||||||
|
Driver = {
|
||||||
|
|
||||||
|
new = function(self, host, port, options)
|
||||||
|
local o = { host = host, port = port, sock = nmap.new_socket() }
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
return o
|
||||||
|
end,
|
||||||
|
|
||||||
|
connect = function(self)
|
||||||
|
return self.sock:connect(self.host, self.port)
|
||||||
|
end,
|
||||||
|
|
||||||
|
login = function(self, username, password)
|
||||||
|
local status, resp = mongodb.login(self.sock, arg_db, username, password)
|
||||||
|
if ( status ) then
|
||||||
|
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||||
|
elseif ( resp ~= "Authentication failed" ) then
|
||||||
|
local err = brute.Error:new( err )
|
||||||
|
err:setRetry( true )
|
||||||
|
return false, err
|
||||||
|
end
|
||||||
|
return false, brute.Error:new( "Incorrect password" )
|
||||||
|
end,
|
||||||
|
|
||||||
|
disconnect = function(self)
|
||||||
|
return self.sock:close()
|
||||||
|
end,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
local function needsAuth(host, port)
|
||||||
|
local socket = nmap.new_socket()
|
||||||
|
local status, result = socket:connect(host, port)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to connect to server"
|
||||||
|
end
|
||||||
|
|
||||||
|
local packet
|
||||||
|
status, packet = mongodb.listDbQuery()
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, result
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Send packet
|
||||||
|
status, result = mongodb.query(socket, packet)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, result
|
||||||
|
end
|
||||||
|
|
||||||
|
socket:close()
|
||||||
|
if ( status and result.errmsg ) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
action = function(host, port)
|
||||||
|
|
||||||
|
if ( not(needsAuth(host, port)) ) then
|
||||||
|
return "No authentication needed"
|
||||||
|
end
|
||||||
|
|
||||||
|
local engine = brute.Engine:new(Driver, host, port )
|
||||||
|
|
||||||
|
engine.options.script_name = SCRIPT_NAME
|
||||||
|
engine.options.firstonly = true
|
||||||
|
status, result = engine:start()
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
@@ -29,18 +29,22 @@ Attempts to get a list of tables from a MongoDB database.
|
|||||||
-- | name = admin
|
-- | name = admin
|
||||||
-- |_ totalSize = 167772160
|
-- |_ totalSize = 167772160
|
||||||
|
|
||||||
-- version 0.1
|
-- version 0.2
|
||||||
-- Created 01/12/2010 - v0.1 - created by Martin Holst Swende <martin@swende.se>
|
-- Created 01/12/2010 - v0.1 - created by Martin Holst Swende <martin@swende.se>
|
||||||
|
-- Revised 01/03/2012 - v0.2 - added authentication support <patrik@cqure.net>
|
||||||
|
|
||||||
author = "Martin Holst Swende"
|
author = "Martin Holst Swende"
|
||||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||||
categories = {"default", "discovery", "safe"}
|
categories = {"default", "discovery", "safe"}
|
||||||
|
|
||||||
|
dependencies = {"mongodb-brute"}
|
||||||
|
|
||||||
|
require "creds"
|
||||||
require "mongodb"
|
require "mongodb"
|
||||||
require "shortport"
|
require "shortport"
|
||||||
|
|
||||||
portrule = shortport.port_or_service({27017}, {"mongodb"})
|
portrule = shortport.port_or_service({27017}, {"mongodb"})
|
||||||
|
|
||||||
function action(host,port)
|
function action(host,port)
|
||||||
|
|
||||||
local socket = nmap.new_socket()
|
local socket = nmap.new_socket()
|
||||||
@@ -56,6 +60,19 @@ function action(host,port)
|
|||||||
|
|
||||||
try( socket:connect(host, port) )
|
try( socket:connect(host, port) )
|
||||||
|
|
||||||
|
-- uglyness to allow creds.mongodb to work, as the port is not recognized
|
||||||
|
-- as mongodb, unless a service scan was run
|
||||||
|
local ps = port.service
|
||||||
|
port.service = 'mongodb'
|
||||||
|
local c = creds.Credentials:new(creds.ALL_DATA, host, port)
|
||||||
|
for cred in c:getCredentials(creds.State.VALID + creds.State.PARAM) do
|
||||||
|
local status, err = mongodb.login(socket, "admin", cred.user, cred.pass)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
port.service = ps
|
||||||
|
|
||||||
local req, result, packet, err, status
|
local req, result, packet, err, status
|
||||||
--Build packet
|
--Build packet
|
||||||
status, packet = mongodb.listDbQuery()
|
status, packet = mongodb.listDbQuery()
|
||||||
|
|||||||
@@ -41,18 +41,25 @@ Attempts to get build info and server status from a MongoDB database.
|
|||||||
-- | note = fields vary by platform
|
-- | note = fields vary by platform
|
||||||
-- |_ page_faults = 0
|
-- |_ page_faults = 0
|
||||||
|
|
||||||
-- version 0.2
|
-- version 0.3
|
||||||
-- Created 01/12/2010 - v0.1 - created by Martin Holst Swende <martin@swende.se>
|
-- Created 01/12/2010 - v0.1 - created by Martin Holst Swende <martin@swende.se>
|
||||||
|
-- Revised 01/03/2012 - v0.3 - added authentication support <patrik@cqure.net>
|
||||||
|
|
||||||
|
|
||||||
author = "Martin Holst Swende"
|
author = "Martin Holst Swende"
|
||||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||||
categories = {"default", "discovery", "safe"}
|
categories = {"default", "discovery", "safe"}
|
||||||
|
|
||||||
|
dependencies = {"mongodb-brute"}
|
||||||
|
|
||||||
|
require "creds"
|
||||||
require "mongodb"
|
require "mongodb"
|
||||||
require "shortport"
|
require "shortport"
|
||||||
|
|
||||||
|
local arg_db = stdnse.get_script_args(SCRIPT_NAME .. ".db") or "admin"
|
||||||
|
|
||||||
portrule = shortport.port_or_service({27017}, {"mongodb"})
|
portrule = shortport.port_or_service({27017}, {"mongodb"})
|
||||||
|
|
||||||
function action(host,port)
|
function action(host,port)
|
||||||
|
|
||||||
local socket = nmap.new_socket()
|
local socket = nmap.new_socket()
|
||||||
@@ -68,9 +75,22 @@ function action(host,port)
|
|||||||
|
|
||||||
try( socket:connect(host, port) )
|
try( socket:connect(host, port) )
|
||||||
|
|
||||||
local req, status, statusresponse, buildinfo, packet, err
|
local req, statusresponse, buildinfo, err
|
||||||
|
|
||||||
status, packet = mongodb.serverStatusQuery()
|
-- uglyness to allow creds.mongodb to work, as the port is not recognized
|
||||||
|
-- as mongodb, unless a service scan was run
|
||||||
|
local ps = port.service
|
||||||
|
port.service = 'mongodb'
|
||||||
|
local c = creds.Credentials:new(creds.ALL_DATA, host, port)
|
||||||
|
for cred in c:getCredentials(creds.State.VALID + creds.State.PARAM) do
|
||||||
|
local status, err = mongodb.login(socket, arg_db, cred.user, cred.pass)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
port.service = ps
|
||||||
|
|
||||||
|
local status, packet = mongodb.serverStatusQuery()
|
||||||
if not status then return packet end
|
if not status then return packet end
|
||||||
|
|
||||||
status,statQResult = mongodb.query(socket, packet)
|
status,statQResult = mongodb.query(socket, packet)
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ Entry { filename = "membase-http-info.nse", categories = { "discovery", "safe",
|
|||||||
Entry { filename = "memcached-info.nse", categories = { "discovery", "safe", } }
|
Entry { filename = "memcached-info.nse", categories = { "discovery", "safe", } }
|
||||||
Entry { filename = "metasploit-xmlrpc-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "metasploit-xmlrpc-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "modbus-discover.nse", categories = { "discovery", "intrusive", } }
|
Entry { filename = "modbus-discover.nse", categories = { "discovery", "intrusive", } }
|
||||||
|
Entry { filename = "mongodb-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "mongodb-databases.nse", categories = { "default", "discovery", "safe", } }
|
Entry { filename = "mongodb-databases.nse", categories = { "default", "discovery", "safe", } }
|
||||||
Entry { filename = "mongodb-info.nse", categories = { "default", "discovery", "safe", } }
|
Entry { filename = "mongodb-info.nse", categories = { "default", "discovery", "safe", } }
|
||||||
Entry { filename = "ms-sql-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "ms-sql-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
|
|||||||
Reference in New Issue
Block a user