OpenEMR - Remote Code Execution in your Healthcare System
A couple interesting issues in OpenEMR leading to unauthenticated remote code execution and file disclosure.
The file disclosure bug starts from the fact that the installer/setup functionality can still be triggered after installation. A complete reinstall is not possible, but it is possible to execute some specific methods of the setup process.
The setup.php
page will create a new Installer
object filled with the configuration information from $_REQUEST
. It will then execute some method based on the current $_POST['state']
. State will lead to the displayNewThemeDiv
method being executed, this method will make a MySQL query using the configuration information derived from $_REQUEST
. So an attacker can query a server they control. A rogue MySQL server can potentially read files from the client side of the connection. This is to support a LOAD DATA
query with a LOCAL INFILE
modifier. By default this is not enabled but as OpenEMR makes legitimate use of the functionality it should be enabled on the PHP server, so the MySQL server can make requests for files of the client.
The second set of issues abuses some existing functionality (a file upload) along with a reflected XSS and LFI due to path traversal for code execution. The reflected XSS is fairly straightforward but also interesting:
<a onclick="dopopup('<?php echo $_SERVER['REQUEST_URI'] . '&display=fullscreen&encounter=' . $encounter; ?>');"
href="JavaScript:void(0);"></a>
You can see that is reflects the REQUEST_URI
into the onclick
handler, normally any '
or "
would be urlencoded in this and so no escape possible, but the author notes that you can include HTML entities within the onclick handler that will be decoded by the time the JavaScript inside is processed. So one can escape the inner single-quoted string by including an '
and then inject their JavaScript.
The directory traversal and local file include is rather traditional. It includes a file based on a $_GET
paramater and appends .plugin.php
to it. Without checking for traversals its possible to load the file from other locations, and combined with the file upload functionality (the post does not detail the intented purpose of the file upload) one can upload a PHP file with the correct name and have it be included.