API5:2019 — Broken Function Level Auth II
Hello all, today we will be looking into OWASP API Security Top 10’s another vulnerability, i.e. Broken Function Level Authorization.
API5:2019 — Broken Function Level Auth II
Hello all, today we will be looking into OWASP API Security Top 10’s another vulnerability, i.e. Broken Function Level Authorization.
The Issue:
“The API relies on the client to use user-level or admin-level APIs as appropriate. Attackers figure out the ‘hidden’ admin API methods and invoke them directly.”
Reference: https://apisecurity.io/encyclopedia/content/owasp/api5-broken-function-level-authorization.htm
Lab Scenario
We have set up the below scenario in our Attack-Defense labs for our students to practice. The screenshots have been taken from our online lab environment.
Lab: Broken Function Level Auth II
This lab environment consists of a Banking WebApp hosted on the target server. The webapp allows its user to update their password and Email ID after a successful login. The issue is that the authorization system in place is not properly implemented. The Banking API just validates the token and allows the user to reset the password of the account corresponding to the provided Email ID. Therefore, anyone having a valid token could update the password for any other user if the Email ID of the other user is known.
Note: The authorization system relies on a scope parameter in the issued token. If the token issued to a user has the scope of “account-write”, then they get write access on the account, else, for token having the scope of “account-read”, the user gets read-only access to the account.
Challenge Statement
Objective: Leverage the vulnerability to hijack admin’s account and retrieve the Golden Ticket!

Solution
Step 1: Check the IP address of the machine.
Command: ifconfig
Determining the IP address of the host machine
The IP address of the machine is “192.248.164.2”
Therefore, the Banking WebApp is running on “192.248.164.3”, at port 5000.

Step 2: Viewing the Banking WebApp.
Open the following URL in firefox.
URL: http://192.248.164.3:5000
Viewing the Banking WebApp
Step 3: Configuring the browser to use BurpSuite proxy and making BurpSuite intercept all the requests made to the API.
Launch BurpSuite.
Select Web Application Analysis > burpsuite
Launching BurpSuite
The following window will appear:
Launching BurpSuite (contd.)
Click Next.

Finally, click Start Burp in the following window:
Launching BurpSuite (contd.)
The following window will appear after BurpSuite has started:
Launching BurpSuite (contd.)
Configure the browser to use the Burp proxy listener as its HTTP Proxy server.
Open the browser preference settings and search for network proxy settings.
Changing browser settings to proxy all HTTP requests through BurpSuite
Select Manual Proxy Configuration and set the HTTP Proxy address to localhost and the port to 8080.
Changing browser settings to proxy all http requests through BurpSuite (contd.)
Click OK.
Everything required to intercept the requests has been setup.

Step 4: Interacting with the Banking API using the WebApp.
Login into the webapp using the provided credentials:
Username: elliot Password: elliotalderson
Note: Make sure that intercept is on in BurpSuite.
Login using the provided credentials
Notice the corresponding requests in BurpSuite.
Forward the OPTIONS request to the /login endpoint
Forward the above request.
Forward the login request
Forward the above request and view the changes reflected in the web app.

Login was successful!!
Click on the Check Balance button.
Checking the account balance
Forward above request.
The balance of the user after the above request was forwarded

Click on Get Golden Ticket button.
Request to retrieve the Golden Ticket
Forward the above request.
Request to retrieve the Golden Ticket (contd). Notice the JWT token sent in the above request
Notice that a JWT Token is sent in the request.
JWT Token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdW1teSBCYW5rIiwiYWNjdCI6MTMzNywic2NvcGUiOiJhY2NvdW50LXJlYWQiLCJleHAiOjE1NzU4ODcwODgsImlhdCI6MTU3NTg4NjQ4OH0.iMbfch1vv3DvNiWBmpBWace-YosFJba6la-X5hJFfzno6eWSggOC8AMryRlF8AtrAS7ykMgcsLjsRuX22MqovbrbUMjnkVQ8Ron_sJu2JyHKRh62H7uSXt54s-cx6lAFLGlvUxjfhTqo2cSaNXBsSqcRhi4oiiseHRFX5b342nD9pXL-9RaRv7JxJkIgdgUzEtCOnq4U5-cAOzEHKoksBh2EiLzV08J2bS8HZ3YL9gaZZCqWl9y-JDYHWffNv8ljz57nr1KSlpb7xN5bLKhyKQpMJ85Csf2R3ePybE-fcVquXyLVr4myz2_dOiNR0Jpwr47nW2aGNFTi32A6YxQYmw
Visit https://jwt.io and decode the above obtained token:
Decoding the above obtained JWT token

Notice that the token has a scope claim and it is set to the value “account-read”.
Forward the above request and view the changes reflected on the web page.
The Golden Ticket couldn’t be retrieved due to insufficient balance
As mentioned in the challenge description:
“The authorization system used relies on a scope parameter in the issued token. If the token issued to a user has the scope of “account-write”, then they get write access on the account, else, for scope of “account-read”, the user gets read-only access to the account.”
And the token obtained above has scope set to “account-read”.
This means that the above user (“Elliot Alderson”) also has read-only access to the account. Therefore, he can only read his account balance.

Step 5: Resetting password for Elliot.
Updating the password for “elliot”
Set the password to 123.
Setting the password to “123”
Forward the above OPTIONS request to update the password

Forward the above request.
Forward the above POST request to update the password
Forward the above request.
The password was updated successfully!!
Notice that the password got successfully updated.

Step 6: Updating the password for the admin user.
As it is mentioned in the challenge description that the Banking API just validates the token and allows the user to reset the password of the account corresponding to the provided Email ID. Therefore, anyone having a valid token could update the password for any other user if the Email ID of the other user is known.
Since the Email ID of the admin user is also known, it is possible to reset the password for the admin user.
Resetting the password for Elliot again:
Login again as “elliot”
Check the corresponding request in BurpSuite.
Forward the above login request

Forward the above request.
Forward the above login request (contd.)
Check the changes reflected on the web page.
Login was successful!!

Click on the Update Profile button.
Updating the password for “elliot”
Set the new password as 1234.
Setting the password to “1234“

Check the corresponding request in BurpSuite:
Forward the above OPTIONS request to update the password
Forward the above request.
Send the above POST request to repeater and turn off the intercept mode
Send the above request to Repeater and turn off the intercept mode:
The password was updated successfully!!
Notice on the web page a pop-up gets displayed acknowledging that the password has been updated successfully.

Navigate to the Repeater window and send a request again after editing the data sent:
Navigate to the repeater window
Set the Email ID of “admin” user in the email field.
Replace the email id with that of “admin” user

Send the modified request.
Send the modified request
Notice the response. It reflects that the password has been successfully updated.
Login to the web app again using the updated credentials of admin user:
Login as admin
Login was successful
Click on Check Balance button.

Note: Run the Burp Proxy in intercept mode for this request to get the JWT token passed in the request.
Request to check the balance. Notice the JWT token passed in the above request
Notice that a JWT Token is passed in this request.
JWT Token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdW1teSBCYW5rIiwiYWNjdCI6OTk5OSwic2NvcGUiOiJhY2NvdW50LXdyaXRlIiwiZXhwIjoxNTc2MDAzMDY2LCJpYXQiOjE1NzYwMDI0NjZ9.T2MSHu5510CYrhs2-efQhsSRcBVPkUE-Fwi9qkxjEJDlWYZUzwqSwHHMVNSFrUGbQHOYwzwusrXU_jv1hCz5Lq0frLlCAf5q-oqvrIp7Ke_xIBEawu6FLXQGLOk1w297KSpKGGiJJq-qbS8068GaccK4oL5HFefDdEDh35V4NOUPvpePGfS6b0vkLdO2iX4h_ErCbcfB1dAe52syKNGRqYwRwh3koj_1ih3JrReF4pABU2IoYWmx7wNnXBbiUxBlUmU1d0OMRWyEzM6tIB1NV_L_EWAVZLyFvNciEdCwYLRLv9K8l2cHg3NdowkxvkItAtFANtQVbqjneP8O-ZhIRg
Decoding this token using https://jwt.io:
Decoding the above obtained JWT token
Notice that this token has a scope of “account-write”.

Forward the above intercepted request and notice the change reflected on the web page.
The balance for admin user is $6000
Click on Golden Ticket button:
The Golden Ticket couldn’t be retrieved due to insufficient balance
The Golden Ticket is not returned since the balance is not greater than $5000000.

Step 7: Increasing the balance for Elliot’s account and retrieving the Golden Ticket.
In the challenge description, it is mentioned that the /balance endpoint supports a POST request as well. That request is used to modify the account balance.
Send a POST request to the /balance endpoint and modify the balance of admin’s account and set it to a value greater than 5000000:
Command: curl -X POST -H “Content-Type: application/json” http://192.248.164.3:8081/balance -d ‘{“acct”: 9999, “balance”: 100000000, “token”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdW1teSBCYW5rIiwiYWNjdCI6OTk5OSwic2NvcGUiOiJhY2NvdW50LXdyaXRlIiwiZXhwIjoxNTc2MDAzMDY2LCJpYXQiOjE1NzYwMDI0NjZ9.T2MSHu5510CYrhs2-efQhsSRcBVPkUE-Fwi9qkxjEJDlWYZUzwqSwHHMVNSFrUGbQHOYwzwusrXU_jv1hCz5Lq0frLlCAf5q-oqvrIp7Ke_xIBEawu6FLXQGLOk1w297KSpKGGiJJq-qbS8068GaccK4oL5HFefDdEDh35V4NOUPvpePGfS6b0vkLdO2iX4h_ErCbcfB1dAe52syKNGRqYwRwh3koj_1ih3JrReF4pABU2IoYWmx7wNnXBbiUxBlUmU1d0OMRWyEzM6tIB1NV_L_EWAVZLyFvNciEdCwYLRLv9K8l2cHg3NdowkxvkItAtFANtQVbqjneP8O-ZhIRg”}’
Modifying the account balance of the admin user

Notice the account balance now:
The account balance was updated successfully!
Note: Turn off the intercept mode in Burp Proxy for all further requests.
The balance was updated successfully.
Since the balance is now greater than $5000000, the Golden Ticket could be retrieved.
Awesome! We have got the Golden Ticket :)
Golden Ticket: This_Is_The_Golden_Ticket_2a2461a19d93085b8ac26bc3593bf4d0

It was great! But tell me how to avoid the issue in the first place?
The issue was that the email id corresponding to the account whose password had to be changed was passed in the request and the backend didn’t validate the email id.
Therefore, the issue could be fixed using the following countermeasures:
- Check if the email id supplied in the request belongs to the logged-in user.
- Do not pass the email id in the request. Rely on the account number JWT token and use it to update the user’s profile.
Stay Safe and Happy Hacking!
References:
메타데이터
- post_id
- 46e8728dc705
- slug
- api5-2019-broken-function-level-auth-ii-46e8728dc705
- url
- https://medium.com/pentester-academy-blog/api5-2019-broken-function-level-auth-ii-46e8728dc705
- canonical_url
- https://medium.com/pentester-academy-blog/api5-2019-broken-function-level-auth-ii-46e8728dc705
- author_url
- https://medium.com/@shivam_bathla
- status
- ok
- fetched_at
- 2026-08-12 06:39:12