diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:42:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:42:04 +0000 |
commit | 0d47952611198ef6b1163f366dc03922d20b1475 (patch) | |
tree | 3d840a3b8c0daef0754707bfb9f5e873b6b1ac13 /scripts/ajp-brute.nse | |
parent | Initial commit. (diff) | |
download | nmap-upstream.tar.xz nmap-upstream.zip |
Adding upstream version 7.94+git20230807.3be01efb1+dfsg.upstream/7.94+git20230807.3be01efb1+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | scripts/ajp-brute.nse | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/scripts/ajp-brute.nse b/scripts/ajp-brute.nse new file mode 100644 index 0000000..76c9a1e --- /dev/null +++ b/scripts/ajp-brute.nse @@ -0,0 +1,113 @@ +local ajp = require "ajp" +local base64 = require "base64" +local brute = require "brute" +local creds = require "creds" +local http = require "http" +local shortport = require "shortport" +local stdnse = require "stdnse" + +description = [[ +Performs brute force passwords auditing against the Apache JServ protocol. +The Apache JServ Protocol is commonly used by web servers to communicate with +back-end Java application server containers. +]] + +--- +-- @usage +-- nmap -p 8009 <ip> --script ajp-brute +-- +-- @output +-- PORT STATE SERVICE +-- 8009/tcp open ajp13 +-- | ajp-brute: +-- | Accounts +-- | root:secret - Valid credentials +-- | Statistics +-- |_ Performed 1946 guesses in 23 seconds, average tps: 82 +-- +-- @args ajp-brute.path URL path to request. Default: / + +author = "Patrik Karlsson" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"intrusive", "brute"} + + +portrule = shortport.port_or_service(8009, 'ajp13', 'tcp') + +local arg_url = stdnse.get_script_args(SCRIPT_NAME .. ".path") or "/" + +local function fail(err) return stdnse.format_output(false, err) end + +Driver = { + + new = function(self, host, port, options) + local o = { host = host, + port = port, + options = options, + helper = ajp.Helper:new(host, port) + } + setmetatable(o, self) + self.__index = self + return o + end, + + connect = function(self) + return self.helper:connect(brute.new_socket()) + end, + + disconnect = function(self) + return self.helper:close() + end, + + login = function(self, user, pass) + local headers = { + ["Authorization"] = ("Basic %s"):format(base64.enc(user .. ":" .. pass)) + } + local status, response = self.helper:get(arg_url, headers) + + if ( not(status) ) then + local err = brute.Error:new( response ) + err:setRetry( true ) + return false, err + elseif( response.status ~= 401 ) then + return true, creds.Account:new(user, pass, creds.State.VALID) + end + return false, brute.Error:new( "Incorrect password" ) + end, + +} + + +action = function(host, port) + + local helper = ajp.Helper:new(host, port) + if ( not(helper:connect()) ) then + return fail("Failed to connect to server") + end + + local status, response = helper:get(arg_url) + if ( not(response.headers['www-authenticate']) ) then + return "\n URL does not require authentication" + end + + local challenges = http.parse_www_authenticate(response.headers['www-authenticate']) + local options = { scheme = nil } + for _, challenge in ipairs(challenges or {}) do + if ( challenge and challenge.scheme and challenge.scheme:lower() == "basic") then + options.scheme = challenge.scheme:lower() + break + end + end + + if ( not(options.scheme) ) then + return fail("Could not find a supported authentication scheme") + end + + local engine = brute.Engine:new(Driver, host, port ) + engine.options.script_name = SCRIPT_NAME + + local status, result = engine:start() + if ( status ) then + return result + end +end |