偵察とブルートフォース
導入
認証列挙はセキュリティの基本的な側面
- 列挙の重要性と、それが効果的なブルートフォース攻撃の準備をどのように整えるかを理解します。
- 主に詳細なエラー メッセージから情報を抽出することに焦点を当てた、高度な列挙方法を学習します。
- 認証メカニズムを侵害する際の列挙攻撃とブルート フォース攻撃の関係を理解します。
- 列挙攻撃とブルートフォース攻撃の両方のツールとテクニックを使用して実践的な経験を積みます。
認証列挙
認証の列挙は、玉ねぎの皮を剥くようなもの、システムのセキュリティの各層を取り除くと、その下にある実際の操作が明らかになる
ユーザー名がわかれば、攻撃者は、パスワードだけに集中できる
ターゲットを絞れる
-
有効なユーザー名の識別
- ログイン時やパスワードのリセットの時にアプリケーションがどのように応答するのかを観察する
- 攻撃者にアカウントが有効かどうかのヒントを与えるエラー例
- 「このアカウントは存在しない。」(ブルートフォースや辞書攻撃でこのエラーが出ないものは有効なユーザー名)
- 「パスワードは正しくない」(ユーザー名は合っている。= 有効なユーザー名)
-
パスワードポリシー
- 決められたパスワード形式がある場合、攻撃者はそのパスワード形式に応じて、戦略や複雑さを判断する。
- パスワードの形式に沿っていないエラーなどから、攻撃者はパスワードの形式に応じた辞書などを作ることができる
- 攻撃者が推測できるエラー例
- パスワードは何文字位以上何文字以内です。
- パスワードには、大文字と-が含まれていなければなりません
-
列挙を行うべきサイト内情報
- 登録ページ
- ユーザー列挙につながるレスポンス
- 「すでにそのユーザーは存在しています。」
- 特殊文字を入れた以外での「そのユーザー名は使用できません。」など
- ユーザー列挙につながるレスポンス
- パスワードリセット機能
- 「ユーザーが存在していません」などの情報は、ユーザー列挙につながる
- 詳細なエラー
- ユーザー名が見つかりません」、「パスワードが間違っています」
- 過去のデータ侵害で漏れた情報の利用
- 以前のセキュリティ侵害のデータは、侵害されたユーザー名とパスワードがさまざまなプラットフォームで再利用されているかどうかをテストできるため、攻撃者にとって金鉱
- 登録ページ
詳細エラーによるユーザーの列挙
詳細なエラーから得られるかもしれない情報
- 内部パス
- 通常のユーザーには表示されない構成ファイルや秘密キーが含まれている可能性のあるアプリケーション サーバーのファイル パスとディレクトリ構造を明らかにする
- データベースの詳細情報
- データベースを覗き見ることができるこれらのエラーにより、テーブル名や列の詳細などの秘密が漏れる可能性
- ユーザー情報
- ユーザー名やその他の個人データが示唆
詳細なエラーの誘発
エラーを引き起こすために使われる一般的な手法
- 無効なログイン試行
- 攻撃者は、意図的に間違ったユーザー名またはパスワードを入力することで、有効なユーザー名と無効なユーザー名を区別するのに役立つエラー メッセージをトリガーする
- SQLインジェクション
- ログイン、登録画面、あらゆる入力欄
- パストラバーサル
- フォーム操作
- ウェブアプリケーションのフォームに含まれている 入力フィールドや隠しパラメータ といった値を意図的に変更(改ざん)して送信することで、アプリケーションが想定外の挙動を起こすかどうかを調べるテクニック
-
- 隠しフィールドの値を書き換える
- 普段はユーザーの画面上には見えない
<input type="hidden">
の値や、ブラウザ開発者ツールでしか見えないパラメータを変更して送信
-
- 検証エラーを意図的に引き起こす
- 例えば「数値しか受け付けないはずのフォームに文字列を入れて送信する」
- 「必須フィールドを削除して送信する」「隠しフィールドを除去して送信する」などを行う。
- アプリケーションのファジング
- アプリケーションのさまざまな部分に予期しない入力を送信して、その反応を確認すると、弱点を特定するのに役立ちます。たとえば、Burp Suite Intruderなどのツールは、プロセスを自動化するために使用され、さまざまなペイロードをアプリケーションに大量に送信して、どのペイロードが有益なエラーを引き起こすかを確認します。
列挙とブルートフォースの役割
- ユーザーの列挙
- 有効なユーザー名を検出することで準備が整い、その後の総当たり攻撃での推測作業が減る
- 詳細なエラーの悪用
- エラーから得られる洞察により、パスワード ポリシーやアカウント ロックアウト メカニズムなどの側面が明らかになり、より効果的なブルート フォース戦略への道が開かれる。
認証フォームでの列挙
ウェブサイトのパスワードを忘れた場合の機能を使ってユーザーを列挙を行える
例
- 無効なメールアドレスを入力すると、ウェブサイトは「メールアドレスが存在しません」と応答し、メールアドレスがまだ登録されていないことを示す
- Web サイトは「無効なパスワード」というエラー メッセージで応答し、電子メールはデータベースに存在するがパスワードが間違っていることを示す
例 : 対象の Web アプリで有効なメールをチェックする Python スクリプト
- メールアドレスのリストは、過去の漏洩した情報などを利用できるかも
import requests
import sys
def check_email(email):
url = 'http://enum.thm/labs/verbose_login/functions.php' # Location of the login function
headers = {
'Host': 'enum.thm',
'User-Agent': 'Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest',
'Origin': 'http://enum.thm',
'Connection': 'close',
'Referer': 'http://enum.thm/labs/verbose_login/',
}
data = {
'username': email,
'password': 'password', # Use a random password as we are only checking the email
'function': 'login'
}
response = requests.post(url, headers=headers, data=data)
return response.json()
def enumerate_emails(email_file):
valid_emails = []
invalid_error = "Email does not exist" # Error message for invalid emails
with open(email_file, 'r') as file:
emails = file.readlines()
for email in emails:
email = email.strip() # Remove any leading/trailing whitespace
if email:
response_json = check_email(email)
if response_json['status'] == 'error' and invalid_error in response_json['message']:
print(f"[INVALID] {email}")
else:
print(f"[VALID] {email}")
valid_emails.append(email)
return valid_emails
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python3 script.py <email_list_file>")
sys.exit(1)
email_file = sys.argv[1]
valid_emails = enumerate_emails(email_file)
print("\nValid emails found:")
for valid_email in valid_emails:
print(valid_email)
脆弱なパスワードリセットロジックの悪用
パスワードリセットフローの脆弱性
以下の3つが多く使われることが多いが、それぞれに脆弱性がある
- メールアドレスを基にしたリセット
- 流れ
- ユーザーがパスワードをリセットすると、アプリケーションはリセット リンクまたはトークンを含むメールをユーザーの登録済みメール アドレスに送信
- ユーザーがこのリンクをクリックすると、新しいパスワードを入力して確認できるページに移動 or システムが自動的にユーザーの新しいパスワードを生成し、メールで伝える
- 懸念
- ユーザーのメール アカウントのセキュリティと、送信されるリンクまたはトークンの機密性に大きく依存する
- 登録時に設定した質問を基にしたリセット
- 流れ
- アカウント作成時に設定した一連の事前設定されたセキュリティの質問にユーザーが答える
- 答えが正しければ、システムはユーザーがパスワードのリセットを続行することを許可
- 懸念
- 攻撃者が個人情報 ( PII : Personally-Identifiable-Information ) にアクセスした場合、簡単に見つかったり推測されたりする可能性があるため、セキュリティが侵害される可能性がある
- SMSを使ったリセット
- 流れ
- SMS を使用してリセット コードまたはリンクをユーザーの携帯電話に直接送信
- あとはメールアドレス認証と同様
- 懸念
- ユーザーの電話へのアクセスが安全であると想定されているが、SIM スワッピング攻撃や傍受に対して脆弱になる可能性がある
全体に関係する脆弱性・懸念
- 予測可能なトークン
- リンクまたは SMS メッセージで使用されるリセット トークンが予測可能であったり、連続したパターンに従っていたりする場合、攻撃者は推測したり、ブルート フォース攻撃を行って有効なリセット URL を生成する可能性がある
- トークンの有効期限の問題
- トークンの有効期限が長すぎたり、使用後すぐに有効期限が切れなかったりすると、攻撃者に攻撃の機会を与えてしまいます。この機会を制限するには、トークンがすぐに期限切れになることが重要
- 不十分な検証
- セキュリティの質問や電子メールベースの認証など、ユーザーの身元を確認するためのメカニズムは、質問が一般的すぎる場合や電子メール アカウントが侵害されている場合には、脆弱になり、悪用される可能性がある
- 情報漏洩
- 電子メール アドレスまたはユーザー名が登録されているかどうかを指定するエラー メッセージは、攻撃者がアカウントの存在を確認して列挙するのに役立つ可能性がある
- 安全でない通信プロトコル
- リセット リンクまたはトークンを HTTPS 以外の接続経由で送信すると、これらの重要な要素がネットワーク盗聴者によって傍受される可能性がある
脆弱なパスワードリセットを利用した予測可能なトークンのブルートフォース攻撃
- 単純で予測可能なトークンや有効期限が長いトークンは、傍受やブルート フォース攻撃に対して特に脆弱である可能性がある。
- そのため、ブルートフォースで突破できることがある
- パスワードをリセットしようして、
forgat.php
で、メールアドレスを入力してリセットリンクがメールで送られるシナリオ
1. 攻撃対象のページにアクセス
http://enum.thm/labs/predictable_tokens/
にアクセス。
2. パスワードリセットをリクエスト
- "admin@admin.com" を入力し、"Submit" をクリック。
- 成功メッセージが表示される(パスワードリセットリンクが送信された)。
3. 送信されたリセットリンクを確認
-
デモ環境ではリセットリンクが表示される
http://enum.thm/labs/predictable_tokens/reset_password.php?token=123
-
トークンが単純な3桁の数値であることに注目。
4. Burp Suite でリクエストをキャプチャ
- 上のリセットリンクにアクセスし、Burp Suite でリクエストをキャプチャ。
- Intruder に送信
"token"
の値(例:123
)を 特殊文字で囲む。この部分をブルートフォースで見つける
5. ブルートフォース攻撃用の辞書を作成
Burp Suite の Numbers で 100
から 300
までの数値リストを設定。
6. ブルートフォース攻撃を実行
- Burp Suite Community Edition を使用するため、処理には時間がかかる。
- 成功すると、レスポンスの
Content-Length
(コンテンツ長)が他と異なるレスポンス(成功したトークン)を発見。
7. 成功したトークンでログイン
- 成功したトークンを使用し、新しいパスワードを設定してアプリにログイン。
- ダッシュボードでフラグを確認。
HTTP基本認証の悪用
2k24(2024年という意味)での基本認証
Basic Authentication(ベーシック認証)
- シンプルな認証方式 で、ユーザー名とパスワード
- 認証情報は Base64 エンコードされ、HTTP ヘッダー (
Authorization: Basic <encoded-credentials>
) に含まれる。 - 暗号化されていないため、HTTPSが必須!HTTPだと盗聴される可能性がある)
- 利用場面
- ネットワーク機器(ルーター、スイッチなど)の管理画面
- 簡易的なAPI認証
- 開発環境やテスト環境の保護
- 長所
- 実装が簡単(特にリソースが限られたデバイス向け)
- 追加のセッション管理が不要(APIなどに適している)
- 短所
- セキュリティが弱い(パスワードが簡単に盗まれる可能性あり)
- HTTPS なしでは使用すべきでない
- 多要素認証(MFA)やOAuthのような高度なセキュリティ機能がない
認証のヘッダーのフォーマット
credentialの部分には、username:password
のBase64エンコード
詳細 : https://datatracker.ietf.org/doc/html/rfc7617
Authorization: Basic <credentials>
Basic Authentication(ベーシック認証)のブルートフォース
目的 : Basic Authentication を利用しているウェブサイトに対してブルートフォース攻撃を行い、ログイン資格情報を取得する。
-
ターゲットにアクセス
- http://enum.thm/labs/basic_auth/ にアクセスする。
-
Basic Authentication のリクエストを取得
- ポップアップが表示されるので、適当な ユーザー名とパスワード を入力し、ログインを試みる。
- Burp Suite を使用して、このリクエストをキャプチャする。
-
Burp Suite の Intruder にリクエストを送信
- キャプチャしたリクエストを 右クリック → "Send to Intruder" で Intruder に送る。
-
Authorization ヘッダーのデコード
- "Positions" タブ に移動し、Authorization ヘッダーの base64 エンコードされた認証情報 をデコードする(base64 decode)。
BurpでBase64デコードする手順
- "Positions" タブ に移動し、Authorization ヘッダーの base64 エンコードされた認証情報 をデコードする(base64 decode)。
-
パスワードリストを設定
- "Payloads" タブ に移動し、"Payload type" を "Simple list" に設定する。
- 使用するパスワードリストを選択
- AttackBox の場合:
- /usr/share/wordlists/SecLists/Passwords/Common-Credentials/500-worst-passwords.txt
-
ペイロードの処理ルールを追加
- ユーザー名とパスワードを一緒に特殊文字で囲む
- 例えば "admin:123456" の形式にする。
- base64 エンコード
- ユーザー名とパスワードを base64 エンコードし、Authorization ヘッダーに適用。
- "="(イコール)を削除
- base64 ではパディングに「=」が使用されるため、エンコードから文字「=」(等号)も削除する
- 「Payload encoding」の中に=を加える
上の設定を全て行ったときの画面
- ユーザー名とパスワードを一緒に特殊文字で囲む
-
攻撃の実行
- "Positions" タブ に戻り、"Start Attack" をクリック。
-
成功したレスポンスを確認
- ステータスコード 200 を確認する。
- ステータス 200 が返ってきたリクエストの Authorization ヘッダーをデコードすると、正しい資格情報(username:password)が判明する。
ステータスコードが200の、ログインできる認証情報を発見したとき
-
入手した資格情報でログイン
- 成功したユーザー名とパスワード を使用し、ウェブサイトにログインする。
- フラグが表示される。
OSINT
Wayback Machineとか Google Dorksが使えるよ