Overview

During a recent perimeter assessment engagement, SilentGrid was tasked with the objective of gaining access to personally identifiable information (PII) data from a client’s external environment. This client happens to be a healthcare service provider.

Ultimately, SilentGrid was able to achieve the objective by exploiting an unauthenticated blind SQL injection vulnerability to gain access to an application’s underlying database, which then allowed sensitive files to be downloaded. Somewhat surprisingly, SQL injection vulnerabilities are still prevalent, as evidenced by the following CVE details links here and here.

While no advanced or novel techniques were utilised, this blog post aims to highlight the benefits of open-scoped security assessments and regular penetration testing, particularly when ensuring the protection of data privacy is a core premise of a business’s service.

Discovering Unauthenticated Web Pages

Following an enumeration of Internet-exposed resources and services related to the organisation, SilentGrid discovered an interesting web application that allowed users to access sanitised medical images over the internet.

This application, which we shall refer to as VulnerableOne, was developed to receive medical files from an imaging provider’s PACS (Picture Archiving and Communication System). PACS systems use the Digital Imaging and Communications in Medicine (DICOM) standard to store, transmit, and communicate medical images and data. When a medical image is acquired using a device such as a CT or MRI scanner, the image is typically saved in the DICOM format.

Upon receiving an image from a PACS system, the VulnerableOne application removes or redacts specific DICOM metadata, which could include sensitive patient details such as full names, health numbers, and birth dates. According to the application developers, this allowed the finalised image(s) or cine-loops to then be safely shared with friends and family e.g., on social media platforms.

Browsing to the application's main page revealed a login page that accepted a single parameter (key) for authentication.

A HTTP request for the login page

After a few failed brute-force attempts against this page, SilentGrid decided to identify other web pages that were accessible without authentication.

Identifying unauthenticated web pages

While the contents of the .DS_Store file contained references to cached PHP files (for which public disclosure was likely unintentional), this discovery was unable to be leveraged further. However, of more interest were the view.php and verify.php web pages, which were freely accessible to anyone on the internet. Both of these pages also accepted a single parameter for input, utilising the POST method for data transmission.

Based on the fragmented functionality present within each page, it was reasoned that access should only have been allowed for authenticated users. Yet more significant than the omission of secure access controls was that both of these pages were found to be vulnerable to blind SQL injection.

Confirming the Vulnerability

For brevity, a deep dive into the intricacies of SQL injection is not covered in this blog post; however, an informative resource that describes the vulnerability and impact in excellent detail can be found here.

In contrast to standard SQL injection vulnerabilities, which allow the requested data to be retrieved within the rendered web page, in a blind SQL injection attack, no data is returned in-band as a result of the injected payload. Therefore, successful exploitation requires the use of inference techniques to exfiltrate data.

One method to infer data is by introducing execution delays in the injected subqueries to consume time, commonly known as time-based attacks. In MySQL, this can be achieved using database-native functions such as the sleep() function.

To demonstrate this technique, SilentGrid first evaluated the application's standard response time after submitting a request to the verify.php web page, which was equal to approximately four (4) seconds.

A standard query response time

Next, to induce an artificial delay of nine (9) additional seconds, the following payload was injected into the form-vulnerable parameter:

silent'''%2b(select*from(select(sleep(9)))a)%2b'

As shown in the figure below, the induced delay was observed in the new response time, which confirmed the presence of an (unauthenticated) blind SQL injection vulnerability.

Inducing a delayed response time

Leveraging Time-Delays

To exfiltrate information from the database via a blind SQL injection attack, it was necessary to construct if() and sleep() statements that induced an artificial delay to retrieve output on a letter-by-letter basis. The heavily simplified pseudocode that resembles this logic is as follows:

IF firstChar equals "a" THEN
    Wait for 3 seconds
ELSE
    Return immediately
END IF

IF secondChar equals "a" THEN
    Wait for 3 seconds
ELSE
    Return immediately
END IF

To expedite the exploitation process based on the above time-delay technique, sqlmap was used to eventually gain access to the application and its data. The various enumeration methods and attacks performed by SilentGrid are detailed in the following section.

Exfiltrating Data

Enumerating the database properties revealed that the current redacted_root user did not appear to have elevated database administrator (DBA) privileges.

Retrieving database properties and tables

From a security perspective, this configuration followed the principle of least privilege, whereby users are given the minimum level of access or permissions required to perform their tasks. In this case, this involved restricting privileged actions typically associated with those of a DBA.

As an aside, based on the server header directive, it was inferred that the underlying operating system version was either Linux Ubuntu 16.04 or 16.10, both of which no longer receive standard security maintenance support.

SilentGrid proceeded to enumerate the privileges of the redacted_root database user and discovered it had only fewer permissions in comparison to the administrator account. As such, it appeared possible to execute a range of malicious actions on the production database.

Enumerating database user permissions

After inspecting various tables within the database, a limited number of rows from the m_users table were extracted using the below sqlmap command.

sqlmap -r verify.req --batch --dbms=mysql -p "form-vulnerable" --time-sec=3 --risk 3 --level 3 --dump --sql-query="silent'''%2b(select*from(select(sleep(5.5)))a)%2b'" --test-filter=SLEEP -T m_users -D production --keep-alive --no-cast --predict-output -C id_users,keymd5,use_patient_name,dicom_zip_password --start 1 --stop 25

Located within this table were multiple hashed (password) keys required for authentication with the application.

Extracting hashed key values from the database

These hashes were generated using the weak MD5 algorithm and furthermore not salted, which made them highly susceptible to brute-force (mask) or dictionary attacks. This attack was performed using hashcat with the following command:

hashcat -a 3 -m 0 key.md5  -1 "?l?u?d" "?1?1?1?1?1?1?1?1" --increment --increment-min 6 -o cracked.txt -O

As shown in the figure below, several clear-text keys were trivially recovered in under a minute.

Recovering clear-text (password) keys

Now in possession of several password keys, SilentGrid was able to successfully log in to the application. Please note, screenshots of the application’s graphical interface are unable to be shared due to confidentiality considerations.

Digging for Sensitive Data

As stated in the application’s terms and conditions, where possible, the VulnerableOne application de-identifies images for users of the service by removing their DICOM data within images or cine-loops.

Based on the observed data within the application while authenticated, this statement so far appeared to be true and was supported by the existence of anonymised row values and non-sensitive table names within the MySQL database. However, knowing that the application first received medical imaging data from a provider’s PACS, it was theorised that references to the raw images existed prior to the de-identification process.

Eventually after further inspection, a table named m_dicom_zip_requests was identified that revealed various interesting attributes relating to previously shared files.

Metadata of previously shared files

After analysing the retrieved information, a valid URL was reconstructed that allowed a patient's raw files to be downloaded. It was worth noting that, despite the URL(s) containing a complex identifier as a defence-in-depth measure, due to missing access controls, the uploaded DICOM files could be downloaded without authentication.

Once extracted and opened using an appropriate software viewer, the metadata within the DICOM files was found to disclose patient data such as their full name, health care number, and date of birth. Other sensitive details, such as the patient's weight and address, also appeared to be potentially susceptible to disclosure.

Patient PII disclosed in metadata fields

As exploiting the blind SQLi vulnerability was subject to time constraints due to the inherent delay in the attack process, only a limited number of file archives were able to be downloaded and inspected.

Remediation Takeaways

Despite having measures in place to anonymise a patient’s identity and their PII data, the application was found to be vulnerable to an unauthenticated SQL injection attack that nullified its privacy safeguards.

The primary remediation for a SQL injection vulnerability is to implement prepared statements, which help to separate user input from the actual SQL query. By doing so, the risk of malicious input manipulating the query structure is mitigated.

Lastly, the implementation of several additional controls could have either prevented (in the case of restricting access to the vulnerable pages) or significantly reduced the impact of this vulnerability. These include:

  • Enforcing authentication on all sensitive web pages and files
  • Enforcing complex user passwords
  • Avoiding the use of weak hashing algorithms (MD5)
  • Salting passwords