今回は少し前に起こった『StableMagnet』というプロトコルのラグプルについて解説していきます。
この事件を調べるにあたってTwitterや海外のニュースサイトを読み込んだのですが、利用している人が少なかったということもあり、それによって事件の詳細が少ないです。
加えてサイトが飛んでしまって状況がよくわからないままラグられている人が多い印象だったので、正確な情報を終えていないため一部が事実と異なる可能性もあります。
ただ、今回の事件のコード情報が残っているので、その情報をもとに「こういうことができるよね」という話をしたいと思っています。
今後のラグプル対策や自分の資金を守るための知識としてぜひ最後まで読んでもらえたらと思います。
今回のラグプル事件『StableMagnet』の経緯

こちらのBSCニュースのウェブサイトを翻訳しながら解説します。

今回2200万ドル(日本円で22億円)をラグプルで抜いたということが記載されています。
正確な被害金額は調査中でまだよくわかっていないようですが、おそらく2700万ドルくらいに昇るんじゃないかと考えられています。

続いて「StableMagnetのラグプルは新しい攻撃法のおかげです」と記載されていますが、これは今までのラグプルの攻撃法と違うところがあり、明らかに高度化しているという意味になります。
これまでのラグプルだと、サイトを飛ばして引き起こす方法や、ハッキングのポイントをコントラクトの中に仕込んで引き起こす方法が主流だったのですが、今回のラグプルの原因はどちらの方法でもなかったということです。

続いて「Rugdocが引用した問題は…」とありますが、そもそもRugdoca(ラグドック)が何かというと、ラグリスクなどの情報を一覧化して出してくれるプロジェクトのことをいいます。
なのでここは「Rugdocが挙げた(指摘した)問題は、EtherscanもBscScanもリンクされたライブラリ(依存情報)のソースコードを検証しなかったことにより、攻撃者たちがソースコードに引用されているものとは異なるコードライブラリを展開することができた」という意味になります。

「攻撃者たちがソースコードに引用されているものとは異なるコードライブラリを展開することができた」というのはどういうことかというと、画像は実際のトランザクションのページの一例ですが、トランザクションを見てみると、StableMagnetSwapのメインのプールに預けていた人の資金が、結果的に誰だかわからない人のウォレットに送られていたことがわかります。

ちなみにこの3つの合計が大体2200万ドルになります。
(上から順に大体の数字で800万ドル、700万ドル、700万ドル)
詳細な概要
冒頭でも話しましたが、今回この事件について調べるにあたってTwitterや海外のニュースサイトを読み込んだのですが、事件の詳細が少なく、加えてサイトが飛んでしまって原因がよくわからないままの印象でした。
[コントラクト]
StableMagnet: https://bscscan.com/address/0xb89e9365cb5bacfcf4a4b0386dfad45c3b4d3258
Dopple(修正版):
https://bscscan.com/address/0xd108bfe791d7d8bd117b750227de89d0f7056b8e#code
[引き抜きトランザクション]
https://bscscan.com/tx/0xf0ba46c8a20e1e75ad382e42c509bf71393e1b3b90326165c747a5d3cc5d967C#eventlog
ただ、今回の事件のコード情報が残っているので、その情報をもとに「これが事件の原因だね」「こういうことができるよね」という話を今からしていこうと思います。
1. 使っているライブラリが独自のものだった

「StableMagnetのコントラクト」のCodeを見てみると、コントラクトの名前の欄に「Swap」と記載されていることがわかります。また「File 1 of 7 : Swap.sol」と記載されていますが「これがSwapファイルのメインの機能ですよ」という表示になります。
そして四角の赤枠の部分には「Contract Swap…..」と書かれていますが、この赤枠部分が機能のメイン部分になります。要はこの赤枠部分がStableTableのコントラクトの全てになります。

続いて、他のコード部分を見てみると「import」と連なって書かれていますが、この部分は「Swap」の中にある小さな各機能を呼び出している状態になります。
例えば赤枠の下から2番目のimportの後にSwapUtilsと書かれている部分がありますが、イメージで言うと、この「Swap」という機能は「SwapUtils」といった様々な小さな機能(パーツ)が組み合わさって(呼び出されて)作られているといった感じになります。

さらに下にスクロールしてみると、今度はSwapUtilsを構成している各機能がimportの部分に書かれています。(LPTokenやMathUtilsなど)
ちなみに、SwapUtilsというものはいろんなコントラクトで使われているので、基本的にはどのコントラクトでもコピーして使われています。
そしてイメージとしてはこの「Swap」というものが車だとしたら、ドアを構成する部分が「SwapUtils」で、さらにその「SwapUtils」というドアを構成しているものが「LPTokenやMthUtils」などのネジや鉄板にあたる。ということになります。

なので、このコントラクトのページを見れば、どうのように機能が構成されているのか全て分かると言えます。
そして話を事件概要に戻すと、今回問題になったのはSwapUtilsの部分で、下の画像を見るとSwapUtilsのアドレスの一部を攻撃者が独自で作った全くの別物をimport(呼び出し)して今回のラグプルが起こったことがわかりました。
ぱっと見、名前も一緒で構造も似ていておかしいと思う人がいない、そもそもコードを全部読み込む人なんていないということでここが穴となり、詳しい人なら簡単にラグプルを引き起こせる状態になっていました。
2. Scanにはコードの監査的要素は無いためライブラリが別物でも認証していた
事件の概要や原因について解説してきましたが、やはり監査的要素がないのが決定的でした。
今後は、BscScanやEtherScanに頑張って欲しいなと思いますが、この監査の部分はどうしても人的要素が入るので難しいかな〜とも感じています。
おそらく自動で認証させるくらいしかできないので、Auditに頑張ってもらうべきかなのかなと思っています。
原因となったSwapUtilsをより詳しく解説
ここからはさらに詳しく解説していきたいので、StableMagnetのコントラクト(SwapUtilsのコード部分)と、事件後にDoppleFinanceが最近新しく修正したコントラクト(SwapUtilsのコード部分)を比較しながら解説していきたいと思います。
StableMagnet: https://bscscan.com/address/0xb89e9365cb5bacfcf4a4b0386dfad45c3b4d3258
Dopple(修正版):
https://bscscan.com/address/0xd108bfe791d7d8bd117b750227de89d0f7056b8e#code

おそらくこの機能を使ったことがない人が多いと思いますが、上にリンクを貼ったDoppleFinanceのページに飛んで「More option」をタップして「compare」をタップするとコントラクトの比較ができます。

そして右側の検索窓にStableMagnetのアドレスを貼り付けて「Lookup」をタップすると、それぞれのコントラクトが比較できるようになります。



次にDoppleFinanceのSwapUtilsと、StableMagnetのSwapUtilsを比較したいので、それぞれの「SwapUtils」にチェックを入れて「Compare Difference」をタップします。

するとこのような表示がされます。左側がDoppleのコントラクトで、右側がStableMagnetのラグが起こった悪いコントラクトになります。

続いて、先ほどの画面をズラーっと下にスクロールしていくと、途中で色が変わった部分が出てきます。
左のDoppleは825〜836〜836までがオレンジ色で長めに記載されていますが、これはただStableMagnet側の「setBalances(self…..」の部分という機能の部分を展開しただけなので、長くなっているだけです。

問題なのは、StableMagnetの829行目です。Doppleの837行目とどこが違うかというとsafeTransferの右側にある(msg.sender, dy)と記載されている部分になります。これはmessage senderなのですが、「このコントラクトを実行した人」という意味になります。
右側のStableMagnetのsafeTransferの後ろは(to, dy)となっています。2つを比べると「to」と「msg.sender」が違うことがわかりますが、突き詰めるとこの違いがラグの原因になります。

他にも、下にスクロールして探してみるとMintの「to」と「msg.sender」の部分が違うことがわかります。


他にも何箇所か「to」と「msg.sender」となっている箇所があります。
2つを比較をしてみることで、Doppleが「msg.sender」に修正したところが怪しいな〜と目星がつきますよね。そしてここからさらにどう怪しいのか?どういう仕組みでラグが起こったか?攻撃者はどうんなふうに穴をついたのか?詳しく見ていきます。

ということでまずはStableMagnetのSwaputilsを実際に見ていこうと思います。

まず829行目の青文字のsafeTransferのところですが、すぐ後ろにtoがついています。これは、先ほども見た通りSwapというトランザクションを発行してラグが起こっていました。(トークンを転送していた)

続いて、797行目にもaddressの後ろにtoがついています。
SwapUtilsのまとめ
本来Swapというものは仕組み通り考えれば、例えば自分がBUSDを入れてUSDTをもらうという流れなので「to」を入れる必要はありません。なぜならSwapの元に返せばいいだけだからです。ただ逆を返せばSwapした先に全く違う人を設定することができてしまいます。
要は、自分がBUSDをUSDTに交換した後に、toに他のアドレスを入力しておけば全く違う人にそのトークンを送ることができてしまいます。
なので攻撃者はAddresstoに自分たちのウォレットを設定してSwapという処理を行い結果的にTransferで全て抜き取ったということになります。
これに加えて、今回ラグった後にTwitterやテレグラムなどで「LPを解体したら何もウォレットに反映されませんでした」という報告がちょこちょこ上がっていたのですが、おそらくこれも原因は今話したことだと思います。
簡単に言い換えれば、とりあえずLPは消えずにあり、そしてLP解体もできた。とにかく被害を最小限に抑えるために早く資金を抜こうとLPを解体してみたら全てが消え去った。という感じです。コードを確認してみるとRemoveliquidityのところにあるAddressの後にtoがついていたので、LPを解体したら丸ごと持っていかれるようになっていました。
このことから攻撃者はラグが起こった後のユーザーたちの反応まであらかじめ考察した上で、toの後に引き抜きようのあどれを設定して資金を引っ張っていきました。
まとめ
今回のStableMagnetのラグに関してはあまり正確な情報がなく、コントラクトを見ながら事件の概要と詳細を解説していきました。
ひょっとしたら、元々ユーザーが減っていてそれにより情報的価値もなくなり、インプレッションやエンゲージメントが取れないなどの理由でメディアが取り上げなかったかもしれません。
なので、正確な情報かどうかは正直わからないという感じになっています。とりあえず今回は自分自身でコントラクトを見て調べた結果、今回の理由でラグが起きたのではと思っています。
文章だとわかりづらいという方は、この記事と全く同じ内容のYoutube動画もアップしているのでそちらも参考にしていただければと思います。
【3MIKAN Youtube動画:【DeFi】22億円持ち逃げStableMagnetのラグプル事件を解説します】
最後まで読んでいただきありがとうございました。