code4rena-2024-08-axelar-h01

[H-01] Bridge requests to remote chains where interchain tokens are not deployed can result in DoS attacks

보고서

Summary

목적지 체인에 interchain token이 배포되어 있지 않더라도 ITSHub는 토큰 이동 요청을 정상으로 처리 한다. 이때 ITSHub에서의 잔고는 업데이트 되지 않는다. 브릿지 요청은 목적지 체인으로 이동하여, 아직 등록되지 않은 토큰에 대한 브릿지 요청이 허용상태로 대기한다. 이후 목적지 체인에 interchain token을 배포하면 ITSHub 체인의 잔고는 0으로 초기화된다. 허용상태로 대기중인 브릿지 요청을 실행하면 목적지 체인으로의 브릿지 요청이 마무리되고, ITSHub 잔고보다 많은 토큰이 목적지 체인에 존재하게 된다.

Keyword

bridge, lack of input validation, dos

Vulnerability

ITSHub는 토큰을 이동할 때 체인 별 잔고를 추적한다. 목적지 체인에 interchain token 이 배포되어 있지 않다면 잔고가 초기화되어 있지 않아 None 이고, 이 때 revert 하지 않고 넘어간다. 즉 목적지 체인에 interchain token이 배포되어 있지 않더라도 토큰 이동 요청을 정상 처리 한다.

pub fn update_token_balance(
    storage: &mut dyn Storage,
    token_id: TokenId,
    chain: ChainName,
    amount: Uint256,
    is_deposit: bool,
) -> Result<(), Error> {
    let key = TokenChainPair { token_id, chain };
 
    let token_balance = TOKEN_BALANCES.may_load(storage, key.clone())?;
 
    match token_balance {
        Some(TokenBalance::Tracked(balance)) => {
            let token_balance = if is_deposit {
                balance
                    .checked_add(amount)
                    .map_err(|_| Error::MissingConfig)?
            } else {
                balance
                    .checked_sub(amount)
                    .map_err(|_| Error::MissingConfig)?
            }
            .then(TokenBalance::Tracked);
 
            TOKEN_BALANCES.save(storage, key.clone(), &token_balance)?;
        }
@>      Some(_) | None => (),
    }
 
    Ok(())
}

목적지 체인에 interchain 토큰이 배포되어 있지 않다면 메시지가 approve 되어도 토큰이 배포되어 있지 않으므로 토큰을 브릿지받을 수 없다. 하지만 remote interchain 토큰 배포 요청을 frontrun 하는 시나리오나 나중에 remote interchain 에 토큰을 배포하면 꺼내간다는 시나리오를 생각해볼 수 있다. Canonical 토큰의 경우 누구나 remote interchain 토큰 배포가 가능하므로 토큰 이동을 먼저 요청한 뒤 remote interchain 토큰 배포를 요청하는 시나리오를 쉽게 만들 수 있다.

다음 예를 생각해보자.

  1. 토큰 배포자가 B 체인으로 remote interchain 토큰 배포 요청을 한다. 이는 frontrun 될 것이다.
  2. 이 트랜잭션을 프론트러닝하여 토큰 이동을 100 ether 만큼 요청한다.
  3. ITSHub가 ItsMessage::InterchainTransfer 를 먼저 실행한다. 아직 B 체인에 interchain 토큰이 배포되지 않았으므로 B 체인의 잔고는 None으로 유지된다.
  4. ITSHub가 이후 ItsMessage::DeployInterchainToken 를 처리하여 B 체인의 잔고를 0으로 초기화한다.
  5. B 체인에서 remote interchian 토큰 배포 처리가 완료된 후 공격자가 execute 를 실행하여 브릿지된 토큰을 받는다.

ITSHub에서의 잔고는 0이지만 B 체인에는 브릿지된 토큰이 100 ether 만큼 있다. 잔고 불일치는 DoS 와 같은 문제를 일으킬 수 있다. 예를 들어 다른 유저가 A B 체인으로 토큰을 브릿지하여 ITSHub 잔고를 증가시키면 공격자가 B A 체인으로 다시 브릿지를 하여 ITSHub 잔고를 줄일 수 있다. 이후 유저가 다시 B A 체인으로 브릿지를 시도하면 ITSHub의 잔고가 부족하여 브릿지 할 수 없게 된다.

Impact

ITSHub의 잔고가 부족하여 브릿지 할 수 없게 된다. 해당 브릿지를 DoS 할 수 있다.

Mitigation

Remote interchain 토큰이 배포되지 않은 체인으로 브릿지를 허용하는 것이 문제이다. update_token_balance 의 구현을 변경하여 잔고가 초기화된 체인으로만 브릿지가 가능하게 한다. source 체인의 잔고는 추적하지 않으려 한다면 밸런스 초기화 여부로 판단하지 말고 source 체인을 정확하게 식별한 뒤 예외 처리를 해야한다.


tags: bughunting, axelar, smart contract, solidity, rust, cosmwasm, bridge, lack-of-input-validation-vul, dos, severity high