WSL (Windows Subsystem for Linux) allows for a Linux development without a virtual machine. Visual Studio Code runs in a server mode in WSL to talk to the VS Code running in Windows. While setting this up, the author got a firewall dialog box on Windows which peaked their interest. Down the rabbit hole we go!
VS Code is attempting to listen on 0.0.0.0, which is available publicly. After viewing what the commands were actually doing, the author noticed the word WebSocket on port 63574. From reading the scripts for booting the Web Socket server, there was no IP address being specified! To them, this indicated that this was likely done on accident.
The reason why Web Socket are interesting is that it is NOT bound to the Same Origin Policy in the browser. As a result, modifications and data stealing can be performed if the security of the Web Sockets is not done properly. The author links 6+ other articles about this type of attack being done before. A lot of the time, they lead to RCE!
To test this, they simply setup a website that attempts to connect to this address on localhost. The server did not care about the Origin of the request during the initial testing.
The protocol being used over Web Sockets was its own beast though. From looking at the traffic in Wireshark and the source code, they noticed DRM within the calls. Yikes! Luckily for the author, there is a pre-built extension that can be used to make the DRM calls. So, the reversing was not too necessary since the hardwork was being done by some library.
With understanding of the protocol, we can mimic being a VS Code client to the WSL side. Since the remote aspect has code execution BY DESIGN on the application, this leads to a complete game over. How do we actually exploit this though?
In the Web Socket protocol, a Node Inspector instance can be created. Since this is listening on all interfaces, all a victim has to do is visit our personal website to trigger the bug. Once, the outside application or local website connects to the server, arbitrary code can be ran on the machine. Another option is emulating the VS code client directly, but this would require a ton of reverse engineering to figure out.
To fix this, the obvious choices are NOT listening on 0.0.0.0 and checking the Origin of the Web Socket upgrade request. The actual fix was to verify the connection token in the request, which was not being done properly before.
The author had a few other things that they tried but did not work out. First, they tried injected ENV variables into the system to pop a shell, which is possible via the protocol. They attempted a command injection via the execArgv variable as well to no avail because of typescript. The URI handler was looked at to no avail as well. I appreciate the thought process for this added, even if it did not work.
Overall, this was a really good post on stumbling onto some functionality and going down the rabbit hole. These types of local desktop client issues are all over the place with this being a good example of that.