Greetings!
Only one interesting compromise this week. Every compromise is an opportunity to learn and get better at securing our projects. So let’s do a bit of an in-depth analysis and note some important lessons.
A South Korean project, PlayDapp, was exploited twice due to private key theft. The attacker minted $36.5m worth of PLA tokens on February 9th and another $253.9m on February 12th. The incident has a number of lessons in incident response, resilient smart contract design and secure configuration. Let’s look at the timeline first to see just how quickly the attacker executed the compromise and laundering:
2024-02-09 13:39:23 - Malicious minter account 0xD15105 added.
2024-02-09 13:42:35 - Malicious pauser account 0xD15105 added.
2024-02-09 13:45:11 - 0xD15105 mints - 100k PLA
2024-02-09 14:12:15 - Funds start flowing to Polygon and exchanges.
2024-02-09 14:25:23 - Compromised deployer renounces minting privileges.
2024-02-09 14:27:23 - Compromised deployer renounces pausing privileges.
2024-02-09 14:31:23 - 0xD15105 mints - 100k PLA
2024-02-09 16:43:00 - Peckshield Tweet (3 hours after the attack).
2024-02-09 17:33:47 - Compromised deployer removes ETH/PLA pool liquidity.
2024-02-10 13:52:23 - “Whitehat” offer from PlayDapp team.
2024-02-10 - 2024-02-11 - Exchanges continue receiving PLA tokens.
2024-02-12 7:27:35 - 0xD15105 mints - 1 PLA
2024-02-12 13:01:47 -0xD15105 mints - 1,590,000,000 PLA
2024-02-12 13:06:35 - Funds start flowing to exchanges again.
2024-02-13 2:05:23 - 0xD15105 pauses the token
2024-02-13 12:39:11 - 0xD15105 unpauses the token
2024-02-13 12:44:23 - 0xD15105 pauses the token again.
Some observations from the above:
Attackers were well prepared and knew exactly how (bridging to Polygon) and where to move stolen funds (exchanges).
It took only 6 minutes between the first transaction with a compromised account and the first mint. Only a fully automated system could have responded quickly enough which did not appear to be present.
The PLA contract did not expose removeMinter and removePauser methods in the OpenZeppelin library. There was no way to remove malicious superuser accounts since only accounts themselves could renounce their privileges.
Both pauser and minter accounts were set at contract deploy time to the same address about 4 years ago and never changed. There is a reason why these two roles were separated. A compromise of a single key resulted in complete contract takeover.
Minted PLA tokens were repeatedly deposited to a few exchanges for days after the hack which likely allowed attackers to successfully launder stolen assets. Better coordination with exchanges is critical to stopping bad actors.
Takeaways for developers:
Study adversary tactics and threat actor profiles. This bad actor is the worst you could deal with and unlikely to negotiate a “whitehat” bounty.
Develop a list of invariants for your protocol which when broken should result in automated defensive actions such as smart contract pausing.
Think like an attacker to build survivability features not only into your smart contract, but also configurations, processes, infrastructure, etc. Going through a threat model exercise will help expose your weak points.
Prevention will only get you so far. Build and practice incident response playbooks to deal with the worst case scenarios.
To gain access to comprehensive vulnerability write-ups, post-mortems, exploit proof of concepts (PoCs), attacker addresses, and additional data regarding this week’s compromises, please subscribe to the premium plan below.
Quiet weeks like this one are rare, so enjoy plenty of high quality research from across the blockchain security ecosystem. Let’s dive into the news!