mirror of
https://github.com/nmap/nmap.git
synced 2025-12-07 21:21:31 +00:00
Clean up some typos and differences. Most have been normalized to whatever form of the name occurred in the largest number of scripts. Paulino was contacted directly and requested his email be added to all of his credits.
151 lines
5.5 KiB
Lua
151 lines
5.5 KiB
Lua
local brute = require "brute"
|
|
local creds = require "creds"
|
|
local http = require "http"
|
|
local shortport = require "shortport"
|
|
local stdnse = require "stdnse"
|
|
local string = require "string"
|
|
|
|
description = [[
|
|
Performs brute force password auditing against Joomla web CMS installations.
|
|
|
|
This script initially reads the session cookie and parses the security token to perfom the brute force password auditing.
|
|
It uses the unpwdb and brute libraries to perform password guessing. Any successful guesses are stored using the
|
|
credentials library.
|
|
|
|
Joomla's default uri and form names:
|
|
* Default uri:<code>/administrator/index.php</code>
|
|
* Default uservar: <code>username</code>
|
|
* Default passvar: <code>passwd</code>
|
|
]]
|
|
|
|
---
|
|
-- @usage
|
|
-- nmap -sV --script http-joomla-brute
|
|
-- --script-args 'userdb=users.txt,passdb=passwds.txt,http-joomla-brute.hostname=domain.com,
|
|
-- http-joomla-brute.threads=3,brute.firstonly=true' <target>
|
|
-- nmap -sV --script http-joomla-brute <target>
|
|
--
|
|
-- @output
|
|
-- PORT STATE SERVICE REASON
|
|
-- 80/tcp open http syn-ack
|
|
-- | http-joomla-brute:
|
|
-- | Accounts
|
|
-- | xdeadbee:i79eWBj07g => Login correct
|
|
-- | Statistics
|
|
-- |_ Perfomed 499 guesses in 301 seconds, average tps: 0
|
|
--
|
|
-- @args http-joomla-brute.uri Path to authentication script. Default: /administrator/index.php
|
|
-- @args http-joomla-brute.hostname Virtual Hostname Header
|
|
-- @args http-joomla-brute.uservar sets the http-variable name that holds the
|
|
-- username used to authenticate. Default: username
|
|
-- @args http-joomla-brute.passvar sets the http-variable name that holds the
|
|
-- password used to authenticate. Default: passwd
|
|
-- @args http-joomla-brute.threads sets the number of 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
|
|
--
|
|
--
|
|
-- Based on Patrik Karlsson's http-form-brute
|
|
--
|
|
|
|
author = "Paulino Calderon <calderon@websec.mx>"
|
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
|
categories = {"intrusive", "brute"}
|
|
|
|
|
|
portrule = shortport.http
|
|
|
|
local DEFAULT_JOOMLA_LOGIN_URI = "/administrator/index.php"
|
|
local DEFAULT_JOOMLA_USERVAR = "username"
|
|
local DEFAULT_JOOMLA_PASSVAR = "passwd"
|
|
local DEFAULT_THREAD_NUM = 3
|
|
|
|
local security_token
|
|
local session_cookie_str
|
|
|
|
---
|
|
--This class implements the Brute library (http://nmap.org/nsedoc/lib/brute.html)
|
|
---
|
|
Driver = {
|
|
new = function(self, host, port, options)
|
|
local o = {}
|
|
setmetatable(o, self)
|
|
self.__index = self
|
|
o.host = stdnse.get_script_args('http-joomla-brute.hostname') or host
|
|
o.port = port
|
|
o.uri = stdnse.get_script_args('http-joomla-brute.uri') or DEFAULT_JOOMLA_LOGIN_URI
|
|
o.options = options
|
|
return o
|
|
end,
|
|
|
|
connect = function( self )
|
|
return true
|
|
end,
|
|
|
|
login = function( self, username, password )
|
|
stdnse.print_debug(2, "HTTP POST %s%s with security token %s\n", self.host, self.uri, security_token)
|
|
local response = http.post( self.host, self.port, self.uri, { cookies = session_cookie_str, no_cache = true, no_cache_body = true }, nil,
|
|
{ [self.options.uservar] = username, [self.options.passvar] = password,
|
|
[security_token] = 1, lang = "", option = "com_login", task = "login" } )
|
|
|
|
if response.body and not( response.body:match('name=[\'"]*'..self.options.passvar ) ) then
|
|
stdnse.print_debug(2, "Response:\n%s", response.body)
|
|
local c = creds.Credentials:new(SCRIPT_NAME, self.host, self.port )
|
|
c:add(username, password, creds.State.VALID )
|
|
return true, brute.Account:new( username, password, "OPEN")
|
|
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 password field is there
|
|
if ( response.status == 200 and response.body:match('type=[\'"]password[\'"]')) then
|
|
stdnse.print_debug(1, "Initial check passed. Launching brute force attack")
|
|
session_cookie_str = response.cookies[1]["name"].."="..response.cookies[1]["value"];
|
|
if response.body then
|
|
local _
|
|
_, _, security_token = string.find(response.body, '<input type="hidden" name="(%w+)" value="1" />')
|
|
end
|
|
if security_token then
|
|
stdnse.print_debug(2, "Security Token found:%s", security_token)
|
|
else
|
|
stdnse.print_debug(2, "The security token was not found.")
|
|
return false
|
|
end
|
|
|
|
return true
|
|
else
|
|
stdnse.print_debug(1, "Initial check failed. Password field wasn't found")
|
|
end
|
|
return false
|
|
end
|
|
|
|
}
|
|
---
|
|
--MAIN
|
|
---
|
|
action = function( host, port )
|
|
local status, result, engine
|
|
local uservar = stdnse.get_script_args('http-joomla-brute.uservar') or DEFAULT_JOOMLA_USERVAR
|
|
local passvar = stdnse.get_script_args('http-joomla-brute.passvar') or DEFAULT_JOOMLA_PASSVAR
|
|
local thread_num = stdnse.get_script_args("http-joomla-brute.threads") or DEFAULT_THREAD_NUM
|
|
|
|
engine = brute.Engine:new( Driver, host, port, { uservar = uservar, passvar = passvar } )
|
|
engine:setMaxThreads(thread_num)
|
|
engine.options.script_name = SCRIPT_NAME
|
|
status, result = engine:start()
|
|
|
|
return result
|
|
end
|