Summary
The challenge is to withdraw funds from the contract by passing the two impossiblerequire statements by jumping with the help of the function which changes the memory. This is my first ctf to achieve first blood which has been solved by 7 other teams.
Introduction to challenge
This script checks the last deployed jump contract's balance should be equal to 0 to solve the challenge.
While looking at the contract, withdraw() and breakIt() functions grabs the attention. The withdraw function checks the value sent to be 0 to transfer the balance whereas the breakIt checks the value sent to be not equal to 0. Notice that the withdraw is a private function so we cannot call it from outside. Let's dig deeper...
The struct
Func maps a internal function to it. frwd is a internal function which calls withdraw. Now back to breakIt, the struct is initialized here and frwd is passed in the place of internal func in func.f Everything's fine breakIt calls the internal function frwd which in turn calls the withdraw function.
But, how do we jump the
require statements ?
Time for low level, the mstore takes a offset as its first argument and value as its second and stores it in the next 32 bytes in memory.
Here the offset is struct function location in memory 0x80 and value is callvalue (msg.value) sent.
Let us remove the require statement in the
breakIt function to see how it works without finding the solution yet...
the memory slot 0x80 contains the value 0xb3 which is location of frwd that was initialized.
Before going further, let's understand this
Function call is nothing but a unconditional jump, it jumps to the function location and runs that part. On the other hand require statement is conditional jump which jumps to the instruction location when the condition is satisfied.
Here struct
Func.f points to the function location frwd which differs. So, by changing the destination of Func.f to the transfer instruction in withdraw function we would able to drain all the funds.
By debugging the breakIt function's transaction we know that the jumpi points to the destination - 100 and with the condition - 1 in stack. The only possible way to change the destination is by using callvalue. The assembly adds 0xb3 which is location of frwd and the call value should be 0x100 - 0xb3 = 77. So, the call value should be 77 wei to drain all the funds. Now let's remove the require statements to try it.
Success, we drained all the funds.