I like Broken Access Control vulnerabilities.
If you are a security researcher, It is very likely at some point you heard the golden advice: know your target. Before you will be able to identify significant security bugs on any application, you have to understand it inside-out, sometimes even mapping out the functionalities in a written form. And this is particularly true for BAC (Broken Access Control) bugs because while for other vulnerabilities automated detection is possible (XSS for example), BAC doesn’t come out with static code analysis.
It may be detected with fuzzing – but most of the time, the most interesting findings come out from manual research. And that’s why I like it.
A couple of months ago I was working on a booking system for a pharmaceutical company, and I decided to use Easy Appointments after some research about the open-source options available. Easy Appointments turned out to be a great choice for usability and structure, but it also contained a very dangerous security bug that was exposing PII (Personally Identifiable Information) to unauthenticated actors.
PII exposures are always highly coveted bugs for criminals because the data obtained can be used for any sort of malicious purpose, like identity theft, account takeovers, phishing, scamming, and so on.
In this blog post, we will go through the process that brought me to identify and patch the vulnerability, even if I wasn’t actively hunting for it.
The target in brief
Easy Appointments is a web application based on CodeIgniter, a powerful and lightweight PHP framework based on MVC pattern. Compared to other similar frameworks (like Laravel), I consider CodeIgniter to be more liberal because it doesn’t provide some basic features like authentication – which you have to code up yourself. While there are some built-in classes for database abstraction, routing, and data modeling, the application logic is mainly in the hands of the developer.
This is of course exciting and challenging, but also pretty error-prone.
Speaking about security, CodeIgniter has many built-in features to avoid XSS (cross-site scripting), CSRF (cross-site request forgery), a class to manage sessions securely, and many others. But of course, nothing can protect you when there is an unprotected API and this was my case.
Modern development is heavily based on 3rd parties, which are considered secure especially if they are open-source and community contributed. But that doesn’t mean you can’t perform at least a general security overview, even just to understand more of the logic you are gonna build on.
A good starting point is to understand the folder structure, which Easy Appointments inherits from CodeIgniter and looks like this:
If you have some knowledge about MVC (model view control) patterns, you know that access-related issues are more likely to be found in controllers, and that was where my eye immediately went.
In the controllers folder, I found a Backend_api.php file that caught my attention because it was clearly ruling some interaction with the backend of the application, which is where important data resides. Reading the first 100 lines of code was enough for me to understand something was wrong: in the ajax_get_calendar_events() method the response object was built before checking user permissions.
This was a big red flag for me. The code goes on (check it if you are curious) with some logic that cleans up that object if the current logged user is low privileged, showing only the appointments the user is supposed to view – but I still couldn’t understand why there was no permission check before pulling that data and storing it in a variable. I set up a development instance and started to navigate it with my Burp proxy active, in order to be able to review the HTTP traffic later.
The ajax_get_calendar_events() method was used in the backend to populate the calendar of the current logged-in operator, and was passing just 3 params:
- start date
- end date
- CSRF token
REQUEST POST /index.php/backend_api/ajax_get_calendar_events HTTP/2 Host: REDACTED Cookie: csrfCookie=f93f18637dfad4c1fde27c7c84115358; ea_session=redacted User-Agent: REDACTED Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Content-Length: 82 Origin: https://redacted Referer: https://redacted Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin Te: trailers csrfToken=f93f18637dfad4c1fde27c7c84115358&startDate=2022-02-01&endDate=2022-02-01
My first attempt was to remove all the cookies from the request, but I got a 403 Unauthorized response. But wait, what if that 403 was due to the missing CSRF token and the session was still not validated, as I spotted in the code? Bingo!
The problem here, is that the CSRF token is not an authentication system, is meant to avoid unwanted submissions and in fact, is available to any unauthenticated user by just visiting a public page of the web app. The attack scenario is now clear, and it is easily exploitable.
An attacker could just grab his CSRF token from the app homepage, and then start querying the unprotected API endpoint (/index.php/backend_api/ajax_get_calendar_events) lopping through the dates, and downloading all the appointments/users data stored in the target system. To make things even worse, the HTTP response contained all kinds of juicy information that can be harmfully used:
- all the customers provided details (full name, email, phone, address, etc..)
- the appointment hashes, enough to delete appointments and break data integrity
- the service provider data and his hashed passwords (impact unknown)
Aware of the fact that I was in front of a high severity vulnerability, I decided to report it immediately using all the channels available:
- I submitted a report to Huntr, which is a specific platform for open-source software protection
- I shot an email to Alex Tselegidis, the Easy Appointments main developer, explaining the vulnerability and proposing a patch
I have to say that Alex was really responsive and cooperative. He told me that while the patch was easy, he had to fix all the previous Easy Appointments versions and provide a way for non-technical users to easily update the software, which he did. He also performed a full security review fixing other minor security issues.
The patch was ready in about one month, not the fastest but I understand it was challenging. Here is the disclosure timeline:
- 30 Jan 2022 – vulnerability notified to Huntr and Alex
- 3 Feb 2022 – the vulnerability was validated and confirmed
- 8 Mar 2022 – a patch was released to fix Easy Appointments 1.4.3 and all previous versions
I was also awarded a small bounty from Huntr and most importantly, I was assigned CVE-2022-0482. Thank you so much, folks!
Are we safe now?
Unfortunately, I think we are not. While the software is now secure, the problem is that Easy Appointments still hasn’t an automatic update or notifications system (like the most popular WordPress/Joomla/Drupal), so the reality is that the biggest part of the instance on the web are still vulnerable, and data are still at risk.
I wrote a Nuclei template to help security researchers to easily detect this vulnerability using automated scans. I also personally notified a couple of Non-Governmental Organisations that were using the software for booking COVID19 vaccines. At this stage, I think it’s all I can do.
In the nearest future, I hope you can use the OpenCIRT vulnerability notification framework, to notify as many companies as possible and make the whole web more secure!