Our first Capture The Flag event recently came to an end. It was a great success!
Beginning May 1st and continuing until May 10th, in total we received 11 submissions that qualified for the challenge. These submissions were of such a high quality they got us thinking about how we can potentially partner with some of these security pros in the future.
That said, we are delighted to announce that the first submitter, Kevin Charm, took the first prize of 10,000 DAI home. Other participants that submitted in time and correctly received an NFT and $500 USDC reward. While this latter reward was not initially planned, we were so impressed by the quality of the submissions we made the decision to honor the submitters’ great work.
This challenge was fun, engaging, and brought us insights from participants that will ensure our future challenges will be even more effective.
In this post we will go over the vault vulnerability, the winner’s submission, what we did well in this challenge, and things we will incorporate in our future challenges.
Finding the vulnerability
The first Hats CTF challenge was a simple card fighting game. The goal was to capture the flag by pitching your deck of Mons against the deck of the flag holder. The catch? The game was set up to be unwinnable: the deck of the flag holder consisted entirely of Mons that were unbeatable according to the rules of the game.
The main exploitable vulnerability was hidden in the “swap” function, where two Mons are exchanged by two subsequent “safeTransfer’’ calls. The safeTransfer calls are inherited from OpenZeppelin’s ERC721 implementation, which (as the standard requires) tries to call a callback function on the receiver of the token. An attacker could exploit this callback function by creating a receiver contract that re-enters the game contract when only one leg of the swap is completed, and the attacker has received the counterparty’s mon from the swap, but not yet transferred her own.
To capture the flag, several iterations of reentrancy had to be implemented. Almost all submissions were of very high quality, many of them providing implementations of a working demo, and a write-up of the approach.
As the challenge occurred, we observed the following…
We got many amazing entries, but only one was the first
Most of the entries we received were correct and overall great, which from a content perspective makes it really hard to choose a winner. Given the parity of quality submissions, we thought it made sense to make the first correct entry the winner. For future challenges, we might consider adding extra rules and guidelines that allow non-first entries to be the winner if they excel relative to our stated criteria.
Clarity over length
The entries that stand apart from the rest are not the ones that are the longest. Instead those that are clear, seamless, easy to understand and accompanied with a good POC were the real standouts.
Finding more than one vulnerability
During the challenge, we had one entry that in addition to writing a correct response, also brought up other problems with the contract and the game. One of them was a bug that we did not think of at first. This speaks of the creativity and talent that exists within the security research community. We welcome entries that think outside the box, and provide different perspectives.
We want to thank all submitters to our first CTF for joining us in our first game. We would also like to thank blockchain security researchers in general. You are the true heroes of web3, for helping to keep the space secure and creating a more trustworthy ecosystem.
This will not be the last challenge, as we intend to create more CTFs