code4rena-2023-01-biconomy-h07

[H-07] Replay attack

보고서

Summary

nonce 관련 확인 로직이 부족하여 Signature를 재사용해 replay 공격이 가능하다.

Keyword

replay attack, nonce, input validation, theft

Vulnerability

SmartAccount에게 컨트랙트 콜을 시킬 때, nonce를 확인한다. nonce는 batchId 별로 관리되며, 한 트랜잭션을 실행할 때마다 1씩 증가한다. nonces[batchId] 는 각 batchId 별로 0부터 시작하여 증가하며 소비된다.

function execTransaction(
    Transaction memory _tx,
    uint256 batchId,
    FeeRefund memory refundInfo,
    bytes memory signatures
) public payable virtual override returns (bool success) {
    uint256 startGas = gasleft() + 21000 + msg.data.length * 8;
 
    bytes32 txHash;
    {
        bytes memory txHashData =
            encodeTransactionData(
                // Transaction info
                _tx,
                // Payment info
                refundInfo,
                // Signature info
                nonces[batchId]
            );
    // Increase nonce and execute transaction.
    // Default space aka batchId is 0
    nonces[batchId]++;
    txHash = keccak256(txHashData);
    checkSignatures(txHash, txHashData, signatures);
}

해당 트랜잭션을 위한 서명이 올바른지 txHashData 에 nonce를 포함하여 검증한다. 여기서 문제는 batchId에 대한 검증이 없다. batchId를 바꾸어 nonces[batchId_maiupulated] 이 이전에 실행했던 트랜잭션에서 사용한 nonce와 동일하다면 해당 트랜잭션에 사용한 signature를 재사용 할 수 있다. 즉, 해당 트랜잭션을동일한 파라미터로 또다시 실행시킬 수 있다.

nonces[batchId] 가 제각각인 경우 적절한 상황을 기다려야 하므로 공격하기 위해서는 타이밍을 기다려야 한다. 하지만 무조건 가능한 경우가 있다. 바로 nonce의 초기값인 0을 이용하는 트랜잭션, 즉 유저가 각 batchId로 처음 실행한 트랜잭션이다. nonce가 0인 2^256개의 batchId를 활용할 수 있으므로, 첫번째 트랜잭션을 매우 많이 replay 할 수 있다.

다음은 간단한 PoC 코드이다. 첫번째 execTransaction 에서 batchId를 1의 nonce 0을 이용해 트랜잭션을 생성한다. 두번째 execTransaction 에서 batchId를 77의 nonce 0을 이용해 동일한 signature를 이용하여 동일한 트랜잭션을 생성한다.

const txs: MetaTransaction[] = [
    buildContractCall(
        walletFactory,
        "deployCounterFactualWallet",
        [owner, entryPoint.address, handler.address, 1],
        0
    ),
    buildContractCall(
        userSCW,
        "execTransaction",
        [transaction, 1, refundInfo, signature],
        0
    ),
    buildContractCall(
        userSCW,
        "execTransaction",
        [transaction, 77, refundInfo, signature],
        0
    ),
];

출처: PoC 코드 https://github.com/code-423n4/2023-01-biconomy-findings/issues/316

Impact

Replay 공격을 이용하여 유저의 자산을 빼내거나 의도치 않는 작업을 반복하게 할 수 있다.

Mitigation

batchId 를 Signature 확인 대상 데이터에 포함하여 확인한다.


tags: bughunting, smart contract, biconomy, account abstraction, erc4337, crypto theft, lack-of-input-validation-vul, replay attack, signature, wallet, severity high