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 vulnerability that allowed an attacker to buy and sell BTC for USD at an arbitrary exchange rate. The issue became unexploitable when Coindrawer suspended the feature earlier this year citing “banking and regulatory challenges”. Coindrawer entirely removed the suspended function from their site on 26 April 2014.
Coindrawer chose to ignore my report and repeated requests for updates. 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.
Impact: High (theft of Bitcoin and USD from Coindrawer)
Difficulty: Sale of Bitcoin at an arbitrary exchange rate is suspected to have required a high level of administrator interaction, as it required a cheque to be sent to the attacker. Purchase of Bitcoin is suspected to have required no administrator interaction.
Coindrawer and their BTC buy/sell facility
Coindrawer allowed users to buy and sell BTC for USD. In both cases, the transaction existed only between Coindrawer and the user. Coindrawer did not provide a market or exchange like Mt. Gox or BTC-E, but acted as more of a vendor like Coinbase or CoinJar. Coindrawer themselves would offer to buy or sell BTC at the current market rate, presumably an average of rates across multiple exchanges.
Supply arbitrary exchange rate
When a Coindrawer user was to purchase Bitcoin using USD (
Buy BTC feature), the workflow was advertised to have been:
- User sends USD by bank wire, cheque or bank deposit to Coindrawer's Bank of America account.
- Coindrawer increments user's USD account balance.
- At the Buy Bitcoin page, Coindrawer informs the user of the current BTC/USD exchange rate.
- User submits a Buy Order, specifying the amount of Bitcoin to be purchased at the advertised exchange rate.
- If the amount requested by the user is in Coindrawer's BTC-for-sale buffer, then the order is executed immediately. If Coindrawer's BTC-for-sale buffer is exhausted, the user is told their order will be put in a pending state until a future date, at which time the sale will proceed at the then-current exchange rate. The user has the chance to cancel such a pending order.
- When the order executes, the user's USD balance is decremented and BTC balance is incremented. The user can then send the BTC to a Bitcoin address outside of Coindrawer's system.
When a Coindrawer user was to sell Bitcoin for USD (
Sell BTC feature), the workflow was advertised to have been:
- User has BTC in their Coindrawer account.
- At the Sell Bitcoin page, Coindrawer informs the user of the current BTC/USD exchange rate.
- User submits a Sell Order, specifying the amount of Bitcoin to be sold at the advertised exchange rate.
- The order is placed in a pending state.
- Coindrawer sends a cheque to the user by post and the order is marked as completed.
When confirming a Buy or Sell Order, the user's browser sent, among others, the following parameters in a POST request to
session_token- a CSRF token
amount_btc- amount of BTC to buy or sell
exchange_rate_sell- the exchange rate to place the buy or sell order at
bankacct_key=0- seems to be a legacy option, from a time when users could link bank accounts to fund their purchases (and sales?)
amount_fiat- product of
amount_btc(seems to be ignored by the server)
exchange_rate_sell parameters were fed from hidden input fields. The fields were populated by the server when sending the
Buy BTC or
Sell BTC page to the user, and contained the current exchange rate. The value can be modified when POSTing the request to Coindrawer using a tool such as Burp Suite or Tamper Data and the server would trust the user-supplied exchange rate and process the purchase or sale at the user's desired rate.
This attack was never attempted, as doing so would require me to have deposited USD into Coindrawer's Bank of America account which was relatively impractical for me to do for a Proof of Concept. I asked Coindrawer to review my hypothesis and let me know if the attack was possible, but they never responded to my requests. I strongly suspect that the attack was possible, as the malicious orders would be listed in the
Order History list at the specified exchange rate, and the apparent UX suggests that a
Buy BTC order would be fulfilled instantly if the Coindrawer account had a positive USD balance at the time of the order. Coindrawer has not denied that my hypothesis is correct.
As follows is an attack on the
Sell BTC function (I did not take screenshots of an attack on the
Buy BTC function before Coindrawer removed the function)
Sell BTC form:
Confirm Sale with Burp Suite's
Intercept Requests feature enabled:
Intercept the POST to
Modify the POST to provide arbitrary (inflated) exchange rate:
View order in
Coindrawer's actions are in bold.
- 6 Jan 2014 - Submission of JSEC1053 (Provide arbitrary buy/sell exchange rate)
- 8 Jan 2014 - Submission of additional information for JSEC1053
- 15 Jan 2014 - Request for acknowledgement of JSEC1053
- 20 Jan 2014 - Coindrawer acknowledges receipt of JSEC1053
- 14 Feb 2014 - Coindrawer promises an update on issues including this one “by the end of the week”. This is the last I hear from Coindrawer for 2 months.
- Early 2014 - Coindrawer suspends buy/sell functionality citing “banking and regulatory challenges”.
- 20 Feb 2014 - Request for an update. No response
- 27 Feb 2014 - Request for an update. No response.
- 4 Mar 2014 - Request for an update. No response.
- 20 Mar 2014 - Request for an update. No response.
- 21 Mar 2014 - Request for an update. No response.
- 27 Mar 2014 - Request for an update. No response.
- 3 April 2014 - Notification to Coindrawer of disclosure date (1 May 2014).
- 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 date 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:
- Coindrawer Bug Bounty experience
- JSEC1046 - Coindrawer Persistent DOM XSS Disclosure (Paycoin Feature)
- JSEC1051 - Coindrawer Payment Replay Disclosure, Create Multiple Merchant Orders
- JSEC1053 - Coindrawer Provide Arbitrary Exchange Rate Disclosure
- JSEC1065 - Coindrawer Non-persistent XSS Disclosure (Buy/sell Orders Feature, Cancel_order Param)
- Coindrawer Bug Bounty finale