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
|
local brute = require "brute"
local creds = require "creds"
local ipmi = require "ipmi"
local shortport = require "shortport"
local rand = require "rand"
description = [[
Performs brute force password auditing against IPMI RPC server.
]]
---
-- @usage
-- nmap -sU --script ipmi-brute -p 623 <host>
--
-- @output
-- PORT STATE SERVICE REASON
-- 623/udp open|filtered unknown
-- | ipmi-brute:
-- | Accounts
-- |_ admin:admin => Valid credentials
--
author = "Claudiu Perta"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive", "brute"}
portrule = shortport.port_or_service(623, "asf-rmcp", "udp", {"open", "open|filtered"})
Driver = {
new = function(self, host, port)
local o = {}
setmetatable(o, self)
self.__index = self
o.host = host
o.port = port
return o
end,
connect = function(self)
self.socket = brute.new_socket()
self.socket:set_timeout(
((self.host.times and self.host.times.timeout) or 8) * 1000)
self.socket:connect(self.host, self.port, "udp")
return true
end,
login = function(self, username, password)
local console_session_id = rand.random_string(4)
local console_random_id = rand.random_string(16)
local request = ipmi.session_open_request(console_session_id)
local status, reply
self.socket:send(request)
status, reply = self.socket:receive()
if not status then
return false, brute.Error:new(
"No response to IPMI open session request")
end
local session = ipmi.parse_open_session_reply(reply)
if session["session_payload_type"] ~= ipmi.PAYLOADS["RMCPPLUSOPEN_REP"] then
return false, brute.Error:new("Unknown response to open session request")
end
if session["error_code"] ~= 0 then
return false, brute.Error:new(ipmi.RMCP_ERRORS[session.error_code] or "Unknown error")
end
local bmc_session_id = session["bmc_session_id"]
local rakp1_request = ipmi.rakp_1_request(
bmc_session_id, console_random_id, username)
self.socket:send(rakp1_request)
status, reply = self.socket:receive()
if not status then
return false, brute.Error:new("No response to RAKP1 message")
end
local rakp2_message = ipmi.parse_rakp_1_reply(reply)
if rakp2_message["session_payload_type"] ~= ipmi.PAYLOADS["RAKP2"] then
return false, brute.Error:new("Unknown response to RAPK1 request")
end
if rakp2_message["error_code"] ~= 0 then
return false, brute.Error:new(
ipmi.RMCP_ERRORS[rakp2_message["error_code"]])
end
local hmac_salt = ipmi.rakp_hmac_sha1_salt(
console_session_id,
session["bmc_session_id"],
console_random_id,
rakp2_message["bmc_random_id"],
rakp2_message["bmc_guid"],
0x14,
username
)
local found = ipmi.verify_rakp_hmac_sha1(
hmac_salt, rakp2_message["hmac_sha1"], password)
if found then
return true, creds.Account:new(username, password, creds.State.VALID)
else
return false, brute.Error:new("Incorrect password")
end
end,
disconnect = function(self)
self.socket:close()
end,
check = function(host, port)
return true
end
}
action = function(host, port)
local status, result
local engine = brute.Engine:new(Driver, host, port)
engine.options.script_name = SCRIPT_NAME
status, result = engine:start()
return result
end
|