Something about #realworldctf doc2own

The challenge is to pwn the machine when the victim opens a Dash docset. Both Dash and Adobe Brackets are up to date. Actually the designed solution involves no zero day at all. This writeup from Team 217 Real World CTF 2018 — doc2own (in Traditional Chinese) is the expected solution.


The non-zeroday solution

From remote debug to shell

After the VSCode 9333 debugging port issue (https://medium.com/0xcc/visual-studio-code-silently-fixed-a-remote-code-execution-vulnerability-8189e85b486b) I looked at some other javascript based desktop applications, especially editors and IDE, then I came across this exact same vulnerability in Adobe Brackets: CEF remote debugging is vulnerable to dns rebinding attack #14149

It’s weird to have a debugging port in production but Brackets does it. Unlike Atom or VSCode, Brackets is based on libCEF and custom node.js runtime binding. The debugging protocol for web frontend is the same as Chromium.

In the original report, exploit requires dns rebinding to get the random websocket uuid to start a debug session, then use DOM manipulation (there was a bug so Runtime.Evaluate doesn’t work) to inject malicious javascript to editor frontend context. But node.js runtime can not be accessed so you need a V8 engine bug to achieve native code execution and there’s no sandbox... The libCEF is pretty old so all you need is to grab an n-day exploit. But wait, memory corruption is not what I am familiar with.

There’s some special objects in the context: appshell, brackets.

In the challenge you don’t really need a shell because brackets already gives the filesystem access.

Unrestricted file system access almost equals code execution (but requires some trigger). Besides there are two functions that can be turned to instant command execution.

  1. brackets.app.openURLInDefaultBrowser does not limit file:/// protocol, so point to a executable extension like .cmd or .exe equals ShellExecute
  2. The application bundle on macOS is actually a directory with special structure. Opening such bundle will execute a file. Unfortunately brackets.app.showOSFolder can trigger this behavior.
function calc() {
// use brackets.fs to write your own executable
// makedir, writeFile, chmod are your friends
  if (brackets.app.getUserDocumentsDirectory().indexOf('/') === 0) {
brackets.app.showOSFolder('/Applications/Calculator.app');
} else {
brackets.app.openURLInDefaultBrowser('file:///C:/windows/system32/calc.exe');
}
// Note that brackets.getModule is also available. We can even activate a node debugger backdoor
const NodeConnection = brackets.getModule("utils/NodeConnection");
const conn = new NodeConnection();
conn.connect(true);
conn.domains.base.enableDebugger(); // enable *:5858 as a backdoor, which accepts connection from another computer. Just attach it with VSCode or other debugger to execute node.js code
}

The patch killed dns rebinding, but this port is still available. So what if we can invoke from somewhere without same origin policy?

The Dash part

There’s no special reason to choose Dash as this part. Dash is popular for developers, and it uses a WebView that can make cross site AJAX. The WebView in Dash is the same WebKit engine as Safari, I think no one will waste a Safari 0day exploit in our CTF.

Somebody may be thinking about directly load file:/// domain with AJAX. Actually this bug has been killed for a while, including symlink, and the path traversal in GCDWebServer.


Demo

Putting them all together. Looks like both two issues are not so serious, but together they can spawn remote shell:

  • A debugging port that only allows localhost connection
  • A web browser that can bypass same origin policy

Here’s a proof of concept that launches a calculator:

Demo Video

But to my surprise! During the CTF, it didn’t cost Plaid Parliament of Pwning, CyKOR and Eat, Sleep, Pwn, Repeat too much time to find real zero day solutions. And after the game, I did a quick disassemble and found some other new bugs that have been confirmed by the developer.

After reporting to Kapeli, he quickly released a new release, and checked the docset repo to make sure there were no actual attack. Thanks for his response!

The docsets available by default within Dash (including user contributed ones) have been checked and no evidence of these vulnerabilities being exploited has been found.

To protect end users of Dash, I’ll not reveal the unintended bugs now. Please upgrade to Dash 4.4.0 ASAP.