The CTF covers some of the common smart contract vulnerabilities one must be aware of as a developer or an auditor. Before we jump into the challenges, Let’s just understand what concepts we must be aware of, that can be helpful in solving these challenges.
approve grants the
spender to spend
amount number of tokens on behalf of the owner or caller. A typical example would be granting a Decentralized Exchange (DEX) the approval to swap tokens. The malicious spender may empty your wallet if you give blind approvals to any smart contracts you interact with.
A flash loan is a type of uncollateralized loan that enables a user to borrow assets without providing any security, as long as the assets are returned inside the same block in which they were borrowed. A typical use case of Flash Loans would be an arbitrage opportunity. You see that the token $XYZ is trading at a discount on an exchange. So, you leverage this opportunity by buying $XYZ on a cheaper exchange and selling on another exchange for a profit. Malicious users take advantage of this feature to manipulate the token prices or governance votes.
In the smart contract eco-system, we generally have to interact with other contracts by making external calls. A
delegatecall from ContractX to ContractY means that — we are running the code of ContractY with storage of ContractX.
Automated Market Maker(AMM)
It is a protocol via which many decentralized exchanges (DEX) operate. In a typical trading system, we follow the order book approach where a centralized entity is responsible for providing most of the liquidity for trading. But in the context of Defi, the users actually provide liquidity to the pool for which they earn interest on every trade. The AMM pools can serve as an Oracle by providing the price of tokens by calculating the ratio of the tokens in a pool. Example: ETH/USDT, BTC/ETH, etc.,
A reentrancy attack occurs in scenarios wherein a contract makes an external call to another contract. The issue arises when the external call ends up making a recursive call back to the original function, the attacker can end up draining funds. The DAO attack resulted in the Ethereum hard fork into Ethereum and Ethereum Classic, due to reentrancy.
Lending and Borrowing
Suppose you own 10 ETH, and you do not want to sell it as you believe that it is going to give good returns in the future but you need some cash. So you deposit ETH in protocols like Aave, which is a popular Defi Borrow and Lending platform, they can offer up to 80% of the collateral stable coins which you can use instead of selling the asset.
Popular DEX like Uniswap is a pretty good example of a price oracle. The way it works is it calculates the price of the asset based on the liquidity in the Pool. Defi protocols using a single source of Price Oracle is a very bad practice. If an attacker is somehow able to influence the price of the pool from which the current price is derived, it may result in the token price of one asset plummeting. A good recommendation is to use Chainlink, since it fetches prices from several sources.
I think these concepts should be good enough to go ahead with the challenge. In any case, please follow this link, which can help you further understand these concepts.
The developer has implemented a custom ERC20
approval function with a missing Access Control. There is no check for the caller of the function. As a result, anyone can call the
approve function, grant approval to themselves, and spend the owner’s tokens.
Flashloan contracts generally respond with a
callback function to offer the tokens to the borrower. At the end of the function the borrower needs to return the borrowed tokens or else the whole transaction fails. In our challenge, the developer has implemented the callback via
delegatecall. As a result, the attacker can pass the function signature and it will be executed in the context of the
LenderPool. In the challenge, we exploit it and give ourselves the approval to spend the tokens and later on transfer them to ourselves.
There is a known reentrancy bug in the ERC223 implementation, wherein a callback
tokenFallback is triggered for every token transfer. The way to solve this challenge is that we first add some liquidity to the DEX, the callback is triggered which we ignore, and then move on to remove the liquidity, once the callback is triggered, we continue calling the remove liquidity, until we drain the pool.
The challenge is a classic example of a deadly combination of Flash Loan + Price Manipulation Attacks. We first borrow the $ISEC tokens via Flashloan and swap 90% of the borrowed tokens for $BOR. Due to the large volume of the $ISEC tokens, the value of $BOR soars. Now, The swapped $BOR tokens are then deposited and $ISEC is borrowed. Due to the inflated price and the amount of $BOR tokens we hold. We end up borrowing all of the $ISEC tokens from the
borrowSystem, As a result, draining it from the $ISEC tokens.
Thanks for Reading!