code4rena-2024-08-chakra-h10
[H-10] ChakraSettlement.receive_cross_chain_msg and ChakraSettlement.receive_cross_chain_callback functions do not ensure that receiving ChakraSettlement contract’s contract_chain_name must match to_chain corresponding to respective txid input though they should
Summary
브릿지를 받을 때 toChain 파라미터가 자신의 체인이 맞는 지를 확인하지 않는다. 즉, 다른 체인이 목적지인 메시지를 등록해도 처리할 수 있으며, 다른 체인에서 사용된 브릿지 요청 서명을 재전송하면 토큰을 탈취할 수 있다.
Keyword
theft, lending protocol, replay attack, bridge, signature
Vulnerability
txid를 만들기 위해 해시할 때 toChain 를 포함하는 것으로 txid 에 목적지 체인에 대한 정보를 포함한다. 하지만 이 정책은 목적지 체인에서 자신의 체인 이름을 파라미터로 사용하며 txid를 직접 계산하여 사용할 때 유효한 것이다. receive_cross_chain_msg 함수는 txid 를 재계산하지 않고 입력받은 값을 그대로 이용한다. 즉, 현재 txid 는 검증 없이 사용되므로 toChain 역시 검증되지 않고 있다는 의미이며, 다른 체인이 목적지인 메시지를 등록해도 처리할 수 있다는 의미이다.
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 {
{
// verify signature
bytes32 message_hash = keccak256(
abi.encodePacked(
@> txid,
from_chain,
from_address,
from_handler,
to_handler,
keccak256(payload)
)
);
require(
@> signature_verifier.verify(message_hash, signatures, sign_type),
"Invalid signature"
);
require(
receive_cross_txs[txid].status == CrossChainMsgStatus.Unknow,
"Invalid transaction status"
);
}
...
}서명 replay attack을 통해 receive_cross_chain_msg 를 호출하면 토큰을 부정 수급할 수 있다. 서명 replay attack이 가능하려면 한 가지 조건이 있다. to_handler 와 동일한 주소에 handler 컨트랙트가 배포되어 있어야 한다. 동일한 트랜잭션 nonce 를 이용하여 배포하거나 create2를 통해 배포하는 경우 동일한 주소에 컨트랙트를 배포할 수 있다.
많은 프로토콜들이 멀티체인 지원을 할 때는 각 체인의 컨트랙트 주소를 동일하게 맞추곤 한다. 그리고 유저가 자신의 handler를 배포한 뒤 시스템에 연동할 수 있으므로 여러 체인에 동일 주소로 핸들러를 배포하는 것을 막을 수 없다. 따라서 동일 주소에 Handler 가 있을 수 있다는 가정은 현실적이다. 따라서 Settlement는 서명 해시에 to_chain 정보를 추가하여 서명 replay attack을 막을 책임이 있다.
Impact
서명을 재사용하여 토큰을 탈취할 수 있음
Mitigation
message_hash 에 목적지 체인 이름을 포함한다. ERC712 를 적용하는 것도 좋은 방법이다.
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 {
{
// verify signature
bytes32 message_hash = keccak256(
abi.encodePacked(
txid,
from_chain,
from_address,
from_handler,
to_handler,
+ keccak256(contract_chain_name), // toChain name
keccak256(payload)
)
);
require(
signature_verifier.verify(message_hash, signatures, sign_type),
"Invalid signature"
);
require(
receive_cross_txs[txid].status == CrossChainMsgStatus.Unknow,
"Invalid transaction status"
);
}
...
}tags: bughunting, chakra, smart contract, starknet, cairo, bridge, cross chain, lack-of-input-validation-vul, signature, replay attack, crypto theft, severity high