見出し画像

見えないコードが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活用に関する記事を定期的に発信しています。

いいなと思ったら応援しよう!