Repository for the Warroom ETHCC 2023. The goal of this project is to create four tasks to be solved by the participants of the Warroom.
Each team starts with 0 WAR tokens, at the end WAR tokens will count for points, the goal of most problems is to score as much points as possible. The team with the most points wins. (the proxy capture task is an exception, the winner is the last owner of the proxy, and is worth X points)
- Each task, except the first one, will have WAR tokens that can be withdraw after solving the task.
- For proxy, we will send the WAR tokens the last owner.
- After the team decides they are finished and they completed the task, they will get additional WAR tokens depending on order of completion, the first one gets more points. First place gets 13 points bonus, second place 8 points, third place 5 points, and the rest 3 points.
- Points per task:
- Proxy capture - 15 points
- Flash loan - 25 points
- Signature malleability - 30 points
- Access control - 35 points
- Bonus task - 10 points
The goal of the task to have all participant tackling the same deployed contract. This a unique task that will be the same for every team, the winner will be the last owner of the proxy, either by having an implementation that cant be taken over or implementation having a self destruct. Goal is for users to compete who will recognize on chain that the proxy can be reinitialized. Additional, everybody should be able to take over the contract after initialization by call the same function initialize, so its a race between all the teams to take over the contract and avoid others to take it over. The end game for the user is to deploy new implementation of the proxy which will not allow new initialization and will be the final owner. To authorize upgrade, user must withdraw some funds and also whitelisted the owner. Check out test Proxy.t.sol for more details.
The participant should understand the flash loan logic. Recognize that the contract is connected to Aave v3. Find on Aave v3 that he can mint for himself some tokens and send to the contract so it can execute successfully by paying the flash loan premium. The function addUsingFlashLoan()
in Loan contract is added to misguide the user. It will increase totalLoan but not for the user as needed for task but instead to called Loan contract.
The user should use flash loan function by himself and set Loan contract as the receiver address to solve the task. Now the user has enough totalLoan to withdraw reward token from the contract by calling function removeLoan
. In flash loan function, there is require that the contract must contain the double amount of the flash loan. This can be achieved by creating a contract that will take flash loan, send the amount to Loan contract and then call again pool flash loan function and set Loan contract as receiver this time. It's important that new contract calls removeLoan
function for loaned token so it can pay off its flash loan.
To see solution, check out test FlashLoan.t.sol. To successfully execute the attack, the user must create additional contract that will also call flash loan. This is done in AttackLoan.sol.
There is a contract WhitelistedRewards
that allows whitelisted users to withdraw rewards funds. The contract has one transaction that claimed rewards by providing the correct signature from a whitelisted address. The goal of this task is to recognize that you can provide different signature from the same address. The valid signature can be extracted by using a signature that already signed the transaction. Now the attacker can generate a new signature for the whitelisted address that signed the transaction. With a valid signature, the attacker can claim rewards from the contract. Check out test WhitelistedRewards.t.sol for more details.
For more info on this read section "Signature malleability" in RareSkills blog. Get more info about math on signature malleability.
This task has two contracts, RewardsBox
and AccessControl
. AccessControl
is a trick Access Controller that provides no way to add an owner. The preset owners are vitalik.eth and a randomly generated address. Even the deployer has no function to add a new owner. RewardsBox
is very simple and has a function claim(address accessController, uint256 amount)
that checks the provided accessController
to see that msg.sender
is permissioned and if so, deals amount
reward tokens.
RewardsBox
enforces that you provide a correct AccessControl
contract as the controller by checking the codehash of your provided controller against a codehash that is baked in on the RewardsBox
init.
The trick here is that when a contract is deployed in the EVM, arbitrary code can be executed in the constructor that is not reflected later in the deployed contract code. So an attacker can deploy a new contract, in the constructor add themselves to the owners
mapping, and then set the deployed code to a proper AccessControl
. See the provided test for details.
The goal of this task is to see if the users can recognize that Multiply
contract is deployed using Factory
. The user will see the verified Multiply.sol
contract on Etherscan that has some funds. The idea is to trick the user to approve Multiply
contract to spend their tokens for a small multiplication of tokens he gets in return. After the user has approved the tokens, we can destroy the current contract and deploy a new one with a different logic, Multiply2.sol
, but it will still have an allowance from the user. With the new logic, we can steal all allowed tokens from the user. Check out test MultiplierRug.t.sol for more details.
One thing to mention is that this should be the last task, so we can put on a bit of show, and steal funds after the time is up. Also, the final score should be counted in ERC20
token, not in ETH because we need allowance on the token. We could create ERC20 Warroom token and see top holders for the final score.
More info about metamorphic contracts: https://proxies.yacademy.dev/pages/proxies-list/#metamorphic-contracts
Create .env
file, see .env.example
for reference. Then run:
source .env
First step is to deploy War token. To deploy War token run script:
forge script script/WarToken.s.sol:WarTokenScript --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv
Now, change the WAR_TOKEN
in Constants.sol
to the address of the deployed War token.
To deploy proxy capture task run script:
forge script script/Proxy.s.sol:ProxyScript --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv
To deploy flash loan task run script:
forge script script/Loan.s.sol:LoanScript --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv
To deploy Signature malleability task run script:
forge script script/Signature.s.sol:SignatureScript --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv
To deploy Access Control task run script:
forge script script/AccessControl.s.sol:AccessControlScript --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv
To deploy Metamorphic factory and initial Multiply contract run script:
forge script script/Metamorphic.s.sol:MetamorphicScript --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv
To destroy Multiply contract run script:
forge script script/Metamorphic.s.sol:MetamorphicDestroy --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv
To deploy new Multiply contract run script:
forge script script/Metamorphic.s.sol:MetamorphicDeployNew --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv