TombForkに対する攻撃手法を一挙公開します

この記事は約29分で読めます。
スポンサーリンク

攻撃手法を理解することで、自衛が可能になる。セキュリティの基本です。

  1. 当記事の執筆を決めた理由
  2. Bad Actor (悪意ある攻撃者)について
    1. Devについて
    2. Dev以外のプレイヤー
  3. TombForkのコントラクトについて
    1. Peg Token
    2. Share Token
    3. Treasury
    4. Boardroom
    5. Bond
    6. Share reward pool
    7. Genesis Reward Pool (Gen Pool)
    8. 殆どのラグはGen Pool段階で発生する
      1. ラグ目的のDevは、そもそもプロジェクトを継続するつもりがない
      2. Devの能力不足がバレる前にラグる
  4. 具体的な攻撃手法
    1. 1.Devによるトークンのダンプ(大量売却)
      1. Gen PoolのDeposit Fee
      2. Boardroomの報酬
      3. Tokenの追加Mint
    2. 2.Dev以外のプレイヤーによるトークンのダンプ
    3. 3.Deposit Feeの吊り上げ
    4. 4.BRのDev FundとDAO Fundの吊り上げ
    5. 5.資金を抜くコードを入れておく
    6. 6.governanceRecoverUnsupported()の悪用(その1)
    7. 7.governanceRecoverUnsupported()の悪用(その2)
    8. 8.governanceRecoverUnsupported()の悪用(その3)
    9. 9.Tomb Forkのプールの仕組みを悪用
    10. 10.悪意あるコントラクトにすり替え(フロントエンド)
  5. 対策
    1. 全てなくなっても良い金額でプレイする
    2. LP内の資金を常にチェックする
      1. Gen Pool開始時にLP内資金が少なければ危険
      2. プロジェクト中のLP減少も危険
    3. BRの利用は危険
    4. コミュニティがTelegramだけは危険
    5. RugDoc reviewedは自分での確認が必要
    6. コミュニティに入って情報集め
    7. Renounceの確認
    8. プロジェクトのデザインがしょぼかったら危険
    9. キャラクター名のプロジェクトは危険
    10. コードをDiffする
    11. governanceRecoverUnsupported()に注意する
    12. Approve先のコントラクトに注意する
  6. 終わりに

当記事の執筆を決めた理由

前回の記事で紹介したとおり、TombForkが盛り上がってた時代は終わりました。他のプロジェクトを簡単にクローンできるようになったことで、品質が悪いプロジェクトが乱立したことが大きな要因です。

現在、新しいTombForkは「9割がスキャム(詐欺)、1割がスキャムじゃないが品質が悪い」って感じになっています。つまり、新しく作られてる大半は詐欺目的だと考えても差し支えないかと。

TombForkは詐欺の巣窟です。高APRなのには、それなりの理由があるのです。

なお、仮想通貨の詐欺のことを、海外では「ラグ」と呼びます。これは、「マット(Rug)の上に立っている投資家を、マットを引っ張ることで一気に倒す」アナロジーからきています。この記事でも、ラグと呼ぶことにします。

私はこの1年間ほど様々なTombForkを観察してきて、彼ら(悪意ある攻撃者)のラグの手法を研究してきました。

この記事では、私が知りうる限りの、特にメジャーなラグの手法について解説していきます。

TombForkのラグ手法の数としては、この記事が世界で最も網羅しているはずです。

なお、当記事は「TombForkをそれなりに知っている」前提で話を進めるため、専門用語が乱立している箇所もあります。その辺は適当に読み進んでください。

この記事の進め方ですが、まずは「攻撃者」の分類を行います。その後に、それぞれの攻撃手法を解説します。最後に、被害を抑えるための推奨事項について説明します。

基本的にTombForkにフォーカスした話ですが、今後増えていくであろうWeb3の新たなサービスにも活用できると思います。

なお、プレイヤーのウォレットに対する攻撃手法は、Tomb Fork関係なく仮想通貨(Crypto Block Chain)全般に関する内容なので、以下の記事を参照ください。

Bad Actor (悪意ある攻撃者)について

TombForkに対する攻撃者は2通りに分類されます。

  • Dev(管理者・運営者)
  • 他のプレイヤー

Devについて

TombForkに参加していると、よく「Devが・・・」とか聞くと思いますが、このDevについて解説します。

Devは「Development Team」の略称で、IT業界で働いている人は「開発チーム」と思うかもしれません。

しかし、DeFiの世界では、Devとは「プロジェクトの開発から運営まで、全てを担当しているチーム」と考えることが一般的です。と言いますのも、TombForkなどの「ブロックチェーン上のサービス」を開発・運営するチームは一般的に2-5人程度の少人数で構成されているからです。わざわざ開発・運営など人を割り振るレベルではないのです。

なので「プロジェクトのチームメンバー」と同義で「Dev」が利用されるシーンが非常に多い。

話を戻します。

TombForkのラグは90%以上がDevによるものだと考えています。これまでの実績と照らし合わせた肌感覚です。

彼らが実装したTombForkサービスの中に、悪意ある仕掛けが施されており、お金が集まってきたタイミングでラグるケースが非常に多い。

この記事の大半は、この「Devによる、悪意ある仕掛け」について解説していきます。

Dev以外のプレイヤー

我々のような一般プレイヤーを指します。

上述の通り、TombForkでは、Dev以外のプレイヤーによるラグは殆ど見かけたことがありません。

ただ、どこまでが「ラグ」かについては主観的なところもありますので、Dev以外のプレイヤーによるラグについても少し考察していきます。

TombForkのコントラクトについて

この章は元々書くつもりはなかったのですが、後述する「攻撃方法」の理解を深める目的で執筆することにしました。

既にご存知な方は読み飛ばしてください。

TombForkは主に以下のコントラクトが相互に連携することで機能しています(間接的に連携)。

Oracleは敢えて割愛します。

  • Peg Token
  • Share Token
  • Treasury
  • Boardroom
  • Bond
  • Share reward pool
  • Genesis reward pool

Peg Token

プロジェクトのトークンです。このトークンをUSDCやFTMなどの主要トークンとPegさせることが目的です。

Share Token

プロジェクトの株式みたいなものです。Peg TokenがDepegすると一気に価格が下がります。

Treasury

実は最も重要なのですが、説明が非常にややこしい。このコントラクトがRewardを管理したり、Boardroomの状態を管理したりします。

Boardroom

略してBR。ここにShare Tokenを預けることでPeg Tokenが取得できます。

Bond

Tomb Forkで最も使われていない機能かも。Depegしたときの買い支えに使われます。

Share reward pool

このPoolにDepositすることでファーミングができます。報酬(Reward)はShare Tokenです。

ここまでが主要なコントラクトの説明です。Tomb Forkは簡単に言うと「いかにPeg TokenをDepegさせないか」のゲームです。Share reward poolに預けることで、Peg Tokenが新たに発行されて、報酬として出回ります。受け取ったプレイヤーは報酬を売却し、結果としてPeg Tokenの価格が下がります。Peg TokenはShare reward poolに預けることも可能で、その場合の報酬はShare tokenです。受け取ったプレイヤーはShare tokenを売却し、結果としてShare tokenの価格が下がります。このままだと両方の価格が下がり続けるので、TWAPやBondなどの対策を講じて価格下落と戦うのですが、その辺は別の記事で解説予定です。

さて、Peg Tokenが重要であることは理解いただけたと思うのですが、そもそもプロジェクトの始めは(Dev以外は) 誰もPeg Tokenを持っていません。このPeg Tokenを初めに生み出す(厳密にはあらかじめDevがアサインしたPeg Tokenを一般プレイヤーに放出する)のがGenesis Reward Pool (通称 Gen Pool)です。

Genesis Reward Pool (Gen Pool)

これはプロジェクト開始から数日だけ稼働するプールです。

このプールでファーミングを行った場合、報酬が(Share Token)ではなく、Peg Tokenとなります。

預ける通貨は、通常はUSDCやFTMなどの主要トークンとなります。

殆どのラグはGen Pool段階で発生する

重要なポイント。

私の肌感覚では7割以上のラグがGen Pool中のラグ、若しくはGen Poolが終わった直後のラグです。

なぜGen Poolの段階でのラグが多いのか?理由は以下の通り。

ラグ目的のDevは、そもそもプロジェクトを継続するつもりがない

ラグ目的のDevは早い段階でラグった方が効率が良い。Gen Poolはプロジェクト開始直後のフェーズであり、この時点でラグるのが手っ取り早いのです。

フロントエンドはしっかりしていても、コントラクトはGen Pool以外はむちゃくちゃなラグプロジェクトも何度もみてきました。

Devの能力不足がバレる前にラグる

ブロックチェーン上にスマートコントラクトを実装可能なSolidityエキスパートって、実際は世界でも多くありません。

TombForkのコントラクトを理解している人なんで本当に稀です。恐らく世界で50人もいないかと。

私はTombForkのコミュニティで多岐にわたって活動しており、今では新しいプロジェクトを始めたいDevからDMを貰って「このコントラクトのこの値は何を設定した方がいいか?推奨値はあるか?」などの相談を受けることもありますが、、そんなレベルでプロジェクト運営できるのか?と思うほどレベルが低い。

ラグ目的でプロジェクトを作っているDevのほとんどは、実はスマートコントラクトやTombForkの知識が乏しいケースが多く、プロジェクトを長く続けると知識のなさが露呈してしまうので、本音としては早く資金を抜いて切り上げたい訳です。なので、Gen Poolのタイミングで逃げ切りたい。

ここまでで、Tomb Forkの基本や攻撃者の分類を行ってきました。では、いよいよ具体的な攻撃手法について解説していきます。

具体的な攻撃手法

かなり専門用語が出てきます。

1.Devによるトークンのダンプ(大量売却)

これをラグと言っていいのかは微妙ですが・・・ちなみに個人的にはルール範囲内だと思っています。ただ、人によっては「Soft Rug」などラグと定義する場合もあるので、対象に入れておきます。

そもそも、Devはどうやって収益をあげているのでしょうか?主に以下の3通りです。

Gen PoolのDeposit Fee

プレイヤーがDepositした際に、Deposit Feeが自動的にDevに支払われる仕組みです。通常は0.5%か1%程度です。

例えば全体で$3000がプールされた場合は、およそ$30程度がDevのウォレットに転送されていると考えれば良い。

このDeposit FeeはGen Poolコントラクトにて定義されます。後述します。

Boardroomの報酬

これがDevの収益の中心となります。Boardroom利用者はPeg Tokenが報酬として支払われることは前述しました。これ、もう少し細かく説明すると、一回に放出するPeg Tokenの量は決まっていて、Boardroom(以下BR)の利用者に割合分配されています。

その排出量が決まっているPeg Tokenのうちの数%がDevに支払われている仕組みです。厳密にはDao Fundというのも定義されており、それも数%支払われています。

通常はTreasuryのsetExtraFunds()にて設定され、daoFundSharedPercentの値が分配時の割合として使用されます。

プロジェクトが健全な時しかBRの排出は行われないため、この報酬は正当です。

Tokenの追加Mint

DevはTokenコントラクトのオーナーでもあるので、やりようによっては自由に数を増やして自身のウォレットに転送することが可能です。これは行われないようにRenounceしたりするのですが、当然ながらルール違反です。

上記の手法で取得したTokenをDevが売却すると、当然ながら価格が下がります(DepositFeeは例外)。でも、Devも慈善事業じゃないので収益を上げる必要があるので、個人的にはDevFeeで取得したTokenを売る行為は否定しません。問題になるのは、上記の「Tokenの追加Mint」などで不当に手に入れたTokenのダンプです。

2.Dev以外のプレイヤーによるトークンのダンプ

これもラグとは言えないと思っています。資産を大量に保有するプレイヤー若しくはグループが一斉に売却することで、トークン価格の下落を狙うものです。

最近のTombForkは規模が縮小しており、LPが$2000程度っていうのも珍しくありません。そんな時に$1000程度のダンプが行われると、価格が急激に下落します。Sell Panicで更に下落したタイミングで購入を狙っているグループも存在します。

3.Deposit Feeの吊り上げ

ここからは技術的なラグ手法となります。

まずはGen PoolのDeposit Feeの吊り上げです。始めは0.5%などの良心的な値にしておいて、急にDeposit Feeを上げるのです。

基本的にDeposit FeeがとられるタイミングはDepsitしたタイミングです。なので、(基本的には)既にDepositした人に被害はありません。

Gen Poolが健全に動いていると感じた人が自分も入ってみようと思って、Depositして被害にあうパターンです。

4.BRのDev FundとDAO Fundの吊り上げ

3.と似ていますが、こちらはBRのDev FundとDAO Fundを後で変更するものです。

そもそもBRが健全に動いていることが前提なので、かなりレアなケース。

5.資金を抜くコードを入れておく

Gen PoolとShare Pool両方で多発している手口です。

スマートコントラクトに予め資金を盗むコードを入れておいて、プールに資金が集まったタイミングでメソッドをコールして資金を奪う。

実例を出しますね。ラグプロジェクト「Starburst FInance」のPoolコントラクト0x3D99Ae3F972cC9f02cFE9f762247eBE943403DE2の一部分を抜粋します。

    function MarsAllocation(
        IERC20 _token,
        uint256 _amount,
        address _to
    ) external onlyOperator {
        _token.transfer(_to, _amount);
    }

この関数MarsAllocation()が呼ばれると、呼び出し元(Operator)にプールの資産を送信する、非常にシンプルなコードです。

このプロジェクトによって約$2000以上が被害にあいました。

スマートコントラクトは一度作ったら(基本的に)変更ができません。コードも公開されているので「なんで事前に見つからなかったの?」って疑問に思うかもしれないのですが、実は上記のケースのStarburstでは、メインで使われていたShare Reward Poolのコントラクトは問題ありませんでした(上記のコードは存在していませんでした)。安全なプロジェクトを装っていたのです。で、信頼を勝ち取り始めたタイミングで「お得なプールを作りました」と言って、上記のコントラクトにプレイヤーを誘導したのです。そして、資金が集まって数時間で上記の関数をコールして逃げました。

このプロジェクトのPeg TokenはMARSでした。MarsAllocationという関数名も「Marsのトークン追加補填かな?」と思わせる名前にしたのでしょう。実際はPeg Tokenとは全く関係のないMalicious Codeです。

この攻撃に対する防ぎ方については後述しますが、Tomb Financeオリジナルのコードに存在しない関数があったら、気をつけた方がいいです。

6.governanceRecoverUnsupported()の悪用(その1)

コードを悪用したラグの場合、ほとんどはgovernanceRecoverUnsupported()の悪用です。

それぞれのPoolコントラクトにはgovernanceRecoverUnsupported()という関数が用意されています。オリジナルのコードは以下の通り。

    function governanceRecoverUnsupported(IERC20 _token, uint256 amount, address to) external onlyOperator {
        if (block.timestamp < poolEndTime + 90 days) {
            // do not allow to drain core token (TOMB or lps) if less than 90 days after pool ends
            require(_token != tomb, "tomb");
            uint256 length = poolInfo.length;
            for (uint256 pid = 0; pid < length; ++pid) {
                PoolInfo storage pool = poolInfo[pid];
                require(_token != pool.token, "pool.token");
            }
        }
        _token.safeTransfer(to, amount);
    }

このコントラクトの目的は、以下の2点です。

  • プールの活動が終わった時(主にプロジェクトが終わった時)、その数ヶ月後に資金を救出する
  • 万が一、設定したプールと違う種類のトークンが入ってしまった際に、その資金を救出する

つまり、通常は使われるものではなく、あくまでも超例外時を救出するための関数です。

非常に強力な関数です。プール内の資金を抜くことができるので。

こんな関数を自由に悪用されたらたまったものではないので、2つの制御が備わっています。まずは以下です。

        if (block.timestamp < poolEndTime + 90 days) {

つまり、コールした時間がプール終了時間の90日後の場合は、後続のプロテクションをチェックします。

require(_token != tomb, "tomb");

引き出そうとしたトークンはPeg Token以外でなければなりません。もしPeg Tokenを引き出そうとしたら、その時点でエラーとなり引き出しに失敗します。

            for (uint256 pid = 0; pid < length; ++pid) {
                PoolInfo storage pool = poolInfo[pid];
                require(_token != pool.token, "pool.token");
            }

引き出そうとしたトークンは、プールに登録されているトークン以外でなければなりません。もしプールに登録されているトークンを引き出そうとしたら、その時点でエラーとなり引き出しに失敗します。

つまり、Tomb Financeのオリジナルコードでは、もしgovernanceRecoverUnsupported()を実行したら以下の挙動となります。(そもそもOperatorしか実行できない)

  • プール終了から90日が立っていない場合は、Peg Token若しくはPoolに登録されているToken以外しか自由に引き出せない

今回の攻撃は、このコードに手を加えられているパターンです。

まずは簡単なもの。Zombie FinanceのGen Poolの例です。

    function governanceRecoverUnsupported(IERC20 _token, uint256 amount, address to) external onlyOperator {
        if (block.timestamp < poolEndTime + 0 days) {
            // do not allow to drain core token (ZOMBIE or lps) if less than 90 days after pool ends
            require(_token != zombie, "zombie");
            uint256 length = poolInfo.length;
            for (uint256 pid = 0; pid < length; ++pid) {
                PoolInfo storage pool = poolInfo[pid];
                require(_token != pool.token, "pool.token");
            }
        }
        _token.safeTransfer(to, amount);
    }

おわかりになりますでしょうか。

90daysが0daysになっています。つまり、Gen Poolが終わった直後に、全てのプールの資金を抜くことが可能になっています。

7.governanceRecoverUnsupported()の悪用(その2)

こんなのもありました。

    function governanceRecoverUnsupported(IERC20 _token, uint256 amount, address to) external onlyOperator {
        if (block.timestamp < poolEndTime + 90 days) {
            // do not allow to drain core token (UNI or lps) if less than 90 days after pool ends
            require(_token != uni, "uni");
            uint256 length = poolInfo.length;
        }
        _token.safeTransfer(to, amount);
    }

プールチェックを全て外すパターンです。

8.governanceRecoverUnsupported()の悪用(その3)

次はもっと巧妙です。Bee FinanceのGen Pool 0x2B1bA43e9A37Fe5fF09C2BD6624A89E296E1B4b4を見ていきましょう。

    function governanceRecoverUnsupported(IERC20 _token, uint256 amount, address to) external onlyOperator {
        if (block.timestamp < poolEndTime + 90 days) {
            // do not allow to drain core token (SYRUP or lps) if less than 90 days after pool ends
            require(_token != syrup, "syrup");
            uint256 length = poolInfo.length;
            for (uint256 pid = 0; pid < length; ++pid) {
                PoolInfo storage pool = poolInfo[pid];
                require(_token != pool.token, "pool.token");
            }
        }
        _token.safeTransfer(to, amount);
    }

上記のコード自体には問題はなかったのですが「コールした時間が、poolEndTime+90日以上」というロジックが攻撃されました

同コントラクトに以下のコードが追加されていました。

    function setGenStartTime(uint256 _genStartTime) external onlyOperator {
        require(block.timestamp < _genStartTime, "late");
        poolStartTime = _genStartTime;
        poolEndTime = poolStartTime + runningTime;
    }

まず、このsetGenStartTime()という関数は、Tomb Financeのオリジナルコードには存在していません。Devが意図的に追加したものです。

一見するとプールのStartTimeを変更する事が目的に見えます。でも、Devの本当の目的はpoolEndTimeを変更する事でした。

上記のコードは以下のとおり動作します。

  1. 関数の引数値と、コールした時刻を比較し、関数の引数値が大きくなければ、エラーを返し後続の処理を行わない。
  2. 引数値をpoolStartTimeに代入する
  3. 「2.」で変更されたpoolStartTimeとrunningTimeを合わせた結果をpoolEndTimeに代入する

つまり、極端に小さい引数値を指定すると、結果的にpoolEndTimeも小さくなり、governanceRecoverUnsupported()のプロテクションを回避できるのです。

(ここで時刻に「小さい」という表現を使っているのはSolidityは時刻にUnix Timestampを使っているため)

ここで「いやいや、「1.」の比較チェックは、それを防ぐためにあるんでしょ?」と気づいた方は、非常に勘がいいですね。

その通りです。でも、実はそれもDevの罠でした。「1.」はプレイヤーの目を誤魔化す(悪意あるコードでない)と思わせるトラップでした。

実は、古いSolidityのコンパイラでは、その変数の最大値を入力し、更に値を足した場合に最小値に戻る性質があります。Devはこの性質を悪用しました。

まずはGenPoolを準備し、資金を集めます。頃合いを見計らって、DevはsetGenStartTime(uint256の最大値近く)を実行しました。結果、poolEndTimeの値が限界突破してしまったため、Unix Timeが生まれた頃に戻ってしまったのです。

あとはgovernanceRecoverUnsupported()を実行して全ての資金を抜いて逃亡。

9.Tomb Forkのプールの仕組みを悪用

これは、かなり手が混んでいます。この攻撃が始めに観測されたのはPanda Financeでした。

まず、Devは通常通りGen Pool Contractをデプロイしました。

次に、Devは複数のPoolをGen Pool Contract内に作りました。

次に、Devは自身の資金をPoolにDepositしました。敢えて例としてDevAが$100をPool1にDepositしたとします。

この時点でコントラクトには「Pool1:DevA:+$100」みたいな台帳ができています。

この後に、DevはgovernanceRecoverUnsupported()で$100を抜き出しました。

governanceRecoverUnsupported()は引数にユーザ名(ウォレットアドレス)は取りません。IERC20トークン名・数量・送信先のウォレットアドレスだけです。これは、governanceRecoverUnsupported()は、Pool全体のトークン合計数から除算するためです。

つまり、governanceRecoverUnsupported()がいくら使用されても、台帳上は「Pool1:DevA:+$100」が残ったままです。

あとは、通常通りGen Poolを開始させました。そしてプレイヤー達がどんどんDepositした後に、自分がDepositした(既にgovernanceRecoverUnsupported()で抜いた)額を好きな時に取り出したのでした。

このラグが発覚した時は、Tomb Forkに詳しいエンジニアも攻撃手法がわからず、この為だけにプライベートチャネルを作成してトランザクションの履歴を一つづつ確認しながらようやく判明しました。Gen Pool コントラクトのトランザクションにgovernanceRecoverUnsupported()の形跡があったら簡単に見つかったのですが、実際にgovernanceRecoverUnsupported()を実行したのは予めsetOperator()でOperatorを変更した先のProxyコントラクトであったり、いろんな形跡が巧妙に隠されていたり、何よりもGen Poolコントラクト自体に悪意あるコードの形跡が少なく、、、。

最も手がかりになったのはinitialize()の存在です。TombForkのコントラクトにはinitialize()という関数で初期値を設定するものもあるのですが、通常のGen Poolコントラクトにはinitialize()は存在しません。デプロイ時のコンストラクタで設定するからです。

しかし、Panda FinanceのGen Poolにはinitialize()が存在していました。これには理由がありまして、通常のGen Poolコントラクトの場合は、デプロイ時のコンストラクタでpoolEndTimeが設定されている為、自ずとgovernanceRecoverUnsupported()のチェックに引っかかって事前に資金が抜けないからです。

後のVader Finance(0xF089a76c87Deaf3f5c8c3a1656A2269929Bf22C0)も同様の手口の攻撃でした。

    function initialize(uint256 _poolStartTime) external onlyOperator {
        require(!initialized, 'already intialized');
        require(block.timestamp < _poolStartTime, "late");
        initialized = true;
        poolStartTime = _poolStartTime;
        poolEndTime = poolStartTime + runningTime;
    }

通常は、上記コードはGen Poolに存在しません。

10.悪意あるコントラクトにすり替え(フロントエンド)

そもそもTombForkを利用するプレイヤーは、どのようにサービスを利用するでしょうか。

フロントエンド(Webサイト)を利用してですよね。直コンで使ってる人はほとんどいません。

例えばWebサイト経由でGen PoolにDepositすると、Webサイトが裏でGen Poolコントラクトと連携して、プレイヤーの資金をDepositします。

この攻撃のシナリオでは、Devは2つのGen Poolコントラクトを用意します

  • コントラクトA:問題のないGen Poolコントラクト
  • コントラクトB:悪意あるコードを含めたGen Poolコントラクト

Gen Pool開始前は、フロントエンドのアクセス先をコントラクトAにしておきます。そしてRug Docなどの監査サービスにコントラクトAをレビュー対象として提出します。当然「問題なし」の判定が返ってきます。WhatTheForkなどに登録して、有志がコントラクトをチェックしても悪意ある形跡は見つかりません。プロジェクトのDocにもコントラクトAを登録します。

そして、Gen Poolが開始する直前に、フロントエンドのアクセス先をコントラクトBに設定します。裏の連携など何も意識しないプレイヤーは、フロントエンドでDepositするのですが、そのアクセス先はコントラクトBです。あとは、DevがコントラクトBの悪意あるコードを実行して資金を抜く。

最近だとKarma Financeがこの攻撃を利用しました。彼らがDocに記載したコントラクトアドレスは0x25D2C72398D540F98FB3E788f845a70eD7CBF6B0でしたが、実際にフロントエンドがアクセスしているコントラクトアドレスは0x218c2F2Ae74296418b01c710b5F8f7d1828B4efC。Verifyもされていない、内部コードが見えない状態であり、これをDevにぶつけたところ、チャンネル自体が消失しました。

対策

TombForkに対する攻撃について、現時点で観測されたものについては書き切った気がします。改めて見直してもDevによる攻撃が多いですね。

TombFork自体、Devに圧倒的に有利なゲームなので、それを理解しておいた方が良いと思います。

さて、では対策です。まず大前提として「100%有効な対策はない」ことを頭に叩き込みましょう。つまり、ラグを絶対に許せないならTombForkはやるな、ってことです。

私は、TombForkは「ラグあり、Devもプレイヤーの一部」と考えています。

それを踏まえて、一般プレイヤーでも対策がしやすい順に対策法を並べてみました。

全てなくなっても良い金額でプレイする

言わずもがな

LP内の資金を常にチェックする

実は、これが最も重要だと思っています。ここでの「LP」とはPeg TokenのLPだと考えてください。

Gen Pool開始時にLP内資金が少なければ危険

LP内資金が$50とか$100とか、極端に少ない場合はDevのやる気が見えないと考えます。ラグする為の可能性が非常に高い。

プロジェクト中のLP減少も危険

プロジェクト中の極端なトークン価格の下落、LPの減少が行ったら、それは危険なサインです。

前述の通り、Devの主な収入源は、BRによるDev/DAO Feeです。プロジェクトが縮小すると、Devのやる気がなくなります。結果的に「ラグった方が儲かりそう・・・」という心理状況になって、ラグを発動させる可能性が高くなる(Devの保有トークンのダンプも含め)。

BRの利用は危険

個人的にはよほどの良条件でない限り、BRは利用しないです。BRは数時間のロックアップ期間が発生するので、その間にラグられたら手も足も出ません。

コミュニティがTelegramだけは危険

TelegramとDiscordの2サービスを準備しているもの以外は危険です。「両方準備するのは大変だから」とか「Modの数が足りていない」とかは言い訳で、Telegramは匿名性が高く逃げやすいというのが殆どの場合の理由。

RugDoc reviewedは自分での確認が必要

「RugDocでReview済」と言っても、本当にレビュー済か確認が必要です。また、プロジェクトによってはGen Poolコントラクトだけレビュー対象にしているケースも多々あります。

実際にRugDocでReviewされているプロジェクトでもラグしたケースは沢山あります。最近だとStarburst Financeもそうです。

コミュニティに入って情報集め

参加するTombForkのプロジェクトのコミュニティ参加は必須です。雲行きが怪しくなるのを肌で感じる事ができますし、有志がDevに問い詰めることもあります。で、そのユーザがいきなり消えたら即Withdraw。

Renounceの確認

RenounceとはOperatorの放棄です。これを行うことで管理者しか実行できない関数について、Devも利用できなくなります。

個人的にはGen PoolのRenounceは必須だと思っています。ただ、それ以外のコントラクトについては、追加設定ができなくなるので微妙ですね。セキュリティとユーザビリティは表裏一体。

ちなみにRenounceされてるから100%大丈夫ってわけではありません。あくまでも「少し安全」程度に考えておいてください。

プロジェクトのデザインがしょぼかったら危険

冗談ではなく非常に重要な要素です。

プロジェクトのデザインに力を入れていない場合、高確率でラグります。

というのも、新しいプロジェクトを立ち上げる時に最もコスト(お金・時間)がかかるのはデザインだからです。それ以外は半日くらいで作れます。

つまり、デザインに力を入れていないプロジェクトは「お手軽ラグプロジェクト」の可能性が高い。

ちなみに、これを逆手にとって、めちゃめちゃ力が入っているデザインのプロジェクトが、実はラグだったってのもあるので注意が必要。

キャラクター名のプロジェクトは危険

Vader FinanceとかMario FinanceとかSonic Financeとか、キャラクター名で知名度を上げようとしているプロジェクトは「お手軽ラグプロジェクト」の可能性が高い。しかも、ラグじゃなくても成功しているプロジェクトをみた事がない。

コードをDiffする

ここからは少しスキルがないとやりづらいと思います。

コードが読めるのならば、Tomb Finance オリジナルのコントラクトと、プロジェクトのコントラクトをDiffしましょう。

Legitなプロジェクトであれば、関数や変数の使い方が同じなはずです。変数名などはプロジェクトのトークン名に変わっていますが、基本的なところは同じであるべきなのです。

オリジナルのコードと比較して、関数が増えていたり変数が増えていたりしたら要注意です。また、変数の値が変わっていても要注意。

いいですか、本来であればオリジナルのコードを変える必要がないのです。コードは人間の手を加えなければ変わりません。つまり、変わってるってことは「Devが何らかの意思で変えている」ってことです。

特定のコードの箇所が気になったら、コミュニティで問いかけてみるものアリだと思います。

governanceRecoverUnsupported()に注意する

コードを見るときは特にgovernanceRecoverUnsupported()に注意しましょう。もし、このコードに手を加えられていたら、ラグの可能性を疑うべきです。そもそも、本来であったら手を加える必要がない関数なので。

Approve先のコントラクトに注意する

主に攻撃方法「10」対策です。

自分の資金をDepositするとき、まずは「Approve」をしますよね。あれって「自分のウォレットの資金を、該当のコントラクトに転送することの許可」をしてるんです。(厳密にはもう少し細かいのですが、乱暴に言うとこんな感じ)

なので、Approve時に表示されているコントラクトアドレスは、Depositしようとしているコントラクトのアドレスのはずです。

もし、そのアドレスがDocに書いているものと違ったら、それは99%ラグろうとしています。

終わりに

この記事では、まずは「攻撃者の分類」を行い、「具体的な攻撃手法」を説明し、最後に「対策方法」について解説しました。これはIT全般に言えることですが、完璧な対策は存在しません。新しい攻撃が日々生まれているからです。新しい攻撃方法が見つかったら随時アップデートする予定です。

TombForkはマネーゲームです。Reward Poolに突っ込んだ資産を誰が効率よく手に入れるかのゼロサムゲームです。

Devもプレイヤーです。味方ではありません。それを常に念頭に置いておきましょう。

コメント

タイトルとURLをコピーしました