A set of challenges to learn offensive security of smart contracts in Ethereum.
Featuring flash loans, price oracles, governance, NFTs, lending pools, smart contract wallets, timelocks, and more!
Visit damnvulnerabledefi.xyz
All Solidity code, practices and patterns in this repository are DAMN VULNERABLE and for educational purposes only.
DO NOT USE IN PRODUCTION.
Solutions to Damn Vulnerable DeFi challenges ⛳️ < version v3.0.0 >
- Unstoppable
- Naive receiver
- Truster
- Side entrance
- The rewarder
- Selfie
- Compromised
- Puppet
- Puppet v2
- Free rider
- Backdoor
- Climber
The goal of the first challenge is to perform a DOS (Denial of Service) Exploit to the contract.
There is a suspicious line in the flashLoan
function:
uint256 balanceBefore = totalAssets();
// totalAssets() returns the balance of the pool
asset.balanceOf(address(this));
If we can manage to alter the totalAssets()
return, we will achieve the goal.
We can easily modify the asset.balanceOf(address(this))
by sending some token to the pool.
In this challenge we have to drain all the funds from a contract made to call flash loans.
The contract expects to be called from the pool, which is fine, but the vulnerability lies on the fact that anyone can call the flash loan function of the pool.
In order to empty the contract in one transaction, we can create an Exploiter contract that calls the flash loan multiple times in its constructor, the repetitive 1 ETH fees draining the receiver in the process.
Here we have to get all the tokens from the pool, and our starter balance is 0.
The flashLoan
from the pool lets us call any function in any contract. So, what we can do is:
- Call the
flashLoan
with a function toapprove
the pool's tokens to be used by the Exploiter - Call the
transferFrom
function of the token, to transfer them to the Exploiter address
If we want to make it in one transaction, we can create a contract that calls the flashLoan
with the approve
, but instead of the Exploiter address, we set the created contract address. Then we transfer the tokens to the Exploiter in the same tx.
For this challenge we have to take all the ETH from the pool contract.
It has no function to receive ETH, other than the deposit
, which is also the Exploit vector.
We can create an Exploiter contract that asks for a flash loan, and then deposit the borrowed ETH. The pool will believe that our balance is 1000 ETH, and that the flash loan was properly paid. Then we can withdraw it.
Here we have to claim rewards from a pool we shouldn't be able to.
Rewards are distributed when someone calls distributeRewards()
, and depending on the amount of tokens deposited.
So, we can do all of this in one transaction:
- Wait five days (minimum period between rewards)
- Get a flash loan with a huge amount of tokens
- Deposit the tokens in the pool
- Distribute the rewards
- Withdraw the tokens from the pool
- Pay back the flash loan