Audios protocol hack analysis
0x01 Preview
Audius is a fully decentralized music platform. Own the masters & the platform. Audius was hacked Saturday losing about $6 million worth of Ethereum-based AUDIO tokens. The 18.6 million AUDIO tokens were re-sold for 705 ETH ($1.1 million) and funneled through a transaction mixing service.
0x02 Attack information
· Attacker’s address
0xa0c7BD318D69424603CBf91e9969870F21B8ab4c
· Attack Transactions
0xfefd829e246002a8fd061eede7501bccb6e244a9aacea0ebceaecef5d877a984
0x3c09c6306b67737227edc24c663462d870e7c2bf39e9ab66877a980c900dd5d5
0x4227bca8ed4b8915c7eec0e14ad3748a88c4371d4176e716e8007249b9980dc9
· Attack Contracts
0xa62c3ced6906b188a4d4a3c981b79f2aabf2107f
0xbdbb5945f252bc3466a319cdcc3ee8056bf2e569
· Attacked Contracts Governance
0x35dd16dfa4ea1522c29ddd087e8f076cad0ae5e8
0x03 Attack steps
- Attackers deploy attack contracts
- the attacker evaluates whether the current 84 proposal has passed by the evaluateProposalOutcome method (the 84 proposal is initiated by the attacker, but lacks the conditions for the proposal to pass)
- Initiate a new proposal 85 for the transfer of a large amount of funds to 0xbdbb5945f252bc3466a319cdcc3ee8056bf2e569 via the transfer method.
4. call the Staking.initialize initialization method to set the attacker contract address to the administrator address (note: why the attacker can call the initialization method)
5.Call the DelegateManagerV2.initialize initialization method to update the administrator address
6.Call DelegateManager.setServiceProviderFactoryAddress update serviceProviderFactoryAddress
7.Call delegateStake method to delegate a large number of votes to the attacker’s contract address
8. The attacker calls the submitVote method to vote
9. The attacker calls the evaluateProposalOutcome method to evaluate the 85 proposal passed and successfully completed the transfer.
0x04 Core of the attack
Initializable contract
Three conditions in the initializer() modifier judgement.
initializing: initially false, also false when the method is finished.
isConstructor():When initially deploying a contract, the code is still undeployed when the constructor is run, and any check on its code size yields zeros.
initialized: Initialized to true to satisfy the condition, modified to false at the end of method execution, no secondary calls can be made.
Normal calls to initialize contracts, methods modified by initializer can only be called once, here the attacker has made calls in multiple contracts, why is it like that?
Proxy contracts exist on the Audius platform, The Governance contract is called by the proxy contract and the modifiers in the initialisation contract are called by the Governance contract when deployed.
The initialization results in the determination of the governanceAddress address, which exists in the first card slot, and the modifier condition for this initialization, where the boolean value of the variable is also stored in the first card slot, resulting in a storage conflict, after which the initializing variable remains true. initializer() modifier can be called multiple times.
0x05 Source and flow of funds
Attackers took by Tornado.Cash platform on Binance chain
Flow of funds
The attackers have now transferred their profits to the Tornado.Cash platform.
0x06 Summary
Although multiple storage conflicts are declared in the official openzeppelin proxy model, unexpected storage conflicts can occur when multiple logics are combined together. Audius has now officially added a judgement condition to the initialisation modifier to prevent secondary exploitation, and added storage parameters to the initialisation contract.
New to trading? Try crypto trading bots or copy trading