Penetration Test Report (InsecuritySH-PrivacyCanada): Openemr insecurity

Project Insecurity - insecurity.sh
OpenEMR v5.0.1.3 - Vulnerability Report
TABLE OF CONTENTS
1.0 - Abstract 3
1.1 - Methodology 3
1.2 - Credits 3
1.3 - Disclosure Timeline 3
2.0 - Patient Portal Authentication Bypass 4
3.0 - Multiple instances of SQL Injection 7
3.1 - SQL Injection in find_appt_popup_user.php 8
3.2 - SQL Injection in add_edit_event_user.php 8
3.3 - SQL Injection in Anything_simple.php 9
3.4 - SQL Injection in forms_admin.php 10
3.5 - SQL Injection in search_code.php 11
3.6 - SQL Injection in find_drug_popup.php 12
3.7 - SQL Injection in find_immunization_popup.php 12
3.8 - SQL Injection in find_code_popup.php 13
3.9 - SQL Injection in de_identification_screen2.php 14
3.10 - Remediation Recommendations 14
4.0 - Unauthenticated Information Disclosure 15
4.1 - admin.php 15
4.2 - sql_patch.php 15
4.3 - setup.php 16
5.0 - Unrestricted File Upload 17
6.0 - Remote Code Execution 18
6.1 - RCE in sl_eob_search.php 18
6.2 - RCE in fax_dispatch.php 20
6.3 - RCE in faxq.php 21
6.4 - RCE in daemon_frame.php 21
6.7 - Remediation Recommendations 21
7.0 - CSRFs 21
7.1 - CSRF to RCE Chain 23
8.0 - Unauthenticated Administrative Actions 24
9.0 - Arbitrary File Actions in import_template.php 25
9.1 - Arbitrary File Write 25
9.2 - Arbitrary File Read 26
9.3 - Arbitrary File Deletion 27
2
1.0 - Abstract
OpenEMR is the most popular open-source electronic medical record and medical practice
management solution. This report details the vulnerabilities our team uncovered in
OpenEMR. Some examples of vulnerabilities detailed below include a portal authentication
bypass, multiple instances of SQL injection, multiple instances of remote code execution,
unauthenticated information disclosure, unrestricted file upload, CSRFs including a CSRF to
RCE proof of concept, and unauthenticated administrative actions.
1.1 - Methodology
We set up our OpenEMR testing lab on a Debian LAMP server with the latest source code
downloaded from Github (h​ ttps://github.com/openemr/openemr)​ . The vulnerabilities
disclosed in this report were found by manually reviewing the source code and modifying
requests with Burp Suite Community Edition, no automated scanners or source code
analysis tools were used.
1.2 - Credits
Brian Hyde (h​ ttps://www.linkedin.com/in/brian-hyde/​)
Cody Zacharias (​https://www.linkedin.com/in/codyzacharias/)​
Corben Leo (​https://www.linkedin.com/in/corben-leo/​)
Daley Bee (​https://www.linkedin.com/in/daleybee/)​
Dominik Penner (h​ ttps://www.linkedin.com/in/dominik-penner/​)
Manny Mand (h​ ttps://www.linkedin.com/in/mannymand/​)
Matthew Telfer (​https://www.linkedin.com/in/matthew-telfer-bb2325167/)​
1.3 - Disclosure Timeline
July 7th, 2018 - Reached out to vendor
July 9th, 2018 - Made first contact, agreed to a one-month public disclosure release date
July 20th, 2018 - Vendor pushes an update fixing the vulnerabilities
August 7th - Public Release Date
3
DISCOVERIES
2.0 - Patient Portal Authentication Bypass
An unauthenticated user is able to bypass the Patient Portal Login by simply navigating to
the registration page and modifying the requested url to access the desired page. Some
examples of pages in the portal directory that are accessible after browsing to the
registration page include:
- add_edit_event_user.php
- find_appt_popup_user.php
- get_allergies.php
- get_amendments.php
- get_lab_results.php
- get_medications.php
- get_patient_documents.php
- get_problems.php
- get_profile.php
- portal_payment.php
- messaging/messages.php
- messaging/secure_chat.php
- report/pat_ledger.php
- report/portal_custom_report.php
- report/portal_patient_report.php
Normally, access to these pages requires authentication as a patient. If a user were to visit
any of those pages unauthenticated, they would be redirected to the login page.
Severity: ​High
4
Walkthrough:
Figure 1: Patient Portal Registration Page
From the Patient Portal login page, navigate to the patient registration page, then modify
the URL to navigate to the page you would like to visit such as add_edit_event_user.php, a
page that would allow an unauthenticated user to book appointments in the OpenEMR
system.
Figure 2: /portal/add_edit_event_user.php
5
Impact:
The photo below demonstrates the severity of the vulnerability by performing the
authentication bypass to access get_profile.php which displayed a random customer profile
from a real target. All the information, minus the first name, have been redacted to protect
the identity of the patient.
Figure 3: [redacted]/openemr/portal/get_profile.php
Vulnerable Code:
//continue session
session_start();
//landing page definition -- where to go if something goes wrong
$landingpage = "index.php?site=".$_SESSION['site_id'];
//
// kick out if patient not authenticated
if (isset($_SESSION['pid']) && isset($_SESSION['patient_portal_onsite_two'])) {
$pid = $_SESSION['pid'];
} else {
session_destroy();
header('Location: '.$landingpage.'&w');
exit;
}
//
6
$ignoreAuth=true; // ignore the standard authentication for a regular OpenEMR user
​
require_once(dirname(__file__) . './../interface/globals.php');
F​ igure 4: verify_session.php - Lines 42-48
$_SESSION['patient_portal_onsite_two'] = true;
$_SESSION['authUser'] = 'portal-user';
$_SESSION['pid'] = true;
F​ igure 5: account/register.php - Lines 16-19
Verify_session.php only checks whether “pid” & “patient_portal_onsite_two” are set.
Register.php shows us that these are actually being set upon visiting. This is highly
concerning, as this now allows an unauthenticated attacker to leverage a couple of the SQL
Injection vulnerabilities mentioned below, compromising all records in the database.
Cause:
The only times that this authentication bypass works, is if the variable “$ignoreAuth” is set
to true. Conflicts begin to arise when the traditional authentication mechanism is loaded
(auth.inc). In globals.php, we will notice that auth.inc only gets loaded if $ignoreAuth is set
to false. There are multiple instances in OpenEMR where $ignoreAuth is N​ OT​ set to false.
if (!$ignoreAuth) {
include_once("$srcdir/auth.inc");
}
F​ igure 6: interface/globals.php - Lines 566-568
Something to also note, $ignoreAuth is set to true in the file verify_session.php, therefore,
every file that includes verify_session.php ignores authentication as well.
3.0 - Multiple instances of SQL Injection
SQL Injection is a exploitation technique that consists of inserting a SQL query through the
input data. A SQL Injection attack can be leveraged to view data from a target database or
leveraged to perform a variety of other things i.e. perform database functions. Below are
details about the 8 SQL injections we identified in OpenEMR.
7
3.1 - SQL Injection in find_appt_popup_user.php
SQL injection in find_appt_popup_user.php is caused by unsanitized user input from the
catid​ and p​ roviderid ​parameters. Exploiting this vulnerability requires authentication to
Patient Portal; however, it can be exploited without authentication when combined with the
Patient Portal authentication bypass mentioned above.
Severity: ​High
Vulnerable Code:
if ($input_catid) {
$srow = sqlQuery("SELECT pc_duration FROM OpenEMR_postcalendar_categories WHERE
pc_catid = '$input_catid'");
​ ​
if ($srow['pc_duration']) {
$catslots = ceil($srow['pc_duration'] / $slotsecs);
}
}
F​ igure 1: find_appt_popup_user.php - Lines 105-110
$query = "SELECT pc_eventDate, pc_endDate, pc_startTime, pc_duration, " .
"pc_recurrtype, pc_recurrspec, pc_alldayevent, pc_catid, pc_prefcatid, pc_title " .
"FROM openemr_postcalendar_events " .
"WHERE pc_aid = '$providerid' AND " .
​ ​
"((pc_endDate >= '$sdate' AND pc_eventDate < '$edate') OR " .
"(pc_endDate = '0000-00-00' AND pc_eventDate >= '$sdate' AND pc_eventDate <
'$edate'))";
$res = sqlStatement($query);
Figure 2: find_appt_popup_user.php - Lines 164-170
Proof of Concept:
http://host/openemr/portal/find_appt_popup_user.php?catid=1' AND (SELECT 0
​
FROM(SELECT COUNT(*),CONCAT(@@VERSION,FLOOR(RAND(0)*2))x FROM
INFORMATION_SCHEMA.PLUGINS GR