code4rena-2024-08-chakra-m10
[M-10] Does not check if to_chain and to_handler is whitelisted in cross_chain_erc20_settlement
Summary
출발지에서 메시지를 보낼 때, 화이트리스트에 등록되어 있는 목적지로 보내는 지를 확인하지 않는다. 이로 인해 유저는 잘못 요청할 수 있고, 이렇게 잘못 요청된 자산은 잠긴다.
Keyword
bridge, cross chain, lack of input validation vul, asset lock
Vulnerability
Handler.cross_chain_erc20_settlement 에서 to_chain과 to_handler 가 화이트리스트에 등록되어 있는 지 확인하지 않는다. 따라서 이 핸들러와 매치되지 않는 임의의 체인, 핸들러로 메시지를 보낼 수 있다.
function cross_chain_erc20_settlement(
string memory to_chain,
uint256 to_handler,
uint256 to_token,
uint256 to,
uint256 amount
) external {
require(amount > 0, "Amount must be greater than 0");
require(to != 0, "Invalid to address");
@> require(to_handler != 0, "Invalid to handler address");
require(to_token != 0, "Invalid to token address");
if (mode == SettlementMode.MintBurn) {
_erc20_lock(msg.sender, address(this), amount);
} else if (mode == SettlementMode.LockUnlock) {
_erc20_lock(msg.sender, address(this), amount);
} else if (mode == SettlementMode.LockMint) {
_erc20_lock(msg.sender, address(this), amount);
} else if (mode == SettlementMode.BurnUnlock) {
_erc20_burn(msg.sender, amount);
}
...
}만약 to_handler 로 컨트랙트가 아닌 주소를 설정했다면 목적지 체인에서 Handler.receive_cross_chain_msg 를 호출할 수 없어 트랜잭션이 revert 된다. 따라서 실패를 알리기 위한 이벤트를 발생시킬 수 없어 실패에 대한 핸들링도 불가하다.
// Settlement.receive_cross_chain_msg
function receive_cross_chain_msg(
uint256 txid,
string memory from_chain,
uint256 from_address,
uint256 from_handler,
address to_handler,
PayloadType payload_type,
bytes calldata payload,
uint8 sign_type, // validators signature type / multisig or bls sr25519
bytes calldata signatures // signature array
) external {
...
@> bool result = ISettlementHandler(to_handler).receive_cross_chain_msg( // this will be reverted
txid,
from_chain,
from_address,
from_handler,
payload_type,
payload,
sign_type,
signatures
);
CrossChainMsgStatus status = CrossChainMsgStatus.Failed;
if (result == true) {
status = CrossChainMsgStatus.Success;
receive_cross_txs[txid].status = CrossChainMsgStatus.Success;
} else {
@> receive_cross_txs[txid].status = CrossChainMsgStatus.Failed;
}
emit CrossChainHandleResult(
txid,
@> status,
contract_chain_name,
from_chain,
address(to_handler),
from_handler,
payload_type
);
}또한 한가지 문제가 더 있다. to_handler 가 핸들러 컨트랙트의 주소이긴 하지만, from_handler와 매치되지 않는 핸들러일 수 있다. 화이트리스트에 등록되지 않은 핸들러가 메시지를 요청했다면 Handler.receive_cross_chain_msg 는 false 를 리턴하여 실패를 알린다. Validator 는 CrossChainHandleResult 이벤트를 리스닝하여 receive_cross_chain_callback 을 통해 source 체인에게 실패를 알리고 핸들러가 실패를 처리하게 한다.
function receive_cross_chain_msg(
uint256 /**txid */,
string memory from_chain,
uint256 /**from_address */,
uint256 from_handler,
PayloadType payload_type,
bytes calldata payload,
uint8 /**sign type */,
bytes calldata /**signaturs */
) external onlySettlement returns (bool) {
// from_handler need in whitelist
@> if (is_valid_handler(from_chain, from_handler) == false) {
@> return false;
}
...
}하지만 Handler.receive_cross_chain_callback 에서는 오로지 화이트리스트에 등록된 체인과 핸들러만 콜백 메시지를 보낼 수 있도록 제한한다. 즉, 잘못된 체인-핸들러로 메시지를 보냈을 때 실패했음을 callback 으로 알리지만, 정작 출발지 체인의 핸들러는 잘못된 체인-핸들러로 인한 실패 상황을 핸들링하지 못하고 무시한다.
function receive_cross_chain_callback(
uint256 txid,
string memory from_chain,
uint256 from_handler,
CrossChainMsgStatus status,
uint8 /* sign_type */, // validators signature type / multisig or bls sr25519
bytes calldata /* signatures */
) external onlySettlement returns (bool) {
// from_handler need in whitelist
@> if (is_valid_handler(from_chain, from_handler) == false) {
@> return false;
}
require(
create_cross_txs[txid].status == CrossChainTxStatus.Pending,
"invalid CrossChainTxStatus"
);
if (status == CrossChainMsgStatus.Success) {
if (mode == SettlementMode.MintBurn) {
_erc20_burn(address(this), create_cross_txs[txid].amount);
}
create_cross_txs[txid].status = CrossChainTxStatus.Settled;
}
if (status == CrossChainMsgStatus.Failed) {
create_cross_txs[txid].status = CrossChainTxStatus.Failed;
}
return true;
}Impact
핸들러가 잘못된 체인과 핸들러로 토큰을 보내는 것을 막지 않는다. 잘못된 핸들러에게 메시지를 보내면 receive_cross_chain_callback 를 통해 실패를 핸들링할 수도 없다.
Mitigation
잘못된 체인-핸들러로 메시지 전송을 요청할 수 없도록 Handler.cross_chain_erc20_settlement 에서 to_chain 과 to_handler 가 올바른지 확인한다.
tags: bughunting, chakra, smart contract, starknet, solidity, bridge, cross chain, lack-of-input-validation-vul, asset lock, severity medium