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.