Enumerating and Abusing APIs
In many cases, our penetration test target is an internally-built,
closed-source web application
that is shipped with a number of Application Programming Interfaces.
These APIs are responsible for interacting with the back-end logic
and providing a solid backbone of functions to the web application.
We can use Gobuster features to brute force the API endpoints.
The API name is often quite descriptive
about the feature or data it uses to operate,
followed directly by the version number.
Let’s try brute forcing the API paths
using a wordlist along with the pattern Gobuster feature.
We can call this feature by using the -p option and providing a file with patterns.
For our test,
we’ll create a simple pattern file on our Kali system containing the following text:
In this example,
we are using the “{GOBUSTER}” placeholder to match any word from our wordlist,
which will be appended with the version number.
To keep our test simple, we’ll try with only two versions.
We are now ready to enumerate the API with gobuster:
We discovered two interesting entries that seem to be API endpoints.
Let’s first inspect the /users API with curl.
The application returned three user accounts,
including an administrative account that seems to be worth further investigation.
We can use this information to attempt another brute force attack with gobuster,
this time targeting the admin user with a smaller wordlist.
To verify if any further API property is related to the username property,
we’ll expand the API path by inserting the admin username at the very end.
The password API path seems enticing for our testing purposes,
so we’ll probe it via curl.
Interestingly,
instead of a 404 Not Found response code,
we received a 405 METHOD NOT ALLOWED,
implying that the requested URL is present,
but that our HTTP method is unsupported.
By default, curl uses the GET method when it performs requests,
so we could try interacting with the password API through a different method,
such as POST or PUT.
Both POST and PUT methods, if permitted on this specific API,
could allow us to override the user credentials,
in this case, the administrator password.
Before attempting a different method,
let’s verify whether or not the overwritten credentials are accepted.
We can check if the login method is supported by extending our base URL:
Although we were presented with a 404 NOT FOUND message,
the status message states that the user has not been found;
another clear sign that the API itself exists.
We only need to find a proper way to interact with it.
We know one of the usernames is admin,
so we can attempt a login with this username
and a dummy password to verify that our strategy makes sense.
Next, we will try to convert the GET request into a POST
and provide our payload in the required JSON format.
Let’s craft our request by first passing the admin username
and dummy password as JSON data via the -d parameter.
We’ll also specify “json” as the “Content-Type”
by specifying a new header with -H.
The API return message shows that the authentication failed,
meaning that the API parameters are correctly formed.
Since we don’t know admin’s password,
let’s try another route and check whether we can register as a new user.
This might lead to a different attack surface.
Let’s try registering a new user
by adding a JSON data structure that specifies the desired username
and password:
The API replied with a fail message
stating that we should also include an email address
We could take this opportunity
to determine if there’s any administrative key we can abuse.
Let’s add the admin key, followed by a True value.
Since we received no error,
it seems we were able to successfully register a new user as an admin,
which should not be permitted by design.
Next, let’s try to log in with the credentials we just created
by invoking the login API we discovered earlier.
We were able to correctly sign in and retrieve a JWT authentication token.
To obtain tangible proof that we are an administrative user,
we should use this token to change the admin user password.
We can attempt this by forging a POST request that targets the password API.
We passed the JWT key inside the Authorization header
along with the new password.
Sadly, the application states that the method used is incorrect,
so we need to try another one.
The PUT method, along with PATCH,
is often used to replace a value
as opposed to creating one via a POST request,
so let’s try to explicitly define it next:
This time we received no error message,
so we can assume that no error was thrown by the application backend logic.
To prove that our attack succeeded,
we can try logging in as admin using the newly-changed password.
Nice!
We managed to take over the admin account
by exploiting a logical privilege escalation bug
present in the registration API.
These kind of programming mistakes
happen to various degrees when building web applications that rely on custom APIs,
often due to lack of testing and secure coding best practices.
So far we have relied on curl to manually assess the target’s API
so that we could get a better sense of the entire traffic flow.
This approach, however,
will not properly scale whenever the number of APIs becomes significant.
Luckily, we can recreate all of the steps from within Burp.
As an example, let’s replicate the latest admin login attempt
and send it to the proxy by appending -proxy to the command.
Once done, from Burp’s Repeater tab,
we can create a new empty request
and fill it with the same data as we did previously.
Next, we’ll click on the Send button
and verify the incoming response on the right pane.
Great!
We were able to recreate the same behavior within our proxy,
which, among other advantages,
enables us to store any tested APIs in its database for later investigation.
Once we’ve tested a number of different APIs,
we could navigate to the Target tab and then Site map.
We can then retrieve the entire map of the paths we have been testing so far.
From Burp’s Site map,
we can track the API we discovered
and forward any saved request to the Repeater or Intruder for further testing.
In this Learning Unit,
we explored how to debug web applications through the web browser console
and network developer tools.
We then learned what REST APIs are,
their role in web applications,
and how we can approach a black-box penetration test
to find weaknesses and abuse them.