Tale of Account Takeover in Multiple Website
This writeup is about account takeover vulnerability I observed in multiple websites during private penetration testing.
While web application testing, I was looking for update email or password update section as well as password reset functionality. Since this feature holds key to the critical vulnerability which can lead to account takeover. Due to private project and criticality of bug, it is not possible to disclose the name of the projects. So we will take example[id].com for understanding the purpose.
Tale-1 #Business Logic Bug in update email with temporary access to the victim’s account can lead to a permanent account takeover.
The password change and email function of an application allow any users to change or reset their password and update email without an administrator intervening. When an email is change application should prompt for the password but in our case due to failed logic, it never did.
So as an impact attacker may able to access complete account and reset user password persistently even after the account is recovered.
Let’s assume Innocent friend: firstname.lastname@example.org.
1) Attacker friend 1: email@example.com.
2) Hacker: firstname.lastname@example.org.
3) Url: https://example1.com/profile
Steps to reproduce:
Note: Physical access temporarily required.
- Suppose user log in to the account using email email@example.com and forgets to log out or even left the computer open and you may have access to it physically.
- Malicious friend/hackers take this opportunity and change the email.
- Clicking on edit email, malicious friend one updates innocent friends email from his email i.e. firstname.lastname@example.org and saves it.
- Again malicious friend reverts the email back to original email i.e. from his email email@example.com to his innocent friend’s email firstname.lastname@example.org.
- After that, they leave computer physically open and another hacker enters into the picture.
This is the fun part !!!
- Now hacker gets physical access and changes email to his email i.e. email@example.com.
- Now saves the email and again changes the email to user’s original email address i.e. firstname.lastname@example.org.
- From email@example.com to firstname.lastname@example.org then reverting it back to original so that user didn’t get to know that anything a happened.
Tadaa!!! The account is hacked permanently.
Let me break it down. This is the bug here. I was checking if the application sends any mail or token to verify the change in an account or not. But it didn’t happen at all. Then I started testing for password reset.
Now click on password reset and enter attackers email i.e. email@example.com.
Hacker receives a password reset link on firstname.lastname@example.org. But this account is not associated with any of the accounts.
Click on password reset and change password, but here we still don’t know whose password is changed.
Now try login using hackers email id and updated password
Check email in profile, it is users original email i.e. email@example.com. Afterwards, if firstname.lastname@example.org tries to login using password reset, it will be able to login into email@example.com as well.
While testing password reset I was looking for successful and failed response for registered and non-registered emails. But for any user which was either registered or changed its email using edit email functionality was able to get the password reset link and change the password of the account on which email was saved or edited even once.
So basically what happened is we have three accounts one is the user with firstname.lastname@example.org. Another second account i.e. email@example.com which is a malicious friend and firstname.lastname@example.org which is the hacker. So firstly rotlu changed the email and saved it’s email then again reverts it back to users original email.
Then another third account hacker changes user’s original email to his email and then reverts it back to users original email.
So the total of two malicious entity one friend and other hacker changed the email to their emails and then reverted it back to the user’s original email. So due to failed business logic, all three were able to login into one account through the email in the profile was of a normal user rgmail.
when the attacker saved his email it was saved in the database and mapped with the user’s id. But once it got changed back to user’s again, the application didn’t remove it from the database and now one user id was mapped to two emails or it can be multiple emails here three in our case(I checked that afterwards).
Since it is permanently stored so even if user recovers account by password reset it can be hacked again because anyone could get the password reset after saving the email into a profile and then changing it back to original one. And another failure was hacker used his email to log in to someone else’s account with different email set in the profile, in our case it was rgmail.
Tale-2 #Improper Authentication in the password update field can lead to the permanent account takeover.
In the website, https://example2.com/ there is a password reset function that sends the password reset link to the user’s email. By intercepting the request and then changing email address can allow the attacker to reset another email’s password, thus allowing him to gain full access to the other user’s account.
1) The attacker request a password reset from reset page and obtains the password reset link in his email.
2) By using a web proxy, he tries to reset password but is able to modify his own email to another user’s email and the password reset will be used to reset another email’s password.
Steps to reproduce:
- Once any registered user clicks on update password.
- A user needs to enter old as well as new password along with confirming the password.
- Intercept the POST request to /user/systemuser.
- Send request to burp intruder and select attack type as a cluster bomb.
Here I was using cluster bomb for the first time since two parameters were needed to be enumerated.
- Add old_password and userid parameter in the cluster bomb as payload1 and payload2.
- For old_password select any word-list or customized word-list and for userid set range on a 4-digit number.
- One can also enumerate valid user id's then using them to bruteforce old_password field.
- As intruder hits both old_password and user_id, it will hit 200 OK and response length also changes.
- Since no rate limiting was present, it was easy to increase the threads to 100 and speed up the process.
Tale-3 #Improper Authentication in the password reset API can lead to the permanent account takeover.
Password recovery functionalities can result in username enumeration, sensitive information disclosure and password reset vulnerabilities.
The attacker requests a password reset and obtains the valid password reset link in his email. By intercepting, an attacker can use the password reset token and modify his own email to a victim’s email and the same password reset will be used for the victim instead of the attacker.
1) Let’s assume user: email@example.com
2) ABC hacker: firstname.lastname@example.org
3) Url: https://example3.com/password_reset/forgot.html
Steps to reproduce:
- Attacker visit website and registers his account.
- Now in the password reset, he enters his email.
- The reset link is sent to the hackers mailbox and he visits the link.
- He lands to https://example3.com/password_reset/forgot.html and enters the new password and confirm password while having proxy intercept on.
- The hacker then modifies the email to victims’ email in the request and submits it.
- Upon submitting the request, the password is successfully changed for the victims account to the hackers desired password.
This is the most generic scenario once will discover in various vulnerable web applications. It will lead to a complete account takeover.
Tale-4 #Broken access control in the password update field in the profile can lead to the account takeover.
While resetting a password, access control was not in place so I tried resetting password but it required critical auth parameter which was used to validate and update the password for every user.
But this problem was solved due to broken access control, it was easy to fetch user details which hold an auth parameter, which is hexadecimal userid used for creating JWT tokens, cookie and other critical fields received after login.
This auth parameter was sent in PATCH along with a new password, without which it was impossible to reset the password and when wrong auth parameter was entered it showed error: duplicate key for userid : xxxx present.
1) API: https://example4.com/api/users/idxxx
2) Victims Userid taken: 9991
3) Attackers Userid taken: 7777
Steps to reproduce:
- Send the get request to GET /api/users/7777 with an authorization header.
- Intercept API request to /api/users and change the userid to victim’s user-id i.e. 9991.
- Copy the auth parameter which is needed in the password update.
- Log in to any account.
- Go to Profile Settings
- Enter New Password and Confirm Password
- Submit via Set New Password and intercept the request.
- Instead of POST/PUT we can see we have PATCH request which is used for partial modification.
- Change the userid to victim’s userid and change the auth parameterin request body from attacker’s auth parameter to victim’s auth parameter.
- Send the request and check the response is a success.
Other than that JWT token was forged to fetch valid user data via API call thus making this attack successful.
- All previous password reset links should automatically expire once a user changes his email address.
- Even User should not be allowed to log in with any other email apart from an email which is added in the profile.
- The mitigation for reset vulnerability is to have some strong encryption. Send an encrypted token and bind it with the particular user.
- Do not include critical token parameters such as auth id in JWT token or user data which is easily fetched as in case of broken access control.
- At multiple places, JWT token was used but it was easily forged using none algorithm
- Csrf token present is usable multiple times to reset password as it is bind with a session. So one token can be used to change multiple account’s passwords. So this token should be stateful(synchronizer token pattern) or stateless (encrypted/hash based token pattern).
- Always provide rate-limiting so that user id enumeration and brute forcing cannot happen.