【ブロック暗号応用編】Bit-flip・Padding Oracle・Nonce再利用|CTF思考フレームワーク #55
こんにちは、アンペンです!
今回はブロック暗号応用編。Bit-flip攻撃・Padding Oracle詳細・Nonce再利用を扱います。AES入門で『モード次第で揺らぐ』と知った人向けに、具体的にどう揺らぐかを深掘りします。
共通点は『鍵を知らないのに暗号文だけで意味のある操作ができてしまう』こと。CBCやCTRの構造的弱点が前面に出ます。
ここで一つ、大事な前提を共有しておきます。多くの人は『暗号化さえすれば、中身も守られるし、改ざんも防げる』と思いがち。でも実は、ただ暗号化しただけでは“中身を読めなくする”ことしかできません。“勝手に書き換えられないようにする”のは、別の仕掛け(認証)が要るんです。今回の攻撃は、すべてこの『認証を付け忘れた暗号化』の穴を突いてきます。

鍵を知らないのに暗号文を『改造』できるの?

CBCの『前ブロックとXOR』の性質を使うと、暗号文の1ビット反転で次の平文の同位置が反転する。これがBit-flip攻撃。authority=user → admin に書き換える系の脆弱性で頻出だよ。
前回のAES編で『使い方しだいで揺らぐ』と学びました。今回はその“揺らぎ”を、もう一歩踏み込んで見ていきます。今日のテーマに共通するのは、ちょっとゾッとする事実——『鍵をまったく知らないのに、暗号文を意味のある形でいじれてしまう』こと。中身を読めなくても、こっそり書き換えたり、すり替えたりできてしまうんです。なぜそんなことが可能なのか、3つの代表例で見ていきましょう。
ブロック暗号応用攻撃の3本柱は(1)Bit-flip(CBC暗号文1ビット反転 → 次ブロック平文1ビット反転)、(2)Padding Oracle(エラー応答差で平文復元)、(3)Nonce再利用(同じnonceで2回暗号化 → XORで平文復元)。いずれも『認証なし暗号化』の限界を突きます。守りはAEAD(GCM/ChaCha20-Poly1305)+nonce厳密管理で完全に封じられます。
この記事で分かること
- CBC Bit-flip攻撃の原理(認証付け権限昇格)
- Padding Oracleの拡張(改ざんも可能)
- Nonce再利用の致死性(CTR/GCM)
- AEADの認証タグが何を守るか
📖 はじめてのWebセキュリティ #55|ブロック暗号応用編
Bit-flip・Padding Oracle・Nonce再利用を扱います。 シリーズ一覧を見る →
⚠️ 大事なお約束
他者の暗号化通信・Cookieに対する改ざん・復号は、業務上の権限や法律に違反します。CTFや自分の検証環境のみで確認してください。
CBC Bit-flip:1ビット反転で権限昇格
CBCモードでは、復号時に『暗号文ブロックを復号→前の暗号文ブロックとXOR=平文』という処理が走ります。つまり、暗号文ブロックNの1ビットを反転すると、平文ブロックN+1の同位置が反転します(N自身は完全に壊れますが、N+1だけは制御可能)。
ここをかみ砕きましょう。CBCの復号は『暗号文を変換したあと、1つ前の暗号文ブロックとXORする』という二段構え。ということは、前のブロックをこちらでいじってやれば、その“ズレ”がそのまま次のブロックの平文に乗ってきます。代償として、いじった前のブロック自身はぐちゃぐちゃに壊れますが——狙ったブロックだけは、思いどおりの方向に書き換えられる。これがBit-flip攻撃のカラクリです。
図解:1ビット反転の連鎖
『user=guest』が平文ブロックの中にある場合、その前のブロックの『g』に対応する位置を XOR 操作すれば、復号時に『user=admin』に書き換わるのです(長さが同じなら)。
具体的にイメージすると、なかなかゾッとします。たとえばログイン情報が暗号文に入っていて、その中に『user=guest』と書いてあるとします。攻撃者は中身を読めなくても、対応する位置をピンポイントでビット反転させ、復号後に『user=admin』へとすり替えられる。鍵を一切知らないまま、ただの一般ユーザーが管理者になりすます——こうした“権限昇格”が、こんなに少ない手数で成立してしまうんです。

CBCは『前ブロックの暗号文を次ブロックの復号に渡すリレー』です。後ろのランナー(復号結果)に影響を与えたければ、その1つ前のランナー(暗号文)を蹴ると確実に届きます。ただし前のランナー自身は転びます(=Nブロックは破壊される)。これがBit-flip攻撃の本質です。

ここで覚える用語:完全性(Integrity) vs 機密性(Confidentiality)
暗号化は機密性(中身を読めない)を保証しますが、完全性(改ざんされない)は別物です。CBC単体は機密性しか守れず、暗号文の改ざんを検知できません。AEAD(GCM等)は暗号化と認証を同時に行うため、改ざんがあると復号失敗としてエラーになります。これが現代の標準。
Nonce再利用は最悪の死亡フラグ
CTRやGCMは『nonceから生成したキーストリームと平文をXOR』で暗号化します。同じ鍵+同じnonceで2回暗号化すると、2つの暗号文XOR=2つの平文XORになり、片方が既知なら他方を、両方未知でも頻度分析やクリブで両方が復元できてしまいます。
なぜnonce(毎回変えるべき使い捨ての値)の再利用が、それほど致命的なのでしょう。CTRやGCMは『nonceから作った“目隠し”を平文にかぶせる』方式です。同じ目隠しを2回使うと、2つの暗号文を重ねた瞬間に目隠しどうしが打ち消し合い、“2つの平文を重ねたもの”だけが残ってしまう。片方の中身が分かれば、もう片方も芋づる式に判明します。しかもGCMの場合は、改ざん検知の“封印鍵”まで漏れて、偽造し放題に。だから『nonceは絶対に使い回さない』は、鉄の掟なんです。
- CTRでnonce再利用:2平文のXORが手に入る → 1つ既知なら他方ごと復元
- GCMでnonce再利用:機密性に加えて認証鍵も漏洩(GHASH key recovery)→ 任意の偽造可能
- 『Forbidden Attack』の名で知られる致命傷
- 判別ポイント:同じ宛先に対し毎回ランダム生成されているnonceが、たまに重複(64bit以下のランダムnonceで birthday paradox)

Padding Oracleで『改ざん』もできる
#54で扱ったPadding Oracleは『復号』に使えますが、応用すると『任意の平文を作って暗号化』もできます。攻撃者が指定した平文に対応する暗号文を、鍵なしで生成できてしまうのです。
面白い(そして怖い)のは、Padding Oracleが“復号”だけの技ではない点です。同じ仕組みを逆向きに回すと、今度は『攻撃者が好きな平文に対応する暗号文を、鍵なしで作り出す』ことができてしまう。つまり、読むだけでなく、書けてしまうわけです。署名の付いていないCBCシステムなら、『私は管理者です』という中身の“正規Cookie”を、攻撃者が自作できてしまう——そんな事態すら起こり得ます。
- 復号: 既存の暗号文を改造→エラー差→平文1バイトずつ判明
- 暗号化(改ざん): 任意の平文を逆算 → 攻撃者が好きな暗号文を作成
- 署名なしCBCシステムでは『管理者権限のCookie』を任意生成可能
CTFでやってみよう:CBC Cookieをadminに書き換える
Bit-flip攻撃で権限昇格を体験
目的は『鍵を知らずに暗号文を意味のある形で改造できる』を体感することです。
- Pythonで
AES-128-CBCを使う簡単なCookieサーバを書く(ペイロード:user=guest;admin=0) - 暗号化されたCookieを受け取り、復号結果を返す
- 『admin=0』の前ブロック該当バイトをXORで反転 → 『admin=1』に書き換わるか確認
- 同じサーバをAES-GCMに置き換え、同じ攻撃が認証エラーで弾かれることを確認
- 応用:CTR鍵+nonce固定で2つの暗号文を作り、XORから平文を復元
ここまでの3つは、攻撃の形こそ違えど、急所は同じ一点に集約されます——『暗号化はしたが、認証(改ざん検知)を付け忘れた』。逆に言えば、認証さえ付いていれば、攻撃者がいじった瞬間に“復号失敗”として弾けるんです。
守る側:『AEAD+nonce衛生』の徹底
- 暗号はAEAD(GCM・ChaCha20-Poly1305)を使う(Bit-flipは復号失敗で弾かれる)
- nonceは96bit以上+カウンタ or 暗号論的乱数で衝突を完全回避
- 同じ(鍵, nonce)を二度と使わない。鍵ローテーションでカウンタリセット
- CBCを使う場合はHMAC等で完全性検証(Encrypt-then-MAC)
- CookieやトークンにはJWT(HS256/RS256)等の署名付き形式を選ぶ
- nonceの長さが64bit以下のCTR/GCMは絶対に避ける(birthday boundで衝突)

暗号化だけじゃ改ざんは止められないんだね。認証タグ大事。

そう。次回はハッシュ・MAC編。衝突攻撃やLength Extension、HMAC誤用を扱うよ。
ここまでをひと言でまとめると、『暗号化は“読めなくする”だけで、“守る”には足りない』。中身を隠す(機密性)のと、書き換えを防ぐ(完全性)のは、別の話なんです。その両方をまとめて面倒みてくれるのがAEAD。だから現代の答えは、毎回『GCMかChaCha20-Poly1305』に寄せておく、になるわけです。
まとめ:『機密性だけでは守れない』
- CBC Bit-flip: 1ビット反転で次ブロックの平文を制御
- Padding Oracle: 復号だけでなく改ざん暗号文も生成
- Nonce再利用: 2平文XORが見える(GCMは認証鍵も漏れる)
- 守りはAEAD一択+nonce厳密管理
今日の持ち帰りは『読めない=安全、ではない』。攻撃者は中身を読まずとも、暗号文を“いじる・すり替える”だけで悪さができます。それを断ち切るのが認証タグ。攻める人は『認証はあるか?』を真っ先に探し、守る人は『暗号化には必ず認証をセットで』。この一点が、ブロック暗号応用編すべての結論です。
次回はハッシュ・MAC編。衝突攻撃・Length Extension・HMAC誤用を扱います。
