Friday, September 28, 2012

Owning a system through a Chrome extension - cr-gpg 0.7.4 vulns

tldr; read all. fun stuff.

I've recently shown a few ways one can abuse certain Chrome extensions. For example it is possible to fingerprint all the extensions current user has installed. Also, they suffer from standard web vulnerabilities. XSS is so common that I've built XSS Chef to assist the exploitation. Together with @theKos we ran workshops on exploiting Chrome extensions.

But the most interesting vulnerabilities may be hidden in the code of plugins (NPAPI .dll, .so files) that are sometimes bundled with extensions. These are binary files that run outside of Google Chrome sandboxes. Plugin functions are of course being called from extensions Javascript code. So, through XSS one could exploit e.g. a buffer overflow, use-after-free and, theoretically, hijack OS user account.

The threat isn't theoretical though. I was able to find a chain of vulnerabilities in cr-gpg extension which handles PGP encryption/decryption from within Gmail interface. Funny thing - the exact same vulnerabilities were reported independently by Gynvael Coldwind - great finds, Gynvael! All reported issues below were present in 0.7.4 version and are fixed in >=0.8.2.

Tuesday, September 11, 2012

If it's a CRIME, then I'm guilty

tldr: see bottom for the script that demonstrates what CRIME might do.

A secret crime 

Juliano Rizzo and Thai Duong did it again. Their new attack on SSL called CRIME, just like their previous one, BEAST is able to extract cookie values (to perform a session hijack) from SSL/TLS encrypted sessions. BEAST was a chosen plaintext attack and generally required:
  • Man-in-the-middle (attacker monitors all encrypted traffic)
  • Encrypted connection to attacked domain (e.g. victim uses https://mybank.com ) with cookies
  • Adaptive Javascript code able to send POST requests to attacked domain
Javascript code tried bruteforcing the cookie value character-by-character. The m-i-t-m component was observing the ciphertext, looking for differences, and once it found one, it communicated with the Javascript to proceed to next character.

CRIME should be similar:
By running JavaScript code in the browser of the victim and sniffing HTTPS traffic, we can decrypt session cookies," Rizzo told Threatpost. "We don't need to use any browser plugin and we use JavaScript to make the attack faster, but in theory we could do it with static HTML. (source)
but the details are not yet known, they are to be released later this month at Ekoparty.

However, there are already speculations on what could the attack rely on. In fact, Thomas Pornin at security.stackexchange.com have most likely figured it out correctly. The hypothesis is that Rizzo and Duong abuse data compression within the encrypted connection. It's likely as e.g. Chromium disabled TLS compression recently.

Compression-based leakage

Thanks to Cross Origin Resource Sharing it is possible (and easy) for JS to send POST request with arbitrary body cross domain. One has limited control over request headers though - e.g. the cookie header will be either attached in full or not at all (it's not possible to set cookies cross-domain). But, the attacker can construct request that looks like this:
POST / HTTP/1.1
Host: thebankserver.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1
Accept: */*
Cookie: secret=XS8b1MWZ0QEKJtM1t+QCofRpCsT2u
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

POST / HTTP/1.1
Host: thebankserver.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1
Accept: */*
Cookie: secret=?

To put it simply, in the POST body we're duplicating part of POST headers. This should compress very nicely. We would know most of the header values (from browser fingerprinting, navigator object etc.), only the cookie value is unknown.

But, we can bruteforce the first character of the cookie by including it in the POST body (we have no control over headers) after the secret= string. By observing the compressed ciphertext length (man in the middle) for all such requests we should be able to spot the difference in one of them. The ciphertext would be shorter due to better compression (longer string occured twice in the request). Then, communicate with JS to proceed to next character and the process continues until the whole cookie value is bruteforced.

That's the theory, at least.

PoC or didn't happen !

There's no time to repeat the whole man-in-the-middle, adaptive JS, encrypted connection set up, so xorninja wrote a script to check the length of zlib deflated HTTP request strings and deduce the cookie values from there. It didn't work, so I've modified the code by adding an adaptive algorithm (encryption length does not always change, sometimes you have to also mutate the POST body to be certain of a character value etc.)

And it works.
Proof of concept can bruteforce the cookie value based on zlib deflated string length only. Cookies can be of arbitrary lengths.

So, what next?

This PoC would have to be included in the whole SSL/mitm/Javascript BEAST-like context so we can check if it actually works in browsers and leaks real-life cookies. Feel free to experiment. I'm waiting for the actual CRIME disclosure.