1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
local bin = require "bin"
local brute = require "brute"
local creds = require "creds"
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
local string = require "string"
local cassandra = require "cassandra"
description = [[
Performs brute force password auditing against the Cassandra database.
For more information about Cassandra, see:
http://cassandra.apache.org/
]]
---
-- @usage
-- nmap -p 9160 <ip> --script=cassandra-brute
--
-- @output
-- PORT STATE SERVICE VERSION
-- 9160/tcp open apani1?
-- | cassandra-brute:
-- | Accounts
-- | admin:lover - Valid credentials
-- | Statistics
-- |_ Performed 4581 guesses in 1 seconds, average tps: 4581
--
author = "Vlatko Kosturjak"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive", "brute"}
portrule = shortport.port_or_service({9160}, {"cassandra"})
Driver = {
new = function(self, host, port, options)
local o = { host = host, port = port, socket = nmap.new_socket() }
setmetatable(o, self)
self.__index = self
return o
end,
connect = function(self)
return self.socket:connect(self.host, self.port)
end,
-- bit faster login function than in cassandra library (no protocol error checks)
login = function(self, username, password)
local response, magic, size, _
local loginstr = cassandra.loginstr (username, password)
local status, err = self.socket:send(bin.pack(">I",string.len(loginstr)))
local combo = username..":"..password
if ( not(status) ) then
local err = brute.Error:new( "couldn't send length:"..combo )
err:setAbort( true )
return false, err
end
status, err = self.socket:send(loginstr)
if ( not(status) ) then
local err = brute.Error:new( "couldn't send login packet: "..combo )
err:setAbort( true )
return false, err
end
status, response = self.socket:receive_bytes(22)
if ( not(status) ) then
local err = brute.Error:new( "couldn't receive login reply size: "..combo )
err:setAbort( true )
return false, err
end
_, size = bin.unpack(">I", response, 1)
magic = string.sub(response,18,22)
if (magic == cassandra.LOGINSUCC) then
stdnse.debug3("Account SUCCESS: "..combo)
return true, creds.Account:new(username, password, creds.State.VALID)
elseif (magic == cassandra.LOGINFAIL) then
stdnse.debug3("Account FAIL: "..combo)
return false, brute.Error:new( "Incorrect password" )
elseif (magic == cassandra.LOGINACC) then
stdnse.debug3("Account VALID, but wrong password: "..combo)
return false, brute.Error:new( "Good user, bad password" )
else
stdnse.debug3("Unrecognized packet for "..combo)
stdnse.debug3("packet hex: %s", stdnse.tohex(response) )
stdnse.debug3("size packet hex: %s", stdnse.tohex(size) )
stdnse.debug3("magic packet hex: %s", stdnse.tohex(magic) )
local err = brute.Error:new( response )
err:setRetry( true )
return false, err
end
end,
disconnect = function(self)
return self.socket:close()
end,
}
local function noAuth(host, port)
local socket = nmap.new_socket()
local status, result = socket:connect(host, port)
local stat,err = cassandra.login (socket,"default","")
socket:close()
if (stat) then
return true
else
return false
end
end
action = function(host, port)
if ( noAuth(host, port) ) then
return "Any username and password would do, 'default' was used to test."
end
local engine = brute.Engine:new(Driver, host, port )
engine.options.script_name = SCRIPT_NAME
engine.options.firstonly = true
local status, result = engine:start()
return result
end
|