Freedom of Testing is Freedom of Thinking. . . .
API testing is often treated as a checklist in the present fast-paced world of software development. We often merely validate their response against acceptance criteria, quickly script them for automated execution, and then hurriedly move them aside to meet tight release deadlines. But, is this enough amid the increasing attack surfaces in API endpoints ?
What if an API endpoint correctly returns a list of users yet exposes sensitive data due to weak access controls or security best practices?
Or what if an endpoint prevents unauthorized users from performing admin tasks but is still vulnerable to privilege escalation?
What if a 2FA passes each and every test cases from UI level but has a major flaw in the business logic ?
The reality is that traditional functional testing only scratches the surface, leaving critical security gaps unnoticed.
Some may argue that security testing is a separate discipline. But in my opinion it is a subset of testing in general. A simple yet proactive “security testing" may add a few extra hours to the release cycle, but it can prevent costly breaches, safeguard user trust, and strengthen the overall integrity of the product at least mitigating the low hanging fruits that will at least prevent average cyber criminals to exploit the system under release.
In this article, I’ll take that a step further with a hands-on proof of concept. We’ll explore a vulnerable API, uncover potential risks, and outline a practical roadmap for security testing that any Software Quality Assurance professional can apply regardless of their security expertise.
In real life testing, any vulnerability or misconfiguration does not appear exactly what we find in vulnerable applications to test. This is also not expected. We do exploit vulnerable applications and boxes for learning the basic and observe the most granular basic state of a a misconfiguration or vulnerability. On the other hand, we must not publish the real life vulnerabilities we find any system we are permitted to test.
So, in real life this helps us attacking a seemingly impenetrable system based on our experience from playing with these vulnerable systems, as well as, we are free to make any Proof of Concepts from these vulnerable applications.
1. Thorough Vulnerability Assessment:
We assume that the VAmPI application's API endpoints have already undergone rigorous exploratory testing- we know their business logic, we know how to interact with them, and we know how they react on success and failure, we know how they are coupled with each other.
Every primary vulnerability and misconfiguration has been meticulously documented, forming a solid foundation for our testing efforts.
2. Strategic Chaining of Vulnerabilities:
In real-world environments, a complex exploit rarely arises from a single flaw or misconfiguration. Instead, it’s the result of linking together several minor vulnerabilities- each seemingly insignificant on its own — into a cohesive chain that maximizes impact on the business. For example, finding a Broken Object Level Authentication or an SQL injection point is just the starting point. These weaknesses must be witfully and strategically combined to create an exploit that truly challenges business operations. This approach is drawn directly from my professional experience as a tester.
3. Interactive System Exploration:
Although this demo simplifies the process, our primary objective is to deeply understand the system by exploring it as much as possible. By interacting with the application, closely observing its behaviour, and breaking down complex functionalities into basic components, we can uncover simple vulnerabilities. These insights then serve as building blocks for developing impactful exploits that go beyond surface-level testing.
Postman, john the ripper, and Burp Suite Community Edition are suffice to handle most of our API Hacking tasks. We also could use ffuf or dirbuster, but they would be an overkill in this scenario, while hashmap will eat up the tiny resource pool of an RPi2.
An unauthorized user can enumerate email and username of the system by hitting the /users/v1
endpoint.
Although this tiny bit of information with Broken Object Level Authorization does not provide us with explicit data exposure like the _debug
endpoint, but we will take the hardest path and gradually explore the more low hanging fruits like broken object level authorisation, mass assignment, and password brute forcing, rate limiting test etc. This BOLA is also not worth reporting as it has a little to no impact in system’s security.
Get an access token by logging in and try to do an administrative task like deleting the user name1
This will resist mister_simple saying that only admin can remove this user
Crack the weak JWT signing key with a dictionary attack
1. Collect a valid token of mister_simple
2. Crack it with John the Ripper
PoC of the secret key
Forge the token
Pass the delete request with the token into Burp
Create a new asymmetric key in Burp with the signature
Change sub into admin and sign it with the secret
VAmPI is a small flask app developed by one ere0s made for running in both vulnerable and strengthen mode. If the app is run in vulnerable mode, it can be deployed with a predictable secret key for signing the JWT token it returns. For demonstration purpose I did the following:
Changed the secret key in /VAmPI/config.py
vuln_app.app.config['SECRET_KEY'] = 'random'
to
vuln_app.app.config['SECRET_KEY'] = 'qazwsx,.-+-*/789'
that belongs to rockyou.txt.
Then deployed the app
Note: If the key did not belong to the wordlist, we could not crack it.
So, the key takeaway is that if a JWT is signed by a predictable secret key, it can easily be cracked by a dictionary attack as hackers regularly harvest and update their dictionary for both malicious and pentesting purpose.
Hit the /me endpoint and observe the output
This is a textbook example of excessive data exposure.
The key takeaway that “admin”
key might be used as a tool to create a fake admin user.
2. Create an admin user using “admin”:true
and “username”: “ admin”
, with a preceding space. The point of creating such a duplicate admin is to confuse the system with authorisation and its users by harvesting fake data for social engineering, among other malicious activities.
Now delete a user with the token of our fake <space>admin
The Backend Story Say we have created a user called forged_admin. Would we be able to delete a user with its token ?The answer is no. Because the app only allows a user named admin to delete it, line 212.
if user.admin:
if bool(User.delete_user(username)):
responseObject = {
'status': 'success',
'message': 'User deleted.'
}
But it did not do any uniqueness validation for an admin user. So, an “admin”
and “ admin”
users with “admin”:true
becomes the same for the vulnerable application. It could have sanitized usernames by discarding pre and post spaces in
new_user = User(username=username, password=password, email=email, admin=admin)
The vulnerable app version also lacks resources and rate limiting.
No Rate Limiting
5. Load password wordlist
6. Bruteforce login session
The vulnerable app did not limit the max retry rate for failed or successful login that led to bruteforce for any user login credential.
Note: We could pause the the bruteforce in Burp intruder settings after getting the success message.
The password change option of the application works like this /users/v1/{username}/password
As the process is not verified by the token authorization, we can takeover the admin account by changing its password.
5. Hit login with sub admin and changed password
A sweet memory to recall: In the third month of my formal career as a software tester, this was one of my first vulnerability reports,obviously in a more complex implementation, in an application that would later evolve into Bangladesh's leading digital platform for the nationwide import and export.
This is a moderately unfamiliar attack to me but I made it unknowingly a few years back while testing a web app where I put a large string of ‘a’s in a text box that resulted in a crash of a service. The fellow developer said that there was ‘sort of validation’ in the backend that could not handle the unexpected number characters. However, I had not been clear about it whether it was a Regex DoS. Please comment if you have any clue about this “bug” or behaviour.
But what I found in
After doing some research and I found that /users/v1/name1/email
endpoint validates the email format with regex which can be found in update_email() method in users.py.
if vuln: # Regex DoS
match = re.search(
r"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@{1}([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$",
str(request_data.get('email')))
Before Regex DoS
Before the attack the application responses to every request while the resources consumption is normal.
After Regex DoS
$ python3 -c "print('aa' * 2000)" > payload.txt
Put the payload in the email key and hit the update user email endpoint
Notice that there is no response from the app’s endpoint. It takes an infinite time to fetch any data from any endpoint. Moreover, the app.py is now consuming more CPU, upto 100 per cent, of the system to process the regex.
So far this demonstration has served as a proof of concept illustrating how we, the testers or SQAs, can incorporate basic API security testing into our daily works. While it is clear that security testing cannot be fully integrated overnight in our work culture- because of the constraints of tight deadlines, extensive stakeholder engagements, and pressure of finishing testing in tight timelines— it is, however, a must testing scope that we will need near future.
A collaborative effort between IT companies and industry leaders, along with clients, is essential. Such a concerted initiative can pave the way for a well-defined roadmap that enables testers or SQAs to gradually adopt, at least, basic security testing practices into their regular workflows. As the attack surfaces of digital products are growing rapidly, the need for embedded security measures becomes increasingly vital.
This proactive approach of API security testing will mitigates risks and reinforce the security of our systems in an ever-changing threat landscape. In my upcoming writeup, I wish to come up with exploiting injection vulnerabilities. Till then, stay good, keep hacking.
Resources
0. The classic series on exploratory testing of API by Micheal Bolton