bitbank

Hacking Smart Contract Solidity ブロックチェーン

[Solidity-Bug Bounty] block.timestampの脆弱性を1からわかりやすく解説

かるでね

こんにちは!実務でPython、Djangoを使って、機械学習やWebアプリケーション開発などをしているかるでねです!
最近はSolidityを使ってスマートコントラクト開発やバグを見つけたりしています。

今回は「タイムスタンプ」の脆弱性について解説していきます!

Solidityではblock.timestampという「タイムスタンプ」がよく使用されています。

実はこの「タイムスタンプ」には脆弱性につながるような危険性が含まれています...。

よく使用されるからこそ注意が必要なので、ぜひこの記事で学んでいってください!

Solidityスキルを1段階あげたい方やバグ・バウンティに参加したいバグハンターを目指している方は必須の知識となるので、この記事で学んでいってください。

バグ・バウンティが何かわからない人は以下の記事を読んでください。

また、以下の記事でもこの記事では取り上げていないblock.timestampの危険性について紹介しているので参考にしてください!

タイムスタンプとは?

まずはタイムスタンプの定義から確認していきましょう!

タイムスタンプの定義

Wikipediaでは以下のように書かれています。

タイムスタンプ(英: timestamp)とはある出来事が発生した日時・日付・時刻などを示す文字列。狭義には郵便物の発送日時等を示すために押される郵便印のことを指す(画像を参照のこと)[1]。現在ではコンピュータにおける「タイムスタンプ」が良く知られている。

https://ja.wikipedia.org/wiki/タイムスタンプ

ある時点での日付や日時を表したものがタイムスタンプであると書かれていますね。

例えばOSでは、「ファイルの作成時」、「ファイルの更新時」に自動で付与されたりします。

Solidityでのタイムスタンプ

では、次にSolidityではタイムスタンプをどのように使用するのか見ていきましょう。

Solidityの公式ドキュメントを確認すると以下のように書かれています。

block.timestamp (uint): 現在のunixのタイムスタンプ(秒)

https://solidity-jp.readthedocs.io/ja/latest/units-and-global-variables.html

まずはuint型かつ秒で示されると言うことがわかりました。

unixと書かれているのですがこれは何でしょう?

unix時間についてwikipediaで調べると以下のように書かれています。

UNIX時間(ユニックスじかん)またはUNIX時刻(ユニックスじこく、UNIX time(ユニックスタイム)、POSIXtime(ポジックスタイム))とはコンピューターシステム上での時刻表現の一種。協定世界時 (UTC) での1970年1月1日午前0時0分0秒(UNIXエポック)から形式的な経過秒数として表される。

真の経過秒数ではなく[1]、その間に挿入された閏秒を引き、削除された閏秒を加えた値である。大多数のシステムで採用されている[注 2]。

UNIX系のオペレーティングシステム(データ型はtime_t)だけでなく、他の多くのオペレーティングシステムにおいてもこの表現方法が用いられている。システム内部では64ビット符号付整数(signed int)や64ビット倍精度浮動小数点数で扱われていることが多い。ここで、以前は多かった32ビット整数で扱われていた場合で、符号付きであった場合、その最大値 2,147,483,647 を超えると負の値になり、正しく時刻を扱えなくなるという問題がある。これを2038年問題という。

https://ja.wikipedia.org/wiki/UNIX時間

読んでも理解しづらいと思うので、コンピューターシステム上での時間表現の1つと覚えておけば良いです!

では実際にSolidityで実行してみましょう。

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.13;

contract Timestamp {
    uint public time;

    function updateTimestamp() public {
        time = block.timestamp;
    }
}

上記のコードを実行すると以下の数値がtime変数に格納されました。

1672451295

ではこの数値を通常の日時に変換してみましょう。

以下のサイトを使います。

2022-12-31 10:48:15

このように変換されました。

タイムスタンプ操作とは?

前章でタイムスタンプの基礎について理解できました。

実はこのタイムスタンプですがマイナーによって操作することができてしまいます。

マイナーとは「トランザクションを検証し、問題なければブロックに含める作業」を行う人のことを指します。

詳しくはcoinbaseさんの以下の記事などが参考になります。

このマイナーによって以下の条件のもとタイムスタンプを自由に操作され、スマートコントラクトを攻撃することができてしまいます。

条件

  • 最後のブロックのタイムスタンプよりも後の時間になっている。
  • 追加するタイムスタンプがあまりにも遠い未来であってはいけない。

この条件を満たせばマイナーによって自由に操作される危険性があります。

具体的には次の章で紹介していきます!

タイムスタンプ操作の実装

前章ではタイムスタンプ操作について確認してきました。

この章では実際のコードをもとにタイムスタンプ操作の危険性について確認してきます!

コード

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.13;

contract Roulette {

    constructor() payable {}

    /// @notice block.timestampが7で割り切れる場合コントラクト内の資金を取得できる関数。
    function judgment() external payable {
        require(msg.value == 1 ether);

        if (block.timestamp % 7 == 0) {
            (bool sent, ) = msg.sender.call{value: address(this).balance}("");
            require(sent, "Failed to send Ether");
        }
    }
}

コードの解説

上記のコードは1 etherを預けてjudgment関数を実行すると、実行タイミングでのタイムスタンプを取得し、もしタイムスタンプが7で割り切れる場合はコントラクト内の資金を全て取得できるものです。

このコードの何がいけないかというと、マイナーが7で割り切れるタイムスタンプを指定してトランザクションを通すことができてしまうことです。

そうするとランダム性は失われ、マイナーにコントラクト内の資金を好き放題に抜かれてしまいます。

以下の記事でもblock.timesampの危険性を取り上げているので、ぜひ参考にしてください。

回避策

ではどうすればマイナーにタイムスタンプを操作されないようにできるでしょうか?

方法は2つあります。

block.timestampを使用しない

そもそもblock.timestampを使用して判定しない設計にすれば、マイナーに好き放題資金を抜かれなくなります。

以下の記事でもblock.timestampの脆弱性を取り上げているように、block.timestampを使用する際は注意が必要なので、使用する部分は注意深く考える必要があります。

15秒ルール

5秒ルール」は聞いたことあっても、「15秒ルール」は聞いたことないと思います。

では15秒ルールとは何でしょうか?

先ほどマイナーがタイムスタンプを操作できる条件として「追加するタイムスタンプがあまりにも遠い未来であってはいけない。」と言うものがありました。

この「あまりにも遠い未来」が15秒先と言うことです。

15秒先のタイムスタンプを持つブロックはブロックされるように設計されています。

つまり、もし15秒経っても整合性が保たれるのであれば、block.timestampを使用しても問題ないという事になります。

最後に

今回は「タイムスタンプ」について紹介していきました!

いかがだったでしょうか?

ポイント

  • タイムスタンプについて理解できた!
  • タイムスタンプの脆弱性について理解できた!
  • タイムスタンプを使用する際の注意点を理解できた!

あなたが上記が当てはまっていれば嬉しいです!

もし何か質問などがあれば以下のTwitterなどから連絡ください!

普段はSolidityやブロックチェーン、Web3についての情報発信をしています。

Twiiterでは気になった記事などを共有しているので、ぜひフォローしてくれると嬉しいです!

参考

-Hacking, Smart Contract, Solidity, ブロックチェーン
-, ,