code4rena-2024-08-chakra-m02

[M-02] Missing ERC20Method validation at destination allows non-transfer tx to be handled as transfers

보고서

Summary

Cairo 구현과는 다르게, Solidity에서는 전달 받은 메시지에서 method_id를 확인하지 않았다. 이는 크로스체인 브리지의 무결성을 훼손하고 의도하지 않은 조작을 가할 수 있게 한다.

Keyword

bridge, cross chain, lack of input validation

Vulnerability

Cairo 핸들러는 크로스 체인 메시지를 수신하면 메시지를 이를 디코딩하여 적절한 지 확인한다.

  1. payload_type이 ERC20 인지 확인한다.
  2. method_id 가 Transfer 함수인지 확인한다.
fn receive_cross_chain_msg(ref self: ContractState, cross_chain_msg_id: u256, from_chain: felt252, to_chain: felt252,
from_handler: u256, to_handler: ContractAddress, payload: Array<u8>) -> bool{
    assert(to_handler == get_contract_address(),'error to_handler');
 
    assert(self.settlement_address.read() == get_caller_address(), 'not settlement');
 
    assert(self.support_handler.read((from_chain, from_handler)) && 
            self.support_handler.read((to_chain, contract_address_to_u256(to_handler))), 'not support handler');
 
    let message :Message= decode_message(payload);
    let payload_type = message.payload_type;
@>  assert(payload_type == PayloadType::ERC20, 'payload type not erc20');
    let payload_transfer = message.payload;
@>  let transfer = decode_transfer(payload_transfer);
@>  assert(transfer.method_id == ERC20Method::TRANSFER, 'ERC20Method must TRANSFER');
    ...
}

하지만 Solidity의 핸들러는 payload_type만 확인하고, method_id는 확인하지 않는다.

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;
    }
    bytes calldata msg_payload = MessageV1Codec.payload(payload);
 
    require(isValidPayloadType(payload_type), "Invalid payload type");
 
@>  if (payload_type == PayloadType.ERC20) {
        // Cross chain transfer
        {
            // Decode transfer payload
@>          ERC20TransferPayload memory transfer_payload = codec
                .deocde_transfer(msg_payload);
 
            if (mode == SettlementMode.MintBurn) {
                _erc20_mint(
                    AddressCast.to_address(transfer_payload.to),
                    transfer_payload.amount
                );
                return true;
            } 
            ...

Impact

잘못된 method_id 메시지를 정상으로 통과시킬 수 있다.

Mitigation

Solidity 구현에서도 method_id 를 확인한다.

Memo

현재 사용되는 method_id는 Transfer 뿐이므로 Low라고 이의가 있었지만, 노드가 오딧 범위가 아니기 때문에 좀 더 관대하게 취약점으로 인정한 것 같다.


tags: bughunting, chakra, smart contract, starknet, solidity, bridge, cross chain, severity medium, lack-of-input-validation-vul