summaryrefslogtreecommitdiffstats
path: root/scripts/nexpose-brute.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/nexpose-brute.nse')
-rw-r--r--scripts/nexpose-brute.nse83
1 files changed, 83 insertions, 0 deletions
diff --git a/scripts/nexpose-brute.nse b/scripts/nexpose-brute.nse
new file mode 100644
index 0000000..38a8199
--- /dev/null
+++ b/scripts/nexpose-brute.nse
@@ -0,0 +1,83 @@
+local brute = require "brute"
+local creds = require "creds"
+local http = require "http"
+local shortport = require "shortport"
+local stdnse = require "stdnse"
+
+local openssl = stdnse.silent_require "openssl"
+
+description=[[
+Performs brute force password auditing against a Nexpose vulnerability scanner
+using the API 1.1.
+
+As the Nexpose application enforces account lockout after 4 incorrect login
+attempts, the script performs only 3 guesses per default. This can be
+altered by supplying the <code>brute.guesses</code> argument a different
+value or 0 (zero) to guess the whole dictionary.
+]]
+
+---
+-- @usage
+-- nmap --script nexpose-brute -p 3780 <ip>
+--
+-- @output
+-- PORT STATE SERVICE REASON VERSION
+-- 3780/tcp open ssl/nexpose syn-ack NeXpose NSC 0.6.4
+-- | nexpose-brute:
+-- | Accounts
+-- | nxadmin:nxadmin - Valid credentials
+-- | Statistics
+-- |_ Performed 5 guesses in 1 seconds, average tps: 5
+--
+
+author = "Vlatko Kosturjak"
+
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+
+categories = {"intrusive", "brute"}
+
+
+portrule = shortport.port_or_service(3780, "nexpose", "tcp")
+
+Driver =
+{
+ new = function (self, host, port)
+ local o = { host = host, port = port }
+ setmetatable (o,self)
+ self.__index = self
+ return o
+ end,
+
+ connect = function ( self ) return true end,
+
+ login = function( self, username, password )
+ local postdata='<?xml version="1.0" encoding="UTF-8"?><LoginRequest sync-id="1" user-id="'..username..'" password="'..password..'"></LoginRequest>'
+ local response = http.post( self.host, self.port, '/api/1.1/xml', { no_cache = true, header = { ["Content-Type"] = "text/xml" } }, nil, postdata )
+
+ if (not(response)) then
+ local err = brute.Error:new( "Couldn't send/receive HTTPS request" )
+ err:setRetry( true )
+ return false, err
+ end
+
+ if (response.body == nil or response.body:match('<LoginResponse.*success="0"')) then
+ stdnse.debug2("Bad login: %s/%s", username, password)
+ return false, brute.Error:new( "Bad login" )
+ elseif (response.body:match('<LoginResponse.*success="1"')) then
+ stdnse.debug1("Good login: %s/%s", username, password)
+ return true, creds.Account:new(username, password, creds.State.VALID)
+ end
+ stdnse.debug1("WARNING: Unhandled response: %s", response.body)
+ return false, brute.Error:new( "incorrect response from server" )
+ end,
+
+ disconnect = function( self ) return true end,
+}
+
+action = function(host, port)
+ local engine = brute.Engine:new(Driver, host, port)
+ engine.options.script_name = SCRIPT_NAME
+ engine.options.max_guesses = tonumber(stdnse.get_script_args('brute.guesses')) or 3
+ local status, result = engine:start()
+ return result
+end