ステガノグラフィー|画像に隠されたデータを探す
フォレンジック編の第2回。暗号は「読めなくする」技術ですが、ステガノグラフィーは「存在自体を隠す」技術です。画像のピクセルに紛れ込んだデータを、ブラウザのCanvas APIを使って本当に抜き出してみましょう。
📋 目次
🖼️ ステガノグラフィーとは何か|暗号と何が違うのか
「読めなくする」のではなく「あることに気づかせない」
ステガノグラフィー = 隠蔽術(ギリシャ語「隠れた書き物」)
暗号(第11話)は、メッセージを誰が見ても読めない形に変換しますが、「ここに重要なデータがある」ということ自体は隠せません。一方ステガノグラフィーは、メッセージが存在すること自体を、第三者に気づかれないようにする技術です。一見何の変哲もない画像・音声・文章の中に、こっそり別のデータを埋め込みます。
歴史的には、見えないインク・マイクロドット(極小の点に縮小した文書)などのアナログな手法がありましたが、デジタル時代では画像ファイルのピクセルデータが最も一般的な隠し場所です。次のセクションで、その代表的な手法「LSB法」を見ていきましょう。
🔢 LSB(最下位ビット)法の仕組み
色をほんの少しだけ変えても、人間の目には分からない
画像の1ピクセルは、赤(R)・緑(G)・青(B)それぞれ0〜255(8ビット)の値で色を表現します。例えばR=200とR=201の違いは、人間の目では区別できません。この「最後の1ビット(最下位ビット/LSB)」を変えても見た目がほぼ変わらないという性質を利用し、多数のピクセルのLSBに1ビットずつメッセージを埋め込んでいくのがLSB法です。
1文字 = 8ビット = 8ピクセル分のLSB
1文字(8ビット)を隠すには8ピクセルのLSBが必要です。仮に'A'(文字コード65 = 01000001)を隠すなら、8つの連続したピクセルのLSBを順に0,1,0,0,0,0,0,1へ書き換えます。これを文字数分繰り返すだけで、画像全体に文章を埋め込めます。
🎨 画像から隠しデータを読み出す(Canvas API実践)
ブラウザだけで本物のLSB抽出ができる
実は、ブラウザに標準搭載されているCanvas APIを使えば、画像の生のピクセルデータを直接読み書きできます。getImageData()を呼ぶと、各ピクセルのR・G・B・Aの値が並んだ配列が手に入ります。CTFのステガノグラフィー問題は、まさにこの仕組みを使って作られています。
var ctx = canvas.getContext('2d');
var data = ctx.getImageData(0,0,canvas.width,canvas.height).data;
// data[0]=1番目のピクセルのR値, data[4]=2番目のピクセルのR値 ...
var lsb = data[0] & 1; // R値の最下位ビットだけを取り出す
取り出したビットを8個ずつまとめて1バイト(文字コード)に変換し、String.fromCharCode()で文字に戻せば、隠されたメッセージが復元できます。次のセクションのチャレンジで、実際にこの処理を実行してみましょう。
JPEGで保存すると壊れる
JPEGは「非可逆圧縮」という方式でファイルサイズを小さくする際、人間の目に分かりにくい部分の情報を間引きます。これによりLSBの値が容赦なく書き換えられてしまうため、LSB法のステガノグラフィーはPNGやBMPのような可逆圧縮(または無圧縮)形式でのみ正しく機能します。
🧰 CTFで使うステガノグラフィーツール3選
自分で書かなくても専用ツールがある
steghide
コマンドラインで動く定番ツール。パスワード付きでデータを埋め込み・抽出できます。CTFではsteghide extract -sf image.jpgのような形で抽出を試すのが定番の最初の一手です。
zsteg
PNG・BMPに特化した解析ツール。複数のビットプレーン・複数のチャンネル(R/G/B)の組み合わせを自動的に総当たりしてLSBパターンを探してくれます。今回学んだLSB法を手動で再現する代わりに使える便利ツールです。
StegOnline / StegSolve
画像の各ビットプレーン(0番目のビットだけ、1番目のビットだけ……)を白黒画像として可視化できるツールです。LSBだけを抜き出して画像化すると、人間の目には見えなかった隠し画像やQRコードが浮かび上がることがあります。
🧩 5分CTFチャレンジ:何の変哲もない画像から隠しデータを読み出せ
下のグラデーション画像、実はただの装飾ではありません
下に表示されている紫のグラデーション画像は、このページに実在するCanvas要素です。見た目はただのグラデーションですが、各ピクセルのR値のLSBにフラグが1ビットずつ埋め込まれています。Consoleで実際に抽出してみましょう。
id=”ep16-canvas” (50×4ピクセル = 200ピクセル分のLSBが利用可能)
チャレンジの手順
① F12 → Consoleタブを開く → ② 下のコードをコピーして貼り付けて実行 → ③ 表示されたDECODED:に続くフラグを確認 → ④ 入力フォームへ!
(function(){
var canvas = document.getElementById('ep16-canvas');
var ctx = canvas.getContext('2d');
var data = ctx.getImageData(0,0,canvas.width,canvas.height).data;
var result = '';
for (var i = 0; i < 30; i++) {
var byte = 0;
for (var b = 0; b < 8; b++) {
var pixelIndex = (i*8+b) * 4;
byte = (byte << 1) | (data[pixelIndex] & 1);
}
if (byte === 0) break;
result += String.fromCharCode(byte);
}
console.log('DECODED:', result);
})();
Consoleで抽出に成功すると表示されるフラグを入力してください。
コードのdata[pixelIndex] & 1の部分が、各ピクセルのR値の最下位ビットだけを取り出している箇所です。8ビット集まるごとに1文字が完成します。
コードをそのままConsoleに貼り付けてEnterキーを押すだけで動作します。実行後に表示されるDECODED: CTF{...}の値をそのままコピーして入力フォームに貼り付けてください。
📝 まとめ+FAQ+次回予告
今回のポイントを振り返ろう
第16話では、暗号とは異なる「存在自体を隠す」ステガノグラフィーの考え方と、その代表的な手法であるLSB法の仕組みを学びました。そして、ブラウザのCanvas APIを使って実際にピクセルデータからフラグを抽出するという、本物のフォレンジック技術を体験しました。
・ステガノグラフィーは「メッセージの存在自体」を隠す技術(暗号とは別物)
・LSB法は各ピクセルの色情報の最下位ビットにメッセージを1ビットずつ埋め込む
・Canvas APIのgetImageData()で生のピクセルデータを取得できる
・LSB法はPNG等の可逆圧縮形式でのみ機能し、JPEG保存で壊れる
・steghide・zsteg・StegOnlineなど専用ツールもCTFでは頻繁に使われる
Q. LSB法で隠せるデータ量はどのくらいですか?
画像のピクセル数とチャンネル数(R・G・B)に比例します。1000×1000ピクセルの画像なら、R値だけでも100万ビット(約125KB)を隠せる計算になります。CTFのフラグのような短いテキストなら、小さな画像でも十分隠せます。
Q. 画像を再保存・再圧縮するとステガノグラフィーは壊れませんか?
はい、特にJPEGのような非可逆圧縮形式で保存し直すと、LSBの値が圧縮処理で書き換えられてしまい、隠したデータは失われます。ステガノグラフィーを使う際はPNGやBMPなど、ピクセル値をそのまま保持できる形式を使う必要があります。
Q. 画像以外にもステガノグラフィーは使えますか?
はい。音声ファイルのサンプル値のLSB、動画ファイルのフレームデータ、さらには文章中の余分な空白文字や改行の使い方(ホワイトスペース・ステガノグラフィー)など、さまざまなメディアに応用できます。
Q. ステガノグラフィーは悪用されることもありますか?
残念ながらあります。マルウェアが画像ファイルに偽装して指令サーバーとの通信内容を隠したり、情報を社外へ持ち出す際に画像に埋め込んで検知を逃れたりする事例が実際に報告されています。セキュリティ分析者がこの技術を学ぶのは、こうした悪用を見抜く防御的な目的のためです。
ログ解析|攻撃の痕跡をテキストから読む
フォレンジック編の第3回。サーバーやアプリケーションが残すログファイルから、攻撃の痕跡を読み解く基本テクニックを体験します。
📚 参考情報
- MDN Web Docs「Canvas API」「ImageData」(Mozilla)
- IPA「情報セキュリティ早期警戒パートナーシップ」関連資料(ステガノグラフィー悪用事例)
- SANS Institute「Steganography in Digital Forensics」概要資料


コメント