インシデントレポート: CVE-2024-YIKES
(nesbitt.io)- CVE-2024-YIKES は、JavaScript 依存関係の侵害が Rust・Python のサプライチェーンへ拡大したインシデント
left-justifyフィッシングにより.npmrc、.pypirc、Cargo・Gem の認証情報が流出vulpine-lz4の悪意あるbuild.rsが CI ホスト上でシェルスクリプトをダウンロードして実行snekpack3.7.0 のマルウェアが約 420万台 に拡散し、SSH キーとリバースシェルを追加- cryptobro-9000 ワームが偶然
snekpackを 3.7.1 に更新し、マルウェアが除去される
事件の概要
- CVE-2024-YIKES は、JavaScript エコシステムの侵害された依存関係が認証情報の窃取につながり、Rust 圧縮ライブラリへのサプライチェーン攻撃と Python ビルドツールによるマルウェア配布へと波及したセキュリティインシデント
- インシデントは 03:47 UTC に受理され、ステータスは「偶然解決」、深刻度は「Critical → Catastrophic → Somehow Fine」へ変更された
- 継続時間は 73時間 で、影響を受けたシステムは「Yes」のまま残された
- 侵害されたパッケージとツールチェーンは
left-justify、vulpine-lz4、snekpackと連なり、約 400万人の開発者 にマルウェアが配布された - 最終的に、別系統の暗号資産マイニングワーム
cryptobro-9000が感染マシン上で更新を実行したことでsnekpackが正常版へ上がり、マルウェアは偶然除去された
インシデントの経緯
-
1日目: JavaScript パッケージで認証情報の窃取が発生
- 03:14 UTC、
left-justifyメンテナーの Marcus Chen は、交通カード、古いノートPC、そして「Kubernetes が吐き出した重要そうな何か」を盗まれたと Twitter に投稿したが、パッケージのセキュリティ問題にはすぐ結びつかなかった - 09:22 UTC、Chen は nmp レジストリへログインしようとしてハードウェア 2FA キーがないことに気づき、Google 検索結果の最上部に出た AI Overview が 6時間前に登録されたフィッシングサイト
yubikey-official-store.netへ誘導した - 09:31 UTC、Chen はそのフィッシングサイトに nmp の認証情報を入力し、サイトは購入への謝意を述べて 3〜5 営業日以内の配送を約束した
- 11:00 UTC、
[email protected]が「performance improvements」という変更ログ付きで配布された - このパッケージにはインストール後実行スクリプトが含まれており、
.npmrc、.pypirc、~/.cargo/credentials、~/.gem/credentialsを攻撃者の選んだサーバへ送信した - 13:15 UTC、
left-justifyに「why is your SDK exfiltrating my .npmrc」というサポートチケットが作成されたが、「low priority - user environment issue」と分類され、その後 14日間アクティビティがなかったため自動クローズされた
- 03:14 UTC、
-
1日目: Rust ライブラリへサプライチェーン攻撃が拡大
- 流出した認証情報の中には、Rust ライブラリ
vulpine-lz4メンテナーの認証情報も含まれていた vulpine-lz4は「blazingly fast Firefox-themed LZ4 decompression」のためのライブラリで、GitHub スターは 12 個しかないが、cargo自体の推移的依存関係だった- 22:00 UTC、
vulpine-lz40.4.1 が配布され、コミットメッセージは「fix: resolve edge case in streaming decompression」だった - 実際の変更は
build.rsスクリプトを追加し、ホスト名に「build」「ci」「action」「jenkins」「travis」または「karen」が含まれていればシェルスクリプトをダウンロードして実行するものだった
- 流出した認証情報の中には、Rust ライブラリ
-
2日目: 検知と対応の失敗
- 08:15 UTC、セキュリティ研究者 Karen Oyelaran は、自身の個人用ノートPCでペイロードが動作したあとに悪意あるコミットを発見した
- Karen Oyelaran は「your build script downloads and runs a shell script from the internet?」という Issue を開いたが、返答はなかった
- 正規のメンテナーは EuroMillions で €2.3 million を当て、ポルトガルでヤギ牧場を調べていた
- 10:00 UTC、Fortune 500 の
snekpack顧客企業の VP of Engineering は、「Is YOUR Company Affected by left-justify?」という LinkedIn 投稿でこのインシデントを知り、なぜ自分がもっと早く含まれていなかったのかを知りたがったが、実際にはすでにもっと早く含まれていた - 10:47 UTC、
#incident-responseSlack チャンネルは一時的に、「compromised」のアメリカ式つづりとしてzを使うべきかどうかを巡る 45 件のメッセージスレッドへ脱線した
-
2日目: Python ビルドツール
snekpackが感染- 12:33 UTC、シェルスクリプトは
snekpackの CI パイプラインを特定の標的として狙った snekpackは、名前に「data」を含む PyPI パッケージの 60% が使用している Python ビルドツールだったsnekpackは「Rust is memory safe」という理由でvulpine-lz4をベンダー取り込みしていた- 18:00 UTC、
snekpack3.7.0 がリリースされ、マルウェアが世界中の開発者マシンへインストールされ始めた - マルウェアは
~/.ssh/authorized_keysに SSH キーを追加し、火曜日にのみ有効化されるリバースシェルを仕込み、ユーザーのデフォルトシェルをfishに変更した - デフォルトシェルを
fishに変える動作はバグと見なされた - 19:45 UTC、別のセキュリティ研究者が「I found a supply chain attack and reported it to all the wrong people」という 14,000 語のブログ記事を公開し、「in this economy?」という文句を 7 回含めた
- 12:33 UTC、シェルスクリプトは
-
3日目: 偶然のパッチとインシデント終息
- 01:17 UTC、オークランドのジュニア開発者が別件をデバッグ中にマルウェアを発見し、
snekpackでベンダー取り込みされたvulpine-lz4を差し戻す PR を作成した - その PR には 2 件の承認が必要だったが、承認者 2 人とも眠っていた
- 02:00 UTC、
left-justifyメンテナーはyubikey-official-store.netから YubiKey を受け取ったが、それは README に「lol」と書かれた 4 ドルの USB ドライブだった - 06:12 UTC、別系統の暗号資産マイニングワーム
cryptobro-9000がjsonify-extreme脆弱性を通じて拡散し始めた jsonify-extremeは「makes JSON even more JSON, now with nested comment support」というパッケージとして説明されていたcryptobro-9000のペイロード自体は特筆すべきものではなかったが、将来の攻撃面を広げるため、感染マシン上でnpm updateとpip install --upgradeを実行する伝播方式を含んでいた- 06:14 UTC、
cryptobro-9000は偶然snekpackを 3.7.1 にアップグレードした snekpack3.7.1 は混乱した共同メンテナーが配布した正規リリースで、ベンダー取り込みされたvulpine-lz4を前のバージョンに戻していた- 06:15 UTC、火曜日のリバースシェルが有効化されたが、コマンド&コントロールサーバは
cryptobro-9000に侵害されており応答できなかった - 09:00 UTC、
snekpackメンテナーは 4 文のセキュリティアドバイザリを公開し、「out of an abundance of caution」と「no evidence of active exploitation」という文言を含めた - 「no evidence of active exploitation」は、証拠を探していなかったため技術的には真とされた
- 11:30 UTC、ある開発者が「I updated all my dependencies and now my terminal is in fish???」とツイートし、47,000 件のいいねを得た
- 14:00 UTC、
vulpine-lz4の侵害された認証情報が差し替えられた - 正規のメンテナーは新しいヤギ牧場でメールを受け取り、「そのリポジトリは 2 年間触っていない」と「Cargo の 2FA は任意だと思っていた」と返答した
- 15:22 UTC、インシデントの解決が宣言され、振り返りミーティングは予定されたのち 3 回リスケされた
- 01:17 UTC、オークランドのジュニア開発者が別件をデバッグ中にマルウェアを発見し、
CVE 割り当てと被害規模
- 6週目 に CVE-2024-YIKES が正式に割り当てられた
- アドバイザリは、MITRE と GitHub Security Advisories が CWE 分類を巡って議論している間、エンバーゴ状態のままだった
- CVE が公開されるまでに、すでに Medium 記事 3 本と DEF CON 発表がこのインシデントを詳しく扱っていた
- 総被害は不明のままとされた
- 侵害されたマシン数は 420万台 と推定される
- 暗号資産ワームが救ったマシン数も 420万台 と推定される
- 正味のセキュリティ態勢の変化は「不便さ」とされた
根本原因と寄与要因
-
根本原因
- Kubernetes という名前の犬 が YubiKey を食べたことが根本原因として扱われた
-
寄与要因
- nmp レジストリは、週次ダウンロードが 1,000 万未満のパッケージについて、依然としてパスワードのみの認証を許可していた
- Google AI Overviews が、本来存在してはならない URL を自信満々に案内した
- Rust エコシステムの「小さなクレート」哲学が npm エコシステムでなぞられた結果、GitHub スター 3 個の
is-even-number-rsのようなパッケージが重要インフラの 4 段階先の推移的依存関係に入り得た - Python ビルドツールは「性能」を理由に Rust ライブラリをベンダー取り込みしたあと更新しなかった
- Dependabot は CI 通過後に PR を自動マージし、CI はマルウェアが
volkswagenをインストールしたため通過した - 暗号資産ワームは、たいていのスタートアップより優れた CI/CD 衛生を備えていた
- 単独の責任者はいないが、Dependabot PR はその金曜日が最終出勤日だった契約社員によって承認された
- インシデント当日は火曜日だった
改善策と残された選択肢
- 成果物署名の実装は Q3 2022 インシデントのアクションアイテムだったが、依然としてバックログにある
- 必須 2FA の実装はすでに要求されていたが、役に立たなかった
- 推移的依存関係の監査は対象が 847 個 あるため取り消し線扱いとなった
- すべての依存関係バージョンを固定するとセキュリティパッチを受け取れない
- 依存関係バージョンを固定しなければサプライチェーン攻撃が可能になる
- Rust で書き直すという選択肢は
vulpine-lz4を指しており、取り消し線扱いとなった - 残された対策としては、善意のワームに期待するか、ヤギ牧場への転職を検討するかしかない
顧客への影響と組織対応
- 一部の顧客は「最適ではないセキュリティ上の結果」を経験した可能性がある
- 影響を受けたステークホルダーに状況の可視性を提供するため、先回りして連絡を行った
- 顧客信頼は「north star」として維持された
- セキュリティ態勢を見直すためのクロスファンクショナルなワーキンググループが作られたが、まだ会議はしていない
- 法務レビューの後、
fishシェルはマルウェアではなく、時々そう感じられるだけだという文言が追加された - このインシデントレポートは、その四半期で 3 本目のインシデントレポートだった
- セキュリティチームの増員要請は Q1 2023 からバックログに残っている
謝辞
- Karen Oyelaran は、ホスト名が正規表現に一致したことで問題を発見した
- オークランドのジュニア開発者が出した PR は、インシデントがすでに解決してから 4 時間後に承認された
- 一部のセキュリティ研究者は先に問題を見つけたが、間違った相手全員に報告した
cryptobro-9000の作者は実名公開を望まなかったが、自分の SoundCloud に触れてほしいと依頼した- Kubernetes という犬はコメントを拒否した
- セキュリティチームは、あらゆる状況にもかかわらずこのレポートの SLA を満たした
1件のコメント
Hacker Newsのコメント
念のため言っておくと、これはサプライチェーン事故を扱った、かなりよく書けたフィクション
流し読みしたときは本物だと思ってかなり不安になり、そのせいで余計に集中して読んでしまった :)
nmp引用文の「GitHubスター12個のvulpine-lz4がcargo自体の推移的依存関係」というくだりが気になって、cargoビルドに紛れ込めて、しかもすでに
build.rsがあるので目立ちにくいクレートをざっと挙げてみた:flate2,tar,curl-sys,libgit2-sys,openssl-sys,libsqlite3-sys,blake3,libz-sys,zstd-sys,ccおまけに
xz2の権限を取れればrustupも汚染できるそれでも少なくとも
Cargo.lockは追跡している-sysクレートはただのバインディングなので、そこで別のことをしていたらかなり怪しく見える残りは
alexcrichtonのようなRustメンテナーやrustlang自体が所有しているものだと思うシニカルになりやすいのは、問題も解決策も後から見るとあまりに自明に見えるから
でも長いあいだ、あるいは今でも、ハッカー文化の信条はmove fast and break thingsだった
npmのようなサプライチェーンシステムの明白な問題を直そうという流れが強まっているのは良いことだが、エージェント型開発がかなりの部分で引き起こす新しいセキュリティ問題の時代に入っていくのが心配だMythos/Glasswingが触るほぼすべてのものに脆弱性を見いだすという話だけではなく、私たちがソフトウェアを作り、依存関係を引き込み、複雑なシステムに対する人間の思考モデルを失っていくやり方そのものが、人間がきちんと理解していない継ぎはぎのソフトウェアやインフラを大量に生みそうに思える
数年後に今を振り返って、どうして自分たちはこんなに無邪気だったのか、複雑なシステムをAIで作り直そうという形で問題を解こうとせずにAI開発のロングテールに十分備えなかったことを後悔しないといいのだが
それでも記事は面白かった
Fish愛好家として、この一文には攻撃されつつも理解されている感じがした: 「fishシェルはマルウェアではなく、たまにそう感じられるだけだという点を明確にしてほしい」
シェルとは別に、「セキュリティチームの増員要請は2023年Q1からバックログにあった」というくだりもあまりに見覚えがある
apt-getやdnfでfigletをインストールしてから、/etc/motdの内容を巨大なASCIIアートのall your base are belong to usで上書きすることもできるleft-justifyのメンテナーが
yubikey-official-store.netからYubiKeyを受け取り、その正体がREADMEに「lol」と書かれた4ドルのUSBドライブだったというくだりで本当に大笑いした完全にトロールだ
フィッシングサイトから届いたUSB機器を差し込む行為自体がまた別の攻撃ベクトルだという点が気に入った
実際のSCPではないけれど、最近読んだ中でいちばんSCPっぽい文章だった
Karenのくだりで大笑いした :D ;)
昔クラスメートのプロジェクトをレビューしたときにもらった
makeベースのビルドスクリプトを思い出したが、ホスト名にbpavukが含まれていると自分のホームフォルダでrm -rfを実行しようとしていたそれが中学1年のときだった!!
サプライチェーン事故は本当に厄介で、もっと改善しないといけない
個人的にはRustでは財団がいくつかの中核クレートを支援し、Rust言語本体と同じ監査プロセスを通すようにして、サプライチェーン上の脆弱性を減らすためにプロジェクトへ資金を出す方向を支持する
cratesやnpmのようなシステムをなくすのが正解だとは思わない。cratesとnpmは多くの開発者に大きな助けになっているcratesもrustsecを取り込もうとする努力はしてきたが、それとは別に、コミュニティが小さな依存関係を大量に持つやり方から、tokioのようなより少数の大きな依存関係へ移っていくといいと思うcrates.ioで最も人気のあるクレートのかなりの部分は、すでにRust組織が提供している第一級クレートだRustのクレートグラフを心配するとき、この点はしばしば見落とされる
crates.ioのトップページにあるダウンロード上位10件を見ると、Rust組織やRustコアメンテナーが作ったものではないのはbase64クレートだけだnpmとnmpの両方が必要なのか「正式メンテナーはEuroMillionsで230万ユーロを当てて、ポルトガルでヤギ飼育を調べている最中」で、「根本原因: Kubernetsという犬がYubiKeyを食べた」というのだから
ああ、そうか。古典的な有名攻撃にやられるなんて無責任だ
いわゆる「宝くじの当選金で誰かを極度に気もそぞろにさせ、別の誰かのペットにはドングルがたまらなくおいしそうに見えるようにする」手口のことだ
みんないつになったら学ぶんだろう
npmやpipを使わず、推奨されるやり方のcurl ... | bashだけを使っていてよかったcurl | sudo bashだろ素人め