code4rena-2022-04-axelar-m01

[M-01] Low level call returns true if the address doesn’t exist

보고서

Summary

로우레벨 call은 해당 주소에 컨트랙트가 배포되지 않았다면 revert 되지 않고, true를 리턴한다. 따라서 로우레벨 call을 하기 전 해당 주소에 컨트랙트가 배포되었는지 확인해야 한다.

Keyword

low level call

Vulnerability

solidity docs를 참고하면 로우레벨 call, delegatecall, staticcall은 해당 주소에 컨트랙트가 배포되지 않았다면 true를 리턴한다 명시한다.

AxelarGateway의 _callERC20Token 함수에서 컨트랙트 배포 여부를 확인하지 않는다.

function _callERC20Token(address tokenAddress, bytes memory callData) internal returns (bool) {
    (bool success, bytes memory returnData) = tokenAddress.call(callData);
    return success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
}

또한 AxelarGatewayProxy의 constructor 에서도 확인하지 않는다.

constructor(address gatewayImplementation, bytes memory params) {
    _setAddress(KEY_IMPLEMENTATION, gatewayImplementation);
 
   (bool success, ) = gatewayImplementation.delegatecall(
       abi.encodeWithSelector(IAxelarGateway.setup.selector, params)
   );
 
    if (!success) revert SetupFailed();
}

Impact

로우레벨 call이 실패했음에도 revert 되지 않는다.

Mitigation

로우레벨 call을 하기 전에 해당 주소에 컨트랙트가 배포되었는지 확인한다.

Memo

나같으면 상황적으로 tokenAddress가 신뢰 가능한 주소라고 생각하고 넘기거나 Low로 제출했을텐데, Medium으로 판정났다니 한번 제출하고 볼 일인가 보다. 또는 초창기 컨테스트라 그럴지도..?

주최자 측도 주소 검증을 하기때문에 일어날 확률이 적지만 Medium으로 인정했다.


tags: bughunting, axelar, smart contract, solidity, solidity low-level call, severity medium