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
|
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 = brute.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(string.pack(">I4", #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
local 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
local size = string.unpack(">I4", 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
|