Back in 2018 I hosted the contest EtherHack which featured a set of vulnerable smart contracts. At that time the tasks were focused primarily on the EVM peculiarities like insecure randomness or extcodesize opcode tricks. Back then the first wave of crypto hype was coming to the end when numerous ICOs were falling apart because they did not deliver on expectations. Nowadays the crypto space is much more mature as it has got a truly useful and promising application of the blockchain technology: DeFi.
DeFi stands for decentralized finance and aims at replacing traditional financial institutions like banks, hedge funds, insurance companies and many others. By eliminating the third party, DeFi allows to manage funds in a truly decentralized way minimizing corruption and promoting real ownership. With that said, DeFi is transparent not only to the legitimate users but also to the malicious actors. That is why smart contract failures are as critical as never before. The composability of different DeFi protocols increases the complexity of smart contract interactions. It is a really hard task to make a smart contract secure which is proved by numerous hacks of DeFi protocols that have happened over the past months. In order to raise awareness and demonstrate typical vulnerabilities of DeFi protocols me and Omar Ganiev (twitter, telegram) created the DeFi Hack wargame. Unlike Damn Vulnerable DeFi, a similar CTF made by OpenZeppelin, the tasks of DeFi Hack are based on real vulnerabilities of DeFi protocols. This is the walkthrough of the first level.
May The Force Be With You
A long time ago in a galaxy far, far away… a new DAO was created. Can you steal all the YODA tokens belonging to MayTheForceBeWithYou contract?
This level replicates the ForceDAO hack that happened in April, 2021 and resulted in the loss of 183 ETH (~$367K). The original vulnerable xFORCE smart contract was a fork of the xSUSHI vault. It allowed to deposit some FORCE tokens and get some xFORCE minted in return. When the contract transferred FORCE tokens from the user, it assumed that transferFrom()
would revert if the user did not have enough tokens. However, the contract used Aragon’s MiniMe ERC20 implementation that returned a boolean value instead of reverting:
function doTransfer(address _from, address _to, uint _amount) internal returns(bool) {
if (_amount == 0) {
return true;
}
// Do not allow transfer to 0x0 or the token contract itself
require((_to != address(0)) && (_to != address(this)));
// If the amount being transfered is more than the balance of the
// account the transfer returns false
if (balances[_from] < _amount) {
return false;
}
// First update the balance array with the new value for the address
// sending the tokens
balances[_from] = balances[_from] - _amount;
// Then update the balance array with the new value for the address
// receiving the tokens
require(balances[_to] + _amount >= balances[_to]); // Check for overflow
balances[_to] = balances[_to] + _amount;
// An event to make the transfer easy to find on the blockchain
Transfer(_from, _to, _amount);
return true;
}
As you can see instead of calling revert()
the contract just returns false
if the balance is insufficient. It means that it was possible to basically mint tokens for free. The same logic was implemented in the task. In order to solve it one had to send two transactions: firstly call deposit()
with the amount of xYODA tokens to mint, and then call withdraw()
to drain the YODA tokens.
The source code of DeFi Hack is now open, you can see the solution of this level as a Hardhat test.
Other posts:
Leave a Reply