JSEC1065 - Coindrawer Non-persistent XSS disclosure (Buy/sell orders feature, cancel_order param)

Posted on

Coindrawer is a “simple cryptocoin wallet and trading platform” that allows users to store and trade Bitcoin, Litecoin, and other cryptocurrencies.

I am disclosing a non-persistent XSS vulnerability. The issue became unexploitable when Coindrawer removed the buy/sell Order History function from their site on 26 April 2014.

Coindrawer has not yet committed to honouring this submission under its bug bounty program.

Update 27 July 2014 - Coindrawer have shut down their service and have honoured this submission under their program. See more at Coindrawer Bug Bounty finale.

Estimated severity

Impact: Medium (XSS can perform unwanted actions in the context of the logged-in user, such as steal funds)

Difficulty: Requires a medium to high amount of user interaction (clicking malicious link, viewing iframe, etc.) and can be detected by in-browser non-persistent XSS protections such as those in Internet Explorer, Chrome, and Firefox (via Noscript). Attack is frameable due to lack of X-Frame-Options.

Non-persistent XSS

The Order Detail function retrieves order data using AJAX. The AJAX response has a Content-Type of text/html and the parameter cancel_order is returned to the requester unsanitized. This leads to non-persistent XSS in the cancel_order parameter:

JSEC1065 - Coindrawer Non-persistent XSS disclosure (Buy/sell orders feature, cancel_order param) /images/201405_coindrawer_jsec1065_xss_burp.png JSEC1065 - Coindrawer Non-persistent XSS disclosure (Buy/sell orders feature, cancel_order param) /images/201405_coindrawer_jsec1065_xss_browser.png

There are some interesting conditions that make this attack possible:

  • session_token, which is usually used by Coindrawer's platform as a CSRF token, is not checked when requesting the data. Of note, if the cancel_order parameter is set to true (or some similar value, I didn't keep logs and the function has since been disabled) and the bsorder_id is set to a user's pending Buy BTC or Sell BTC order ID, then the pending order is cancelled. This provides a CSRF attack (provided the attacker knows the value of one of victim's bsorder_id's) that can be used to cancel a user's order, but it is not needed because…
  • Coindrawer does not check that a given bsorder_id actually belongs to the user submitting a cancel_order=true request. This gives a Direct Object Reference attack that allows an attacker to cancel any user's pending Buy BTC or Sell BTC order, provided the attacker knows the value of the bsorder_id (or is willing to iterate over a large number of values. Values do not seem to be sequential.)

These bugs aren't terribly exciting, as knowing a bsorder_id is difficult unless it's one of your own. However, only due to these conditions can we prepare an XSS attack that will work against any victim account, bypassing CSRF protection and the need to know of a bsorder_id that the victim has access to (as all users have access to all bsorder_id's)

Disclosure Timeline

Coindrawer's actions are in bold.

  • 3 April 2014 - Submission of JSEC1065 (Non-persistent XSS in cancel_order param, buy/sell function) and notification of disclosure date (1 May 2014) due to lack of confidence in Coindrawer's Bug Bounty program.
  • 14 April 2014 - Mike Lucente, CTO of Coindrawer acknowledges disclosure date.
  • 15 April 2014 - Discussion back and forth regarding disclosure and Coindrawer's Bug Bounty program I remind Coindrawer that they can ask for an extension to the disclosure dates if needed. No response.
  • 26 April 2014 - Coindrawer resolves issue by totally removing buy/sell functionality from platform
  • 1 May 2014 - Public disclosure.

I have a series of posts regarding Coindrawer: