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 in any application, you have to understand it inside-out, sometimes even mapping out the functionalities in a written form. 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 patterns. 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.
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 controller's folder, I found a Backend_api.php file that caught my attention because it clearly ruled out 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 currently 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
POST /index.php/backend\_api/ajax\_get\_calendar\_events HTTP/2
Cookie: csrfCookie=f93f18637dfad4c1fde27c7c84115358; ea\_session=redacted
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
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, which can be used 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 patched, 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 easily detect this vulnerability using automated scans, I personally notified a couple of healthcare companies that were using the software to schedule COVID-19 vaccines, and the story was covered by The Daily Swig as well.
Thanks for reading,