Vulnerability

EOA 賬戶中的鎖定乙太幣:虛假合約地址

  • September 23, 2022

我正在閱讀這篇論文:CLUE: Towards Discovering Locked Cryptocurrencies in Ethereum,網址為: https ://www.researchgate.net/publication/346425189_CLUE_Towards_Discovering_Locked_Cryptocurrencies_in_Ethereum 它說:

Contract-creation Failure EOA: When the user deploys a
smart contract in Ethereum, he/she will still receive one fake contract
address if the contract-creation fails. Indeed, the received
contract address does not exist in StateDB just after the contractcreation
failure. However, some users might wrongly ignore the failure
message and still transfer cryptocurrencies to the fake contract
address, leading to cryptocurrencies locked permanently. Because
the address with locked cryptocurrencies never stores code, we
classify it as EOA.

是否有可能獲得虛假的合約地址?上面的文字是否正確?

祖爾菲。

也許“假”這個詞在那種情況下不適合使用。

讓我們看一下從solidity-by-example中獲取的另一個合約部署合約的這種方式:

   function deploy(bytes memory bytecode, uint _salt) public payable {
       address addr;

       /*
       NOTE: How to call create2

       create2(v, p, n, s)
       create new contract with code at memory p to p + n
       and send v wei
       and return the new address
       where new address = first 20 bytes of keccak256(0xff + address(this) + s + keccak256(mem[p…(p+n)))
             s = big-endian 256-bit value
       */
       assembly {
           addr := create2(
               callvalue(), // wei sent with current call
               // Actual code starts after skipping the first 32 bytes
               add(bytecode, 0x20),
               mload(bytecode), // Load the size of code contained in the first 32 bytes
               _salt // Salt from function arguments
           )

           if iszero(extcodesize(addr)) {
               revert(0, 0)
           }
       }

       emit Deployed(addr, _salt);
   }
}

特別注意程式碼塊:

if iszero(extcodesize(addr)) {
  revert(0, 0)
}

它通過檢查契約程式碼大小來檢查契約是否正確部署extcodesize在此處檢查操作碼列表)。

如果這個檢查不存在並且由於某種原因,合約沒有正確部署,我們將有一個地址,但沒有與之相關的程式碼。

合約的地址來源於部署者合約的資訊。因此,理論上,我們可以在不部署合約的情況下生成或獲取合約的可能地址。如果我們在實際部署合約之前將 eth 發送到該地址,那麼我們將無法將合約部署到該地址,我們將失去 eth。

例如,檢查以下合約部署程序:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.16;

contract TestDeployContract {
   uint256 public counter = 1;

   receive() external payable {}
}

contract Contract {

   // Using keccak256 hash of the contract name to use it as the salt
   bytes32 public hash = keccak256("TestDeployContract");
   address public testDeployContractAddress;
   address public testDeployContractAddressFromAssembly;

   // Function to derive the address of a smart contract.
   function getPredictedContractAddress() public view returns (address) {
       // Passing address(this) manually here. But we have no option to provide any address we want when actually deploying the contract with create2
       bytes32 hash32 = keccak256(
           abi.encodePacked(bytes1(0xff), address(this), uint256(hash), keccak256(type(TestDeployContract).creationCode))
       );
       return address(uint160(uint(hash32)));
   }

   function deploy() public {
       // No option provide any creator address we want when actually deploying the contract
       // So it uses the address of the contract that is executing this code,
       // mix it with the bytecode of the TestDeployContract and the salt to produce a
       // keccak256 hash and derive the new contract address from it
       TestDeployContract testDeployContract = new TestDeployContract{salt: hash}();
       testDeployContractAddress = address(testDeployContract);
   }

    function deployWithAssembly() public {
       uint256 _salt = uint256(hash);
       address addr;
       bytes memory bytecode = type(TestDeployContract).creationCode;

       assembly {
           addr := create2(
               callvalue(), // wei sent with current call
               // Actual code starts after skipping the first 32 bytes
               add(bytecode, 0x20),
               mload(bytecode), // Load the size of code contained in the first 32 bytes
               _salt // Salt from function arguments
           )

           if iszero(extcodesize(addr)) {
               revert(0, 0)
           }
       }

       testDeployContractAddressFromAssembly = addr;

   }

}

如果您呼叫該getPredictedContractAddress()函式,您將獲得deploy()deployWithAssembly()將創建並返回的合約的地址。因此,如果我們getPredictedContractAddress()在部署合約之前呼叫,並在 etherscan 中檢查返回的地址,它將看起來像一個正常的、有效的地址。我們可以向它發送 eth。但是我們沒有它的私鑰,它只是一種有效的地址格式,但它不屬於任何人,也不是合約。如果我們將 eth 發送到該地址,我們將無法將合約部署到該地址,我們將失去 eth。

我做的。查看:

在此處輸入圖像描述

https://rinkeby.etherscan.io/address/0xb2216681F3bA09280E5D018f1b7C03D532bF55dc

我向它發送了一些測試 eth。然後,我呼叫該deploy()函式,並將“派生”地址分配給狀態變數,以便我可以看到它:

在此處輸入圖像描述

但是你猜怎麼著,合約部署並沒有失敗,並且部署地址的實際地址不是預期的地址,因為它已經忙/使用了,所以它實際上部署在 address 0x26b76b352b0472f1494bc8e740cb0452fe516ed2,但deploy()函式說它部署在0xb2216681F3bA09280E5D018f1b7C03D532bF55dc. 特別糟糕。

檢查部署的合約:https ://rinkeby.etherscan.io/address/0x26b76b352b0472f1494bc8e740cb0452fe516ed2

所以,現在我認為我的合約的未來地址現在它只是一個普通的 EOA,並且由於我在部署合約之前已經向它發送了 eth,我無法恢復這些 eth,它們已經失去了。

因此,這是我們在部署合約時需要注意的事情之一。

引用自:https://ethereum.stackexchange.com/questions/136191