How to breach sensitive information from broken access controls
In this case study, we will discuss how by exploiting broken access controls, we were able to access and modify information about end users of one of our client’s web applications. (The client has been anonymised.)
Broken access controls are one of the most common vulnerabilities found in web applications. They are listed in the OWASP Top 10, and can be described simply: access controls define what information users can read, modify and delete. Admins have greater permissions and powers than regular users. But broken access controls allow regular users to read, modify or delete information that they should not be able to, including information that admins can. An attacker might exploit this vulnerability to access sensitive information, resulting in a data breach, or use information such as usernames and passwords to escalate their privileges, causing even greater damage en route to their objective. In this case study, we will discuss how by exploiting broken access controls, we were able to access and modify information about end users of one of our client’s web applications. (The client has been anonymised.)
What does the app do and what information does it store?
Our client provided risk questionnaires to financial organisations via a web application. They wanted to ensure that the sensitive information stored in these applications could not be accessed by unauthorised users. The target website and two APIs were designed for the organisation to administer their questionnaires using partner resellers. Our penetration testers discovered that by correctly exploiting a series of vulnerabilities, any user could gain access to the database stored by the client, including the data stored on all partner resellers who used its product, and even the end-users themselves, who took such questionnaires. Without using any complex tools or attack techniques, any user could exploit flaws in the application’s architecture and code to escalate their privileges to be able to modify, exfiltrate or delete the client’s central database of users. Like many directories, their network used a tree structure with a root-and-branch system. This structure also influenced users’ access permissions. The client was at the root, and admins there could create organisations for each customer on new branches, with users and admins. In a customer’s organisation, admins could also create sub-organisations on lower branches for their own clients, which also had users and admins. The basic idea is that users should not be able to perform the same functions as admins, nor should they be able to access or modify anything from organisations higher up the branch than they are (i.e., parent organisations).
Can I do that? Who’s checking?
Our penetration testers were given a login to the web application. The web application was used by the client’s resellers – the organisations and sub-organisations they sold to. Our penetration testers began to test the two APIs that the application interacts with in order to perform certain tasks. One API handled the creation of client accounts (sub-organisations) while another handled the creation of new users and their logging in. This second API is primarily for users of the app. The API used its own log-in system, with an account for each organisation. When logging in, the web server creates an open session, logged in with the unique ID of that organisation, and the web server sends the requests to the API in the user’s stead. The API ensures that the user can only view data from their organisation and its sub-organisations. But at what point did the APIs check if the user was an admin, and allowed to create and modify new users and sub-organisations? It emerged that the flaw resided in how the API was designed. The functionality for admin-level users was built into the code on the front-end of the web application. This flaw could be attributed to the developers’ decision to implement all security controls around logins into the user interface of the application itself, which could be easily bypassed by reading the page's code.
Letting it all hang out (in the HTML code)
Our penetration testers then discovered that by reading the HTML source code using developer tools on a web browser, the functions to perform admin-level actions were visible within commented sections. A regular user could remove the comment tags in the HTML code and by refreshing the page, could now see and perform functions that only admin-level users should. This revealed the lack of appropriate access controls. This form of privilege escalation was just the first piece of the puzzle. The second was, how would an attacker use this to further escalate their privileges, and inflict greater damage? Again, design flaws in the API meant that while users could not access or modify details in their parent organisation, they could request data about their own organisation, which was delivered as a JSON object that displayed a unique ID number of their parent organisation. This unique ID number was all the user needed to create a new user inside their parent organisation. By creating a new user in the parent organisation, an attacker could then log in to their parent organisation as that user.
Privilege escalation, one branch at a time
At this stage, an attacker could repeat the process: request information about their own organisation, then create a new user in the parent organisation using the unique ID, then login as that new user to move one step further up the branch to the root. In this way, they would eventually be able to create a user and log in at the root of the branch i.e., as if they were the client themselves, with access to their full database of clients, including the names and email addresses. Any attacker could then easily exfiltrate the entire database, modify or delete it. The attack chain was a perfect storm that combined four factors:
- The web application should control user permissions so that regular users cannot modify permissions or users other than themselves, and they cannot create admin-level users or reset users created by someone. However, the application instead just hides those forms and elements of the page from regular users.
- The security controls were embedded into the code for the front-end of the application, meaning users can easily access and read it using developer tools on any web browser.
- The main API uses its own log-in system, with an account for each organisation. This system is not found in the application. Instead, the web server has an open session identified as the user’s organisation and sends the requests to the API. This server acts as an intermediary between the application and the API, which takes user requests and "translates" them to the URLs and parameters of the API, using the token and secret that the API uses for authentication. However, this token and secret are all the user needed to make request as an organisation in the API, which makes no distinction between users.
- This API allows you to create new users for any organisation, so long as you provide a valid ID.
When you combine these four factors, any logged-in user can start by giving themselves administrator permissions within their organisation, or directly creating an administrator user in the parent organisation, then log out and back in with their new user, and view all the data from the parent organisation, and then repeat this process. This, along with the other exploited security flaws, were examples of broken access control, where users are able to perform actions or interact with functions which should be restricted based on their access privileges.
Our recommendations
Our recommendations to the client began with the code and architecture of the application. First and foremost, any important actions taken by the user must be checked by the application's back-end to ensure that the user has the correct permissions. Secondly, we advised users should not be able to create users in organisations outside their own. Controls should be added to the API to check the organisation of the requesting user and if it's allowed to perform this action. This would ensure that users could not escalate their privileges, or modify users in another organisation in their branch Finally, if user-level access controls cannot be placed on the web application, instead redesign the API's authorisation control to also incorporate controls between different user roles. It is correct not to send these to the user and instead use a "proxy" web server, but this would mean that the application should add the missing control to distinguish between "administrator" and "adviser" user.
Related articles
Claranet’s top 10 web application vulnerabilities found in 2024
How to secure your applications from the ground up
The art of deception: social engineering in red teaming
Security advisory: exchange server 0-day - ProxyNotShell
Security advisory: critical Fortinet authentication bypass vulnerability exploited in the wild