目に見えるのに見えない悪意あるNode.jsパッケージ:ニッチな設定と不可視文字が交わるとき
Aviad Hahami
2022年2月28日
0 分で読めますここ数年、作成され実際に利用されるオープンソースパッケージの数が大幅に増加しています。今ではどのエコシステムにもパッケージマネージャーがあり、そのほとんどに知られざる機能や設定が存在します。
開発者が増え続ける数のパッケージをインストールする一方で、攻撃者もパッケージの攻撃対象領域に関心を寄せています。そして、巧妙に隠された悪意あるパッケージを作り出すための道のりが始まります。
この記事では、Node.jsエコシステムとyarnおよびnpmパッケージマネージャーを使った攻撃に焦点を当てます。ただし、同様の問題がないか他のエコシステムも調査し、認識を高め、コミュニティ全体のセキュリティ向上につなげるための「行動喚起」として捉えてください。
それでは、さっそく始めましょう。
パート1:ニッチな設定
先日、ある研究者仲間から、あまり知られていないものの重大なセキュリティ上の影響を及ぼしかねないnpmの興味深い設定オプションについて聞きました(後にyarnにも同様のものがあると分かりました)。これらの設定オプションを使うと、プロジェクトディレクトリ内で実行するバイナリをパッケージマネージャーに指定できます。そう、どのバイナリを実行するかです。
設定オプションには、.yarnrcファイルのyarnPathと、.npmrcファイルのgit、shell、script-shellなどがあります。以下の攻撃手法を理解するために、今回の発見について書かれたCider SecurityのRotemによるブログ記事をぜひお読みください。
「今クローン/プルしたファイルが、なぜそのまま適用されるのか」と疑問に思う人もいるでしょう。答えは、npm/yarnがそのように動作するからです。パッケージマネージャーのプロジェクト処理フローでは、.rcファイルを階層的に検索します。最初に現在のプロジェクトディレクトリ、次にユーザーディレクトリ、最後にルートディレクトリが検索されます(詳しくはNPMの設定ドキュメントをご覧ください)。
以上のオプションを使えば、次の.yarnrcファイルを設定として利用し、半ば隠された悪意あるパッケージを(リポジトリ/tarball内に)作成できます(`npm install`などを実行しても`.rc`ファイルはダウンロードされないためです)。
(注:この例では.yarnrcファイルを使っていますが、適切な設定オプションを指定した同様の.npmrcファイルでも同じ結果になります。)
こうすると、上記プロジェクトのルートでyarn installを実行するたびにevil.shが起動します。あとは悪意あるファイルを追加するだけです。
重要な注意点が2つあります:
--ignore-scriptsまたは同等のオプションを指定しても、上記の動作は発生します。このパッケージがプロジェクトの依存関係である場合、悪意ある.yarnrcファイルは
node_modulesの子であり、兄弟ではないため、適用されません。したがって、その場合は問題ありません。
パート2:目の前にあるコードを隠す
この1年で話題になったもう一つのテーマが、トロイの木馬化されたソースコードです(通常とは異なるUnicode値を持つ文字によって生じる悪意あるコード)。
考え方はとてもシンプルです。たとえば、一部の文字(スペース、CR、LFなどではない文字)は空白のように表示されても、有効な文字列として扱われます。
もう少し詳しく見てみましょう。一見何もないように見える「 」(16進数で0x3164)は「HANGUL FILLER」と呼ばれます。ご覧のとおり(見えないかもしれませんが)、これはスペースではなく、有効な「文字」です。これを悪用すれば、コード片に特定のロジックを隠し、悪意あるコードを仕込んでも検知を逃れられます。
今回のデモに必要な情報は以上で説明できたので、ここではこれ以上詳しく触れません。詳細や背景、例を知りたい方は、以下をぜひご覧ください。
パート3:隠しバイナリ+隠し設定=RCE
ここまでの説明を踏まえると、攻撃の手順は簡単です。
一見無害なパッケージを作成する。
隠し文字を使った名前で悪意あるファイルを作成する。
.rcファイルを作成する。
不可視文字を含むバイナリ名を指すように、設定パラメーターを指定する。
これらの手順を終えれば準備完了です。被害者の視点から、この攻撃を考えてみましょう。
開発者が攻撃手法を知らずにこのようなパッケージを見つけたとすると、危険信号を見逃してしまう可能性が高いでしょう。
少し用心深く、ls -lを実行するかもしれません。すると、次のように表示されます。
出力に不審な点がないため、これが最初の落とし穴です。ほとんどの標的はこの時点でyarn installを実行し、被害に遭います。
では、標的が経験豊富な開発者で、ls.に「不可視文字を表示」するオプションを追加するとしましょう。すると、次のように表示されます。
標的は、目立たない不可視ファイルを完全に無視したまま、「では、.rcファイルの中身は何だろう?」と考え、catで表示するかもしれません。その結果は次のとおりです。
これが2つ目の落とし穴です。
yarn(またはnpm)がカスタムバイナリを呼び出す可能性を認識している開発者は多くありません。上記のような表示は確かに奇妙ですが、「evil.sh」とは書かれていませんよね。
3つ目の落とし穴は単純です。標的にはファイルが見えません。.rcファイルを確認し、yarn-pathの仕様を調べたとしても(同じ仕様はnpmにもあります)、そのプロパティは何も指していないと判断して、結局パッケージマネージャーを実行してしまう可能性があります。
私のPoCでは、yarn installを実行すると次のようになります。
緩和策と考察
次の対策を行うことで、安全を保てます。
(サードパーティの)コードを決して信用しないでください。クローン/プルしたものを必ず把握し、不審な動作や設定に注意してください。
サンドボックス内で実行する。サードパーティのコードは必ずサンドボックス化/コンテナ化された環境で実行してください。パッケージが悪意あるものでも、(おそらく)システムへの影響を防ぎ、マシンの侵害を回避できます。
注:カーネルの脆弱性やサンドボックスからの脱出などがあるため、サンドボックス内で実行しても完全に安全とは限りません。それでも、このような環境で実行すればリスクを大幅に減らし、基本的なリバースシェルなどの単純な攻撃の大半を防げます。
これで攻撃を緩和できました。
この攻撃手法の興味深い点は、完全に見えているのに、見えないことです。
「いつもls -laを実行してすべてのファイルを確認しているし、パッケージマネージャーの設定オプションもすべて把握している」と言う人もいるでしょう。なるほど、それは結構です。しかし、本当にそうでしょうか。さらに言えば、組織の全員に当てはまるでしょうか。
ブルームフィルターと同じように、ここでの答えは「いいえはいいえ、はいはたぶん」です。
最後に改めてお伝えしたいのは、これはコミュニティに攻撃手法の認識を広めるための行動喚起であり、悪用を促すものではないということです。誰もがアプリケーションを構築し、依存関係をほとんど確認せずにインストールする状況では、不審な設定を見つけたら周囲に知らせることが欠かせません。
CTFを始めよう
オンデマンドのバーチャル入門ワークショップを視聴して、CTFの課題の解き方を学びましょう。



