If you’ve spent sufficient time on a cybersecurity assignment so that the bigger picture falls into place, you know that some issues will reveal themselves to you with ease.
This was a penetration testing engagement for which I had sufficient time to scour through all the nooks and crannies of the assets involved. I usually spend much less time on assignments, in the ballpark of days.
The assets were their mobile app, as well as the API. When I have a mobile app in scope, this is good news because I often use it as a blueprint to understand what goes on under the hood.
Let me take you through the entire process of discovery:
- Getting to know the app as a legitimate user, I looked at the login endpoint which took the username and password and authenticated the user.
- Inspecting the .java code of the mobile app, I found an endpoint /confirmation/resend (not the real endpoint — of course) that took two parameters: username and email.
- I played with this endpoint to find out that it gives a user the ability to resend themselves an email with a link to confirm their account (in case they didn’t receive it at sign-up).
- Thus, the first natural thing to do was to send my username and the email of someone else (a potential attacker if I may) to this endpoint.
- And I received the confirmation link in the attacker’s email.
- Clicking the link inside reconfirms the account so to speak. In actuality though, it simply links the account of the victim with the attacker’s email.
- What we have so far: a user’s account (victim) with the attacker’s email. What’s next? We must find a way to authenticate into the victim’s account.
- Enter the forgot password endpoint. This endpoint took a username and sent an email to the corresponding email associated with the username. In this case, the attacker’s email.
- Clicking the link inside the email allowed the attacker to change the password, thereby completely compromising the victim’s account.
- If you ask me, this entire process was pretty clean and straightforward.
You may ask, but how do you get a valid username? There was an endpoint responsible for forgotten usernames which spilled out verbose errors and was unprotected to rate-limit bypass attacks.
The main root cause of the ATO: I think that the resend confirmation should only take one of the two (either username or email). If the endpoint must take both of them, there should at least be a backend check that these correspond to one another.
Unless manually testing, reading the code, and taking sufficient time to understand how an asset operates alone or with respect to other assets, this type of business logic issue completely flies under the radar of ALL automated tools and scanners. Safe to say, I was very pleased with this finding.