Upload
johnwilander
View
116
Download
2
Embed Size (px)
DESCRIPTION
Presentation given at GeekMeet in Stockholm, January 2013. Covers the risks with hotlinking JavaScript and images in your websites.
Citation preview
Hotlinking is Too Hot for Comfort
@johnwilander, GeekMeet Stockholm 2013
@johnwilander
Hotlinking ==
<img src="http://3rdparty.net">
<script src="http://3rdparty.net"></script>
@johnwilander
"You Are What You Include"by Nikiforakis et alhttp://seclab.cs.ucsb.edu/media/uploads/papers/jsinclusions.pdf
The Paper.
@johnwilander
Crawled
• Alexa Top 10,000
• Up to 500 pages per domain
• 3,000,000+ pages in total
@johnwilander
@johnwilander
Sites typically hotlink JavaScriptfrom 5-15 remote hosts
@johnwilander
If I can run a script on your site or app, what
can I do?
@johnwilander
Browser Exploitation Frameworkhttp://beefproject.com/
@johnwilander
So, who is able to run scripts on your site?
@johnwilander
Service .js% of Top
AlexaWeb analytics www.google-analytics.com/ga.js 68.37%
Dynamic Ads pagead2.googlesyndication.com/pagead/show_ads.js 23.87%
Web analytics www.google-analytics.com/urchin.js 17.32%
Social Networking connect.facebook.net/en_us/all.js 16.82%
Social Networking platform.twitter.com/widgets.js 13.87%
Social Networking & Web analytics s7.addthis.com/js/250/addthis_widget.js 12.68%
Web analytics & Tracking edge.quantserve.com/quant.js 11.98%
Market Research b.scorecardresearch.com/beacon.js 10.45%
Google Helper Functions www.google.com/jsapi 10.14%
Web analytics ssl.google-analytics.com/ga.js 10.12%
@johnwilander
Service .js% of Top
AlexaWeb analytics www.google-analytics.com/ga.js 68.37%
Dynamic Ads pagead2.googlesyndication.com/pagead/show_ads.js 23.87%
Web analytics www.google-analytics.com/urchin.js 17.32%
Social Networking connect.facebook.net/en_us/all.js 16.82%
Social Networking platform.twitter.com/widgets.js 13.87%
Social Networking & Web analytics s7.addthis.com/js/250/addthis_widget.js 12.68%
Web analytics & Tracking edge.quantserve.com/quant.js 11.98%
Market Research b.scorecardresearch.com/beacon.js 10.45%
Google Helper www.google.com/jsapi 10.14%
Web analytics ssl.google-analytics.com/ga.js 10.12%
@johnwilander
Service .js% of Top
AlexaWeb analytics www.google-analytics.com/ga.js 68.37%
Dynamic Ads pagead2.googlesyndication.com/pagead/show_ads.js 23.87%
Web analytics www.google-analytics.com/urchin.js 17.32%
Social Networking connect.facebook.net/en_us/all.js 16.82%
Social Networking platform.twitter.com/widgets.js 13.87%
Social Networking & Web analytics s7.addthis.com/js/250/addthis_widget.js 12.68%
Web analytics & Tracking edge.quantserve.com/quant.js 11.98%
Market Research b.scorecardresearch.com/beacon.js 10.45%
Google Helper www.google.com/jsapi 10.14%
Web analytics ssl.google-analytics.com/ga.js 10.12%
ga.js and urchin.js are two different versions of Google Analytics => probably not on the same site.
68.37+17.32 ≈ 85% of Alexa Top 10,000
Please don't be evil, Google.
@johnwilander
@johnwilander
https://github.com/Craga89/qTip2/issues/286
2011-12-08 there was an issue reported
@johnwilander
"sends your browser agent and another piece of info"
@johnwilander
"old Wordpress install … security vulnerability"
"infected nearly all JS files on my site"
@johnwilander
"The offending scripts have been removedas well as the Wordpress blog"
"cronjob setup that checks for changes"
"Closed"
@johnwilander
"it downloads some other exploits"
Comment
@johnwilander
https://github.com/Craga89/qTip2/issues/286
One month later …
@johnwilander
"issue is still present"
@johnwilander
"Looks like the security hole wasn't plugged after all"
"Please … do not hotlink"
"Reopened"
@johnwilander
"I've disabled the Wordpress blog on my site"
"Closed"
@johnwilander
Questions on qtip Hack
• How many end user PCs were trojanized?
• How many passwords stolen?
• How many credit card numbers stolen?
• How many internet bank logins remote controlled?
@johnwilander
Stale Hotlink Domains
@johnwilander
Alexa Top 1,000,000
Alexa Top 10,000
…Hotlinks
@johnwilander
Alexa Top 1,000,000
Alexa Top 10,000
Other domains
Hotlinks
@johnwilander
Alexa Top 1,000,000
Alexa Top 10,000
Other domains
Stale domains,open for purchase
@johnwilander
The Stale Numbers
• +3,000,000 pages crawled
• 4,225 hotlinked domains outsideAlexa Top 1,000,000
• 50 domains stale, i.e. no longer registered
@johnwilander
Nick et al purchased two of those stale
domains
@johnwilander
Alexa Top 10,000
Stale domains
goldprice.org
hbotapadmin.com
hbo.com
blogtools.us
@johnwilander
Alexa Top 10,000
Stale domains
goldprice.org
hbotapadmin.com
hbo.com
23 less popular sites
blogtools.us
…
@johnwilander
Alexa Top 10,000
Stale domains
goldprice.org
hbotapadmin.com
hbo.com
blogtools.us
…
blogtools.us
hbotapadmin.com
80,466 4,615Visits (15 days)
23 less popular sites
@johnwilander
Alexa Top 10,000
Stale domains
goldprice.org
hbotapadmin.com
hbo.com
blogtools.us
…
Including domains
Including pages
blogtools.us
hbotapadmin.com
80,466
24
84
4,615
4
41
Visits (15 days)
23 less popular sites
@johnwilander
The Case of the Unauthorized Image
@johnwilander
”Hotlinked images,can they bite me too?”
@johnwilander
<script src="http://3rdparty.net"></script>
<img src="http://3rdparty.net">
OK, this might be bad
But this?
@johnwilander
@johnwilander
What if Meetup allowedprofile images to be hotlinked?
@johnwilander
Meanwhile, at the Attacker’s Server …
@johnwilander
src/main/webapp/ css/… img/thumb_john.jpg js/… html/…
Including images typically looks like thisin a web app project:
But an attacker could instead resolve that image URL in code, like this …
@johnwilander
private static final String IMG_PATH = "/img/thumb_john.jpg";private boolean returnUnauthorized = false;@GET@Path("/thumb_john.jpg")@Produces("image/jpg")public Response getEvilImage(@Context ServletContext context) { if (returnUnauthorized) { return Response.status(Response.Status.UNAUTHORIZED) .header("WWW-Authenticate", "Basic").build(); } else { try { BufferedImage image = ImageIO.read(context.getResourceAsStream(IMG_PATH)); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ImageIO.write(image, "jpg", outputStream); byte[] imageData = outputStream.toByteArray(); return Response.ok(imageData).build(); } catch (IOException e) { e.printStackTrace(); return Response.serverError().build(); } }}
@johnwilander
private static final String IMG_PATH = "/images/thumb_john.jpg";private boolean returnUnauthorized = false;@GET@Path("/thumb_john.jpg")@Produces("image/jpg")public Response getEvilImage(@Context ServletContext context) { if (returnUnauthorized) { return Response.status(Response.Status.UNAUTHORIZED) .header("WWW-Authenticate", "Basic").build(); } else { try { BufferedImage image = ImageIO.read(context.getResourceAsStream(IMG_PATH)); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ImageIO.write(image, "jpg", outputStream); byte[] imageData = outputStream.toByteArray(); return Response.ok(imageData).build(); } catch (IOException e) { e.printStackTrace(); return Response.serverError().build(); } }}
… adding some nasty, alternate behavior.
@johnwilander
@johnwilander
Now what will John Doe enter?
@johnwilander
Some more nails for the coffin …
• CSS files can execute JavaScript (expressions in IE6-7 and XBL in Firefox)
• SVGs can execute JavaScript
• Gif files can be edited to become executable JavaScript and HTML