4

I am currently learning about how the current batch overflow happens. But there are some points I don't understand. The article says following:

The vulnerable function is located in batchTransfer and the code is shown in Figure 2. As indicated in line 257, the amount local variable is calculated as the product of cnt and _value. The second parameter, i.e., _value, can be an arbitrary 256 bits integer, say 0x8000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000(63 0’s). By having two _receivers passed into batchTransfer(), with that extremely large _value, we can overflow amount and make it zero. With amount zeroed, an attacker can then pass the sanity checks in lines 258–259 and make the subtraction in line 261 irrelevant. Finally, here comes the interesting part: as shown in lines 262–265, the balance of the two receivers would be added by the extremely large _value without costing a dime in the the attacker’s pocket!

The image to the article: enter image description here

So now, when the hacker enters the number, the number get's extremely huge. In the next step, the number even gets higher with multiplication with cnt which is the amount of receivers (let's say 2).

Why did the execution not stop in the line 259 as the amount the hacker transferred was way higher than his balance?

Can someone please explain to me what exactly happened here?

  • 2
    If you agree that uint256 amount could overflow and become equal to 0, then you could also see how require(_value > 0 && balances[msg.sender] >= amount); would always return true, thus the rest of the code would run unchecked. – Shawn Tabrizi Apr 26 '18 at 20:13
  • Thank you for your comment, that's true. My fault was, that I did not read it correctly. I understand it now :) – dkb Apr 26 '18 at 21:48
5

Why did the execution not stop in the line 259 as the amount the hacker transferred was way higher than his balance?

If the contract is called with the arguments

batchTransfer([addressA,addressB],0x8000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000)

line 257 becomes

uint256 amount = 2 * 0x8000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000

which is 0x0 due to overflow.

So amount in the subsequent evaluation is 0. So the check in line 259 becomes:

require(0x8000,0... > 0 && balance[msg.sender] >= 0);

The argument to require evaluates to true so the contract execution will continue. And in the for-loop the huge amounts of 0x800.... will be transferred to addressA and addressB and 0 (the amount which was the result of an overflowed calculation) will be subtracted from the originator's balance.

The total amount of tokens has just increased by 2^256 tokens.

Talk about hyperinflation!

  • LOL. I just got it. I actually did not correctly read the whole thing. There is "amount" and "_value", while amount is the whole thing, the total value, that gets to zero because of overflow and _value is what each user gets which remains as the huge value. Thank you for this! – dkb Apr 26 '18 at 21:47
  • Brain farts is an unavoidable part of programming. That should also be clear from the code that this question is about :) – Thorkil Værge Apr 26 '18 at 21:50
  • Yes it is, the code shows clearly what happened. I did not fully read the whole code ;-). – dkb Apr 27 '18 at 12:56
  • 2
    Neither did the developers of that contract :) – Thorkil Værge Apr 27 '18 at 12:58
  • It's bad that I laughed at this. – dkb Apr 29 '18 at 19:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.