A brief analysis of the Web3 music platform Audius exploit

GoPlus Security
3 min readJul 24, 2022

--

Audius community treasury was exploited, and 18.5 million $AUDIO Tokens were stolen, which was equivalent to $6M.

Here is a brief analysis from Go+ researcher Ben.

The related addresses are

Governance Contract https://etherscan.io/address/0x4deca517d6817b6510798b7328f2314d3003abac… (Proxy) https://etherscan.io/address/0x35dd16dfa4ea1522c29ddd087e8f076cad0ae5e8… (Impl)

Staking Contract https://etherscan.io/address/0xe6d97b2099f142513be7a2a068be040656ae4591… (Proxy) https://etherscan.io/address/0xea10fd3536fce6a5d40d55c790b96df33b26702f… (Impl)

Full attack vector: Tamper with vote parameters -> submit malicious proposal -> Tamper with vote weight -> Vote -> Execute proposal

Call initilize() of Governance to tamper with vote params: Set votePeriod = 3 and Delay = 0, so that only 3 blocks were needed to finish voting. Set _votingQuorumPercent = 1%, meaning that only 1% of the total staked token will meet the quorum. https://tools.blocksec.com/tx/eth/0xfefd829e246002a8fd061eede7501bccb6e244a9aacea0ebceaecef5d877a984

Submit malicious proposal(id=85) to Governance: Call submitProposal() with _functionSignature = transfer(address,uint256), address = attacker, amount = 18,564,497,819,999,999,999,735,541,_targetContractRegistryKey= 307800..00(resolve as token contract in registry).

Tamper with voting power of its own _quorumMet() will check whether the vote has met the quorum. If not then no result will come out. The attacker needed to increase its own weight to pass this check.

In DelegateManagerV2 call initialization, set himself as governanceAddress, who has the power to delegatestake. Call delegatestake(), as we can see there’s no limitation on _amount, so the hacker wrote a very large number. Only vote yes to meet the quorum.

Call evaluateProposalOutcome() in Governance to settle proposal 85. Block height was 15201799. Settlement time window reached, quorum met, and only him voted for yes, so the proposal passed. Function inside the proposal will be called, i.e. transfer token to the attacker.

As for why the hacker can initialise an initialised contract, my speculation is that the variable proxyAdmin in the proxy contract collided with one of the two variables of initialized or initializing, which caused the modifier initializer () to pass.

proxyAdmin variable collides with the initialized and initializing variables, causing the modifier initializer() to pass. After deploying the modified contract on the test network, it is found that the proxy without proxyAdmin can work normally and cannot be initialized twice.

--

--

GoPlus Security

Empowering a #SaferWeb3 with user-driven, open access security solutions. Championing user education for a fortified front against adversaries.