Home
1958 words
10 minutes
【Steganography】画像ファイルにZIPを隠す「EOFインジェクション」の仕組みと再現

最終更新:2026-01-12

前回の記事では、NTFSファイルシステムの機能である「代替データストリーム(ADS)」を利用したデータ隠蔽について解説した。

しかし、データを隠す手法はファイルシステムに依存するものだけではない。ファイルそのもののフォーマット(構造)の仕様を突き、画像ファイルの中にアーカイブファイルなどを埋め込む手法が存在する。

これは一般に「EOF(End of File)インジェクション」や「オーバーレイ」と呼ばれ、古くからあるステガノグラフィ(データ隠蔽技術)の一種である。

本記事では、Windows標準のコマンドのみを使用してこの現象を再現し、その仕組みと特性について解説する。


EOFインジェクションの仕組み#

JPEGやPNGといった一般的な画像ファイルフォーマットには、データの終わりを示す「終端マーカー」が定義されている。

  • JPEGの場合: バイナリの末尾に FF D9 (EOI: End of Image) というマーカーがある。
  • PNGの場合: IEND というチャンク(データの塊)が末尾にある。

多くの画像ビューア(フォトアプリやブラウザなど)は、ファイルを先頭から読み込み、この終端マーカーを見つけた時点で画像の描画処理を終了する

そのため、終端マーカーより後ろに余分なデータが結合されていても、画像ビューアはそれを「存在しないもの(またはゴミデータ)」として無視する。この性質を利用し、画像の見た目を保ったまま、後ろに別のファイルを隠すことができるのである。


コマンドプロンプトでの再現手順#

特別なツールは必要ない。Windows標準のコマンドプロンプト(cmd.exe)にある copy コマンドのバイナリ結合オプションを利用するだけで再現可能である。

1. 準備#

以下の2つのファイルを用意する。

  • image.jpg : 隠れ蓑にする普通の画像ファイル。
  • secret.zip : 隠したいデータ(中身は何でも良い)。

2. ファイルの結合#

以下のコマンドを実行し、2つのファイルをバイナリモード(/b)で結合して、新しいファイル output.jpg を作成する。

copy /b image.jpg + secret.zip output.jpg

解説:

/b : バイナリファイルとして扱うオプション。これがないとテキストとして扱われ、データが破損する可能性がある。

+ : 複数のファイルを連結する。

3. 結果の確認#

生成された output.jpg をダブルクリックして開いてみてほしい。通常通り画像が表示され、エラーも出ないはずである。見た目上は元の image.jpg と全く変わらない。隠されたデータを取り出す方法では、結合されたZIPファイルの中身にはどうアクセスすればよいのだろうか。

方法1: 拡張子の変更

もっとも単純な方法は、拡張子を偽装することである。output.jpg の名前を output.zip に変更し、エクスプローラーで開くと、画像部分は無視され、後ろにくっついているZIPファイルとして認識される。これで中のファイルを取り出すことができる。

方法2: アーカイバソフトで直接開く7-ZipやWinRARなどの高機能なアーカイバソフトは、ファイル形式をヘッダー(先頭データ)だけでなく、内部構造から判断する機能を持っている場合がある。output.jpg をそのまま 7-Zip で開く(右クリックメニュー等から)と、画像部分は無視され、内部に含まれるアーカイブ構造が展開される。

代替データストリーム(ADS)との決定的な違い#

以前の記事で紹介したADSも「隠しデータ」を作る手法だったが、今回のEOFインジェクションとは**永続性(Persistence)**において決定的な違いがある。

観点ADS (Zone.Identifier 等)EOF インジェクション(結合)
隠し場所ファイルシステムのメタデータ領域ファイルデータ本体の末尾
ファイルサイズ見た目上のサイズは増えない結合した分だけサイズが増える
ファイルシステム依存NTFS のみ(FAT32 等は不可)依存なし
コピー時の挙動USB 等へコピーすると消えるコピーしてもデータは維持される
Web 転送アップロード/ダウンロードで消える維持される

コピーしても消えない強みと弱み#

EOFインジェクションで作成されたファイルは、単なる「バイト列の塊」であるため、USBメモリ(FAT32/exFAT)にコピーしたり、メールに添付して送信したりしても、隠されたデータは消滅しない。一方で、ファイルサイズ(バイト数)を確認すると 画像サイズ + ZIPサイズ の合計値になっているため、元の画像サイズを知っている場合や、小さな画像なのにファイルサイズが異常に大きい場合などには、比較的容易に露見する。

まとめ#

copy /b コマンドを使用したファイルの結合は、OSのバグではなく、ファイルフォーマットの仕様とコマンドの機能を組み合わせた古典的なトリックである。画像ビューアは「終端マーカー」までしか見ない。アーカイバソフトや拡張子変更により、後ろのデータにアクセスできる。ADSとは異なり、ファイルシステムを移動してもデータが残留する。セキュリティの観点からは、一見無害な画像ファイルであっても、その内部にスクリプトや機密情報が含まれている可能性があることを示唆している。不審なファイルを受け取った際は、見た目だけでなくファイルサイズやヘッダー情報にも注意を払う必要があるだろう。

追記:Pythonによる検知(簡易フォレンジック)#

コマンドプロンプトやプロパティでの確認は手軽だが、大量のファイルを検査する場合や、自動化したい場合には不向きである。 ここではPythonを使用し、JPEGファイルの構造的な末尾(EOIマーカー)以降に余分なデータが存在するかどうかを機械的に判定するコード例を紹介する。

検知コードの実装例#

JPEGファイルは原則としてバイナリの FF D9 (EOI) で終了する。ファイルの末尾からこのマーカーを検索し、それより後ろにデータが存在する場合、何らかのデータが隠蔽されている(Injectionされている)可能性が高いと判断できる。


import os

def detect_eof_injection(file_path):
    """
    Detects data appended after the JPEG End of Image (EOI) marker.
    """
    # JPEG EOI marker: 0xFF 0xD9
    EOI_MARKER = b'\xff\xd9'

    try:
        with open(file_path, 'rb') as f:
            content = f.read()

        # Search for the LAST occurrence of the EOI marker
        eoi_index = content.rfind(EOI_MARKER)

        if eoi_index == -1:
            print(f"[-] {file_path}: EOI marker not found (Not a standard JPEG?).")
            return

        # Calculate sizes
        # EOI marker is 2 bytes, so valid end is index + 2
        valid_end_position = eoi_index + 2
        total_size = len(content)
        extra_bytes = total_size - valid_end_position

        if extra_bytes > 0:
            print(f"[!] {file_path}: Suspicious data detected!")
            print(f"    - Original Image Size: {valid_end_position} bytes")
            print(f"    - Injected Data Size : {extra_bytes} bytes")
            print(f"    - Total File Size    : {total_size} bytes")
        else:
            print(f"[+] {file_path}: Clean (No data after EOI).")

    except FileNotFoundError:
        print(f"[x] File not found: {file_path}")
    except Exception as e:
        print(f"[x] Error processing file: {e}")

if __name__ == "__main__":
    # Test with the file created earlier
    target_file = "output.jpg" 
    detect_eof_injection(target_file)

実行結果#

上記のコードを実行すると、結合されたファイルに対しては以下のような警告が出力される。

[!] output.jpg: Suspicious data detected!
    - Original Image Size: 102400 bytes
    - Injected Data Size : 5120 bytes
    - Total File Size    : 107520 bytes

統合的なフォレンジックツールへ#

このスクリプトはEOFインジェクションのみを検知するが、前回の記事で触れた**代替データストリーム(ADS)**の検知と組み合わせることで、簡易的なWindows向けフォレンジックツールを作成することも可能である。

PythonでADSにアクセスする場合、Windows環境ではファイルパスに を付与してオープンすることで内容を読み取れる(例: open(“file.txt.Identifier”, “r”))。ただし、どのようなストリーム名が存在するかを一覧取得するには、Windows API(kernel32.dllなど)をctypes経由で叩くか、専用のライブラリを使用する必要があるため、実装の難易度は少し上がる。

このように「ファイルサイズ」と「実際のデータ構造」の乖離をプログラムでチェックすることは、セキュリティ実務において重要なアプローチの一つである。

【Steganography】画像ファイルにZIPを隠す「EOFインジェクション」の仕組みと再現
https://ss0832.github.io/posts/20260111_png_eof_injection/
Author
ss0832
Published at
2026-01-12
License
CC BY-NC-SA 4.0

Related Posts

【PowerShell】 ファイルに隠された「Zone.Identifier」の正体と代替データストリーム(ADS)
2026-01-11
Windowsでインターネットからダウンロードしたファイルに付与される「Zone.Identifier」の実体であるNTFS代替データストリーム(ADS)について、PowerShellを用いた確認・操作方法を解説します。
【Unix】scpと中間者攻撃:ホスト認証の重要性
2026-01-11
scpコマンド利用時に潜む中間者攻撃(MitM)のリスクと、SSHのホスト鍵認証(StrictHostKeyChecking)がどのように通信を守っているかを解説します。
【Unix】中間者攻撃の仕組みとSFTPの本当の役割
2026-01-11
中間者攻撃(MitM)がどのように成立するのか、その具体的なメカニズム(ARPスプーフィング等)と、sftpがこの問題に対してどのような立ち位置にあるのかを技術的に解説します。
【Unix】scpコマンドの応用:帯域制限・3点間転送・踏み台活用
2026-01-11
scpコマンドの帯域幅制限(-l)や、セキュアな3点間転送(-3)、踏み台サーバーを経由するProxyJump(-J)など、高度な運用オプションについて解説します。
【Unix】scpコマンドの深層:歴史的背景とセキュリティリスク
2026-01-11
scpコマンドが抱える設計上の課題(CVE-2019-6111等)と、OpenSSHが推奨する代替手段(sftp)について、技術的な背景を解説します。
[Unix] sftpコマンド完全ガイド
2026-01-11
sftp(SSH File Transfer Protocol)について、実践的なコマンド操作、バッチ処理による自動化テクニックを網羅的に解説します。