Exploitation

POPping WordPress

Fun with PHP deserialization and some accidental WordPress bugs.

A few months ago I was putting together a blog post on PHP deserialization vulnerabilities. I decided to look for a real target that would allow me to supply data to the PHP unserialize() function to use for demonstration purposes. I downloaded a load of WordPress plugins and started grepping through the code for calls to unserialize() to find the following example:

The plugin in question made a clear text HTTP request and passed the response to unserialize(). In terms of a real attack it wasn’t the greatest entry point but if I could trigger this code it would be trivial to supply input to unserialize() this way so it was good enough!

Attacking PHP Deserialization

Briefly, deserialization vulnerabilities occur when an attacker can supply data to an application which in turn converts that data into runtime objects without proper validation. If controlling this data allows an attacker to control properties of the resulting runtime objects then the attacker can manipulate the flow of execution of any code that uses those object properties and potentially use it to launch an attack. This is a technique known as property oriented programming (POP). A POP gadget is any snippet of code that can be controlled in this way. Exploitation is achieved by supplying specially crafted objects to an application such that when those objects are deserialized, some useful behaviour is triggered. For more information see my blog post on Attacking Java Deserialization (the general concepts apply regardless of the underlying technology).

In the context of PHP applications the most well known and reliable source for POP gadgets is the __wakeup() method of a class. If a class defines a __wakeup() method then this method is guaranteed to be called whenever an object of that class is deserialized using the unserialize() function. Another reasonably reliable source for PHP POP gadgets is the __destruct() method which is almost guaranteed to be called when the deserialized object goes out of scope, for example when the script has finished executing (unless e.g. a fatal error occurs).

In addition to the __wakeup() and __destruct() methods, PHP has a whole load of other “magic methods” that can be defined in a class and may also be called following deserialization depending on how the deserialized object is used. In a larger or more complex application it can be difficult to trace where a deserialized object ends up and how it is used or what methods are called on it. It can also be difficult to identify which classes can be used in a PHP deserialization exploit because the relevant files may not have been included at the entry point or a class auto loader could have been registered to muddy the waters further.

Universal PHP POP Gadget

To simplify this process I wrote a PHP class that defines all magic methods and writes the details to a log file when any of those magic methods are called. Particularly interesting are the __get() and __call() magic methods which will be called if the application attempts to get a non-existent property or call a non-existent method of the class. The former can be used to identify properties that can be set on the payload object in order to manipulate the code that gets and uses those properties. The latter can be used to identify non-magic methods that can be triggered using a POP gadget (and can themselves hence be used as POP gadgets).

The __wakeup() method of the class also uses the PHP function get_declared_classes() to retrieve and log a list of declared classes that an exploit payload can use (although this wont report classes that aren’t currently declared but which can be auto-loaded).

Instrumenting PHP

By saving the above code to a PHP file we can insert an include '/path/to/UniversalPOPGadget.php' statement into any other PHP script and make this class available for use. The following Python script will find all PHP files in a given directory and prefix the files with this statement, effectively instrumenting the application so that we can provide serialized UniversalPOPGadget objects to it and use them to investigate deserialization entry points.

Analyzing a Deserialization Entry Point

Back to that original WordPress plugin code snippet with the call to unserialize(), I had no idea how to actually trigger the call to unserialize(). All I knew was that at some point the plugin should make a HTTP request to http://api.wordpress.org/plugins/info/1.0/. I used the Python script above to instrument the WordPress and plugin code, then I modified the hosts file on the server to point api.wordpress.org back at the same server. The following code was placed in the file /plugins/info/1.0/index.php in the web root in order to deliver a UniversalPOPGadget payload:

With this instrumentation in place I started using the WordPress instance as normal, paying particular attention to all functionality relating to the target WordPress plugin whilst watching for the UniversalPOPGadget log files. Soon enough some log files were generated including the following (the large list of available classes has been removed for brevity):

The log file shows that, after this UniversalPOPGadget object was deserialized, the application attempted to get or check for the existence of several properties (sections, version, author etc). Firstly this tells us that with this particular entry point we can use code defined in any __get() or __isset() method of any available class as a POP gadget (hence we should review those methods for useful code). Secondly it reveals several properties that the target application attempts to get. Those properties are almost guaranteed to influence the flow of execution and hence are likely to be useful in exploitation.

Sections?

The log file above shows that the very first interaction with the deserialized object is an attempt to get the property named sections.

Going back to the original target plugin, the first thing it did following the call to unserialize() was to check for the existence of the property named ratings.

This log was not generated by the third-party plugin that I was originally targeting!

Accidentally POPping WordPress

A quick grep over the WordPress code for the HTTP URL mentioned above revealed that the request was issued by the WordPress plugins API found in the file wp-admin/includes/plugin-install.php. Skimming over the code it wasn’t immediately obvious exactly how the deserialized payload object was used or where exactly this HTTP request and subsequent call to unserialize() was triggered from. I continued clicking around the WordPress admin interface and found that the logs were being generated from the main dashboard, the Updates page, and the Plugins page. Reloading these pages allowed me to trigger the target HTTP request and supply arbitrary data to unserialize().

I logged some of the HTTP requests WordPress was issuing and sent them on to the real api.wordpress.org in order to capture sample responses. The responses were serialized objects of the type stdClass. More importantly, the sample responses gave me an exact list of properties that WordPress expected to receive, each of which could potentially be used to manipulate the flow of execution of some core WordPress code. I modified my faked api.wordpress.org to return serialized objects based on the real responses I’d captured. The following is a cut-down example of this:

I started modifying the properties of these objects and refreshing the relevant WordPress pages to see what (if any) effect the modifications had on the resulting page. In several cases WordPress used HTML encoding to prevent HTML/JavaScript injection, however I eventually found several fields in which I could insert arbitrary HTML and JavaScript. Bear in mind this happens from within the administrative interface. An attacker who is able to perform a MitM attack or spoof DNS to a WordPress site can potentially exploit this to achieve remote code execution if an admin logs in and views the Updates or Plugins pages.

After some quick and dirty JavaScript and Python scripting I had a working proof of concept exploit. The PoC caused the WordPress admin interface to display a badge next to the Updates and Plugins menus indicating that there were updates available (even when there were not). This is likely to encourage an admin to click on those links to review and potentially install those updates. If an admin does click on either link then a JavaScript payload is injected into the page which adds a new administrator uses and injects a basic PHP command shell into the index.php of the active WordPress theme.

In most cases this PoC attack would be enough to achieve code execution, however I also found that I could attack the click-to-update functionality of the WordPress admin interface in a similar way by sending a false plugin update to WordPress which caused it to download a fake plugin update zip file and extract it on the server if the admin clicked the update button.

Translation

Digging into this some more, I noticed that similar HTTP requests to api.wordpress.org were issued by WordPress even without logging in. I started reviewing the WordPress code to work out what was going on here and whether it could be attacked in a similar way and I came across the function wp_schedule_update_checks() in the file wp-includes/update.php.

Twice a day WordPress will call the functions wp_version_check(), wp_update_plugins(), and wp_update_themes(). By default these update checks can also be triggered by issuing a HTTP request for wp-cron.php. I began manually reviewing these functions and modifying the code to log various pieces of data and the outcome of branches and function calls to see what was going on and whether the functions did anything dangerous with the responses from api.wordpress.org.

I eventually managed to falsify several responses from api.wordpress.org in order to trigger calls to $upgrader->upgrade(). The previous false plugin update attack didn’t seem to work here, however. Then I spotted the following comment within the should_update() method:

It turned out that WordPress was attempting to upgrade the translations for the built-in Hello Dolly plugin. Instead of requesting my fake plugin zip archive, it had been attempting to download hello-dolly-1.6-en_GB.zip from downloads.wordpress.org. I downloaded the original file, added a shell.php to it, and hosted it on my fake downloads.wordpress.org site. Next time I requested wp-cron.php WordPress downloaded the fake update and extracted it to wp-content/languages/plugins/, shell and all.

Right before the call to $upgrader->upgrade()  was another comment I liked:

An attacker who is in a position to perform a MitM attack or spoof DNS to a WordPress site can hence perform a zero interaction attack against the auto update functionality and write malicious scripts to the server. Granted, it’s not necessarily an easy attack to perform, but this still should not be possible!

The WordPress team are aware of these issues, however their stance seems to be that it’s intentional behaviour for WordPress to downgrade to a HTTP connection if HTTPS fails in order to allow WordPress sites running on systems with old/broken SSL stacks to update (or install malicious code)…

Caveats/Gotchas

When requesting update details and update archives, WordPress does attempt to connect to api.wordpress.org and downloads.wordpress.org over HTTPS first, however it falls back to using a clear text HTTP connection if that fails for any reason.

“Oh, I don’t trust that SSL certificate, I’ll connect over HTTP instead”

WordPress won’t download update archives from RFC 1918 (internal) or loopback IP addresses such as 10.x.y.z or 127.x.y.z.

WordPress will by default fail to auto-update (and hence not be vulnerable to the above attack) if the WordPress PHP scripts are owned by a different user to that which is used to run WordPress. For example if index.php is owned by the user foo but WordPress runs under the context of the user www-data.

Bounty

For those of you who participate in bug bounties and anyone else who might be interested, these issues (complete with PoC exploit code and videos) weren’t worthy of a bug bounty.

Preventing These Attacks

Until WordPress implement mitigations such as forcing updates over HTTPS, a simple way to mitigate these attacks is to filter outbound HTTP/TCP port 80 traffic from any server running WordPress. In doing so, if WordPress cannot update over an HTTPS connection or doesn’t trust the SSL certificate, it won’t be able to attempt an insecure update over HTTP instead.

Advertisements
Exploitation

Popping Password-“Protected” JMX

The name gives it away, Java Management Extensions (JMX) is a potentially juicy target for attack. One of the ways that a JMX service may be exposed is using Java Remote Method Invocation (RMI), which we can detect using nmap or my tool BaRMIe by looking for RMI registry services (by default on TCP port 1099) which expose an object named jmxrmi, or an object using the class javax.management.remote.rmi.RMIServer or javax.management.remote.rmi.RMIServerImpl_Stub.

Ignoring horrifically outdated/configured versions of Java where RMI is trivially exploitable with Metasploit, Braden Thomas (@drspringfield) did some research into exploiting the JMX RMI service back in 2013 and came up with a way to achieve remote code execution by instructing the service to load and execute code from a remote server that is under the attacker’s control. One of the recommended mitigations was to ensure that the JMX service is password protected.

Open Sesame!

When JMX is exposed over RMI, an object which uses one of the previously mentioned classes is bound to the RMI registry service. A connecting client will connect to the RMI registry service and request a reference to this object. The client then calls the newClient() method on this object to authenticate to the server and acquire an object that allows further interaction with the JMX service.

Let’s play spot the vulnerability.

Hint: it’s a well-deserved and long overdue entry in the OWASP Top 10 2017.

The JMX client supplies credentials to the JMX server in the form of a java.lang.Object, over RMI, which is based on Java’s built-in serialization format.

By calling RMIServer.newClient(Object) or RMIServerImpl_Stub.newClient(Object), an attacker can supply a specially crafted object to the JMX service in place of authentication credentials and potentially achieve remote code execution despite the service being password protected. Oops.

That’s So 2017…

I wrote an exploit for this issue and incorporated it into BaRMIe in September 2017, so why am I blogging about it now? Previously I just announced the exploit in a tweet and left it at that, but recently I was made aware of a JMX RMI deserialization vulnerability where a recommendation was being made to “secure” unpatched environments by setting a password on the JMX RMI service.

Well, if that unpatched environment has suitable gadgets available to it, such as that which was removed in the patch, then exploitation is still possible.

Stop deserializing everything!

Exploitation

Improving the BMC RSCD RCE Exploit

Last week I wrote about how I semi-blindly produced an RCE exploit for the BMC Server Automation RSCD service without access to a test environment. Since then I’ve got my hands on a test environment where I’ve been able to improve the exploit in several ways through further analysis and fuzzing.

The tl;dr; is that I’ve fixed a few bugs through further analysis, debugging, and a little fuzzing/bruteforcing. The exploit can be found over on Github.

Slow Responses

The first issue with the original exploit was that it took a significant time for command output to be returned whereas Nessus seemed to be getting a response much faster or immediately. The fact that there was a consistent delay in getting a response from my exploit, yet the response was correct (command output), implied that the server was waiting for more data and a timeout had occurred so the server simply responded to the request/command that it did receive. I figured there either had to be another length field in one of the payload packets, or that there was an “end of command” or “end of session” packet that the server was expecting. I couldn’t identify any signs of the former so I took a step back to further analyse the Nessus exploit.

I created two Python scripts: a TCP listener script, and a TCP replay script. One could have done the job but I figured two would put me more in control and allow me to better understand the exploit. I ran a minimal Nessus policy against the TCP listener script which output the received packets until Nessus appeared to expect a response. At that point I modified the TCP replay script to replay those packets and output the response from the real BMC RSCD service. Repeating this process a few times revealed that a total of eight packets (not four) were sent during a successful scan/exploitation. Replaying those packets resulted in the BMC RSCD service returning the command output immediately. Combining this with the code I already had to generate packets for arbitrary commands made the exploit much faster and far more usable!

Truncated Command Output

Testing the exploit further I noticed that longer command output was being truncated as demonstrated in the following example of running the “help” command:

My original code to extract command output from the server’s response was as follows:

Here I made the assumption that the first four bytes of the first output packet would contain the total length of the command output. The script then reads from the socket until at least that much data has been received before checking for success.

The check for success was based on comparing multiple success and failure response packets. Successful responses had an ASCII-HEX length field with a value of 1 as shown in the example below:

In unsuccessful responses the same field indicated the length of an error message as shown in the example below:

By adding a few more calls to SSLSocket.read() into the exploit script and outputting the resulting packets I found that the server was in fact returning all of the command output.

I ran this modified exploit a few more times using both valid and invalid commands and commands producing both long and short output in order to capture traffic for analysis. It was immediately obvious from doing so that the last packet containing command or error output was always followed by a packet containing one of the following two strings:

By reading data until one of the above “end of output” packets was received the exploit could consistently read the full command output back from the exploited BMC RSCD service.

The Disappearing Backslash

Further testing revealed some strange behavior with the backslash character. Running the command ‘cmd /c dir C:\Windows’ resulted in output as though the command ‘cmd /c dir C:\’ had been executed.

My immediate thought was that the backslash may need to be escaped, however various tests around this (escaping, double-escaping, forward slashes, quoting etc) all resulted in the same command output. A quick Google search and skim over the BMC documentation showed examples of command lines containing backslashes but apart from that didn’t lead to anything helpful.

Unfortunately my test environment didn’t give me access to the “nexec” command so I couldn’t use that to generate packets for analysis. Based on the documentation I knew that shell operators (such as the pipe symbol) were supported. Further to this I also knew that I could issue an “agentinfo” command to the BMC RSCD service to identify the target operating system. This allowed me to write a hacky workaround for the disappearing backslash issue under Windows as follows:

This uses the Windows shell substring syntax to grab the backslash character from the %windir% environment variable, turning the command ‘cmd /c dir C:\Windows’ into the following (try it):

While this worked and made the exploit generally more usable, it was a dirty hack that would likely fail in some cases.

While this version of the exploit was providing footholds leading to DA on pentests, I decided to get stuck in to the RSCD process with a debugger. I checked over the imports looking for Windows APIs that would allow RSCD to spawn a process, such as WinExec() and CreateProcess(), and set breakpoints on those functions. Running my exploit again triggered a breakpoint on CreateProcessAsUserW().

Interestingly the command line I specified, ‘cmd /c dir C:\Windows’ had become ‘”cmd” /Q /c dir C:’. The RSCD process wasn’t just stripping out part of my command, it was inserting an additional parameter. Through a combination of stepping out of functions in the debugger and setting further breakpoints I eventually hit a breakpoint where my command string was intact in memory and I was able to step through the instructions to identify the point where it was truncated. It appeared as though the backslash was being treated as an escape character and the following two characters were being consumed/interpreted in the process. Some validation may have been going on leading to the string truncation but I didn’t get that far, instead I decided to drop out of the debugger and do some further testing of potential backslash encodings, unsuccessfully.

Having identified that RSCD supports some kind of escape sequences prefixed with the backslash character I decided to throw together a fuzzer/bruteforcer using my existing exploit script. If RSCD/nexec are encoding/decoding backslash characters then the encoded value is unlikely to be more than a few bytes long. I wrote a fuzzer that iterated over all combinations of byte values from 1 to 4 bytes in length and replaced the backslashes in “dir /c C:\Python27\Doc” with each byte sequence before sending that payload to the RSCD service. If the response contained the string “python2714.chm” then the payload was successful and the byte string was printed out.

It didn’t take long for the fuzzer to identify that the byte sequence 0xc1dc would be decoded to a backslash character by RSCD.

Before updating my exploit code I wanted to be sure that this was definitely the work of RSCD and that it wasn’t some buggy/quirky behavior in the way that Windows was handling strange characters in a path. I fired up my debugger again and set a breakpoint on CreateProcessAsUserW() and, sure enough, the correct command line had been passed in.

Thanks for reading! The exploit can be found over on GitHub, feel free to file an issue there or get in touch on Twitter (@NickstaDB) if you run into any issues with it.

Exploitation

RCE with BMC Server Automation

If you’ve ever come across BMC Server Automation during network scanning then you may have seen Nessus flag up a Critical vulnerability titled “BMC Server Automation RSCD Agent Weak ACL NSH Arbitrary Command Execution” (Nessus plugin ID 91947).

Arbitrary command execution! Winner! Search the usual places for an exploit and you might be a little disappointed to only find exploits for CVE-2016-1542 and CVE-2016-1543 which target a different interface (XMLRPC) to enumerate users and change any user’s password. Don’t get me wrong, it’s awesome work, but it’s not the RCE Nessus promised! It’s also not a particularly clean entry point. Changing a root password in this way might lead to an easy win but chances are, without the original password, you’re going to break something, alert someone of the compromise, or upset someone and end your fun early. Either way, changing the root password is certainly not “Arbitrary Command Execution”!

Looking closer at the Nessus report you might see the output from running “cmd /c echo %USERDOMAIN%/%USERNAME%” or “id” against the target host. Clearly Nessus is exploiting the vulnerability and while that might be good enough evidence for a vulnerability assessment, it’s little use if your goal is to go further. With that, I decided to have a crack at producing a working RCE exploit.

Update (04/01/2018): I managed to get my hands on a test environment and improve some issues with the exploit. More details can be found on my follow-up post: Improving the BMC RSCD RCE Exploit.

Grab the PoC from Github.

Exploiting BMC SA without BMC SA

Unfortunately BMC Server Automation is one of those pieces of software that’s well protected by a paywall and I had no access to it at the time. All I had to work from was Nessus, a packet capture of the encrypted exploit traffic, and details of CVE-2016-1542 and CVE-2016-1543 which I believe target the same access control weakness but via the seemingly less useful XMLRPC interface/protocol. I considered a few options to approach this problem:

  1. Work on reversing the binary Nessus plugin format
  2. Write a proxy that can man-in-the-middle connections between Nessus and BMC to capture the exploit traffic
  3. Try to emulate the target service and have Nessus “exploit” it

Given the capabilities of Nessus plugins I figured the first option was likely to take far longer than I wanted to spend on this. I wouldn’t make any progress with option two until I had access to an environment using BMC SA for testing and traffic capturing. On the other hand I had no idea how complex the network protocol might be so option three seemed far-fetched but it was the most practical way to get started and I could potentially work on option two along the way ready for a testing opportunity to come up.

Faking BMC SA to Capture the Payload

I started with a Python script that simply created a TCP server socket, accepted connections, read some data from the client, then closed the connection.

I then created a Nessus policy with only the target BMC plugin enabled and ran a scan against the above Python script to verify that the plugin was going to run and attempt to connect to my script.

I generated a dummy SSL certificate and modified the Python script to upgrade to a TLS connection if the first three bytes read from the client were exactly “TLS”.

Running the Nessus scan again allowed me to capture and dump the first packet Nessus sends over the encrypted connection.

At this point I didn’t think I would make any further progress without access to a real BMC SA environment because I had no idea what the service would normally return and Internet searches weren’t leading to anything useful.

I modified the script to send back what it received from Nessus on the basis that the packet should at least be in the correct format. To my surprise Nessus appeared to ignore the responses returned by the script and with a few more modifications I was able to capture the four packets sent by the Nessus exploit.

Crafting Packets

To achieve arbitrary command execution I needed to be able to generate valid packets containing arbitrary commands. Out of the four payload packets that were captured, the second one contained the command to execute (id in this case).

The value of the first four bytes of the packet matched the length of the remainder of the packet. This held true for the other three captured packets indicating that this is likely a packet length field. Interestingly the command itself was immediately preceded by the number 2 but in ASCII form.

The exact packet bytes shown above were found hardcoded in the binary Nessus plugin file, along with the Windows payload packet. Comparing the two payload packets we can confirm firstly that the payload command should be prefixed with the command length in ASCII form, and secondly that the command length field is in ASCII-HEX form.

Further comparing the two payload packets we can see what appears to be another length field. Bytes 11 and 12 differ between the two packets but their value in both cases is the ASCII-HEX length of the remainder of the packet. The next eight bytes are identical across both payload packets and have the value “00000010” (0x10 = 16), and are followed by 16 bytes that are also identical across both payload packets (“b7;0;2;cae;da4;0”). Finally there are 8 bytes representing the ASCII-HEX length of the payload command itself, followed by the payload command string.

Further comparing this with the other captured packets showed they were all in a consistent format – a four byte binary length field followed by mostly ASCII data. The ASCII data was split into chunks that could have child chunks and/or sibling chunks and each chunk began with an 8-byte HEX-ASCII length field.

The following Python generates a payload packet to execute an arbitrary command:

After blindly putting that together it was awesome to get a chance to test it out and see it working!

References

Exploitation

Analysis of CVE-2017-12628

This morning I spotted a tweet mentioning an “Apache James 3.0.1 JMX Server Deserialization” vulnerability, CVE-2017-12628, which caught my eye because I wrote a generic JMX deserialization exploit which is included in my RMI attack tool BaRMIe. A quick search for more details led to the security release announcement which states that the vulnerability can only be used for local privilege escalation and mentions an upgrade to a library. This sparked further interest because JMX uses RMI and RMI objects can be accessed remotely even when they are bound to localhost because Java binds the object reference to “0.0.0.0”. BaRMIe exploits this using local port forwarding to attack objects that otherwise appear to be bound to local or internal IP addresses.

Analysis

I span up a VM to run Apache James 3.0.0 (3.0.1 fixes the issue) and the first thing I noticed was the file “libs\commons-collections-3.2.1.jar”. We can use ysoserial to generate a POP gadget chain using this library to achieve arbitrary command execution through deserialization.

I started the James server by running “bin/run.sh”, then used netstat on the VM and nmap from my host machine to find that there was one Java RMI port listening externally on the VM.

Using BaRMIe to enumerate this service showed that it was an RMI object service rather than an RMI registry service, so BaRMIe couldn’t attack the service remotely.

Running nmap locally on the VM revealed that the Apache James RMI registry service was bound to 127.0.0.1:9999. I copied BaRMIe to the VM to enumerate this RMI registry and found that the externally facing RMI service was in fact the RMI object service for the JMX object.

Using BaRMIe’s attack mode with the generic JMX exploit and Commons Collections 3.2.1 payload it was possible to exploit this service to execute arbitrary commands leading to a local privilege escalation as advertised. In addition to this it’s also worth noting that, if the server uses an outdated Java runtime environment (<= 6u131, 7u121, or 8u112) then it is also vulnerable to the ysoserial RMI registry exploit.

Remote Exploit

The security release announcement states that this is a local privilege escalation vulnerability only, however, given that the JMX object is exposed externally, I figured this must be remotely exploitable.

Before I continue, I want to make it clear that this is remotely exploitable, however the remote exploit involves a significant network-based brute force attack.

For a quick and dirty proof of concept I used tcpdump on the VM to capture the traffic to the JMX object service whilst running the BaRMIe JMX exploit with the command “touch fooobaaar”.

Back on my host machine I used a quick and dirty Python script to replay the exploit packets.

Replaying the local attack remotely from my host machine was successful, proving that a remote exploit is possible.

As I suspected however, after restarting the Apache James service, this quick and dirty PoC no longer worked. I generated more packet captures for comparison and did some further testing and it appears to come down to some differences in the third outbound packet of the exploit. The following is the first 27 bytes of this packet:

50aced000577229c4cdbcfdd205cf88304129e0000015f4347bba0

The sections highlighted in blue were dynamic, however their values could be extracted from the previous response packet returned by the server. The orange highlighted section is the RMI object identifier which is generated when the server starts up. This value comes from the RMI registry service, which does only listen locally on the server. If an attacker can brute force or otherwise acquire this 8-byte value then a remote root command execution exploit is possible.

Exploitation

Adobe ColdFusion Deserialization RCE (CVE-2017-11283, CVE-2017-11284)

During my research into the Java Remote Method Invocation (RMI) protocol, the most common RMI service that I came across was Adobe ColdFusion’s Flex integration service which is used to support integration between Flash applications and ColdFusion components. A quick look at this service led to the discovery of two Java deserialization vulnerabilities, both leading to unauthenticated RCE in a service that runs under the local SYSTEM account by default.

Adobe released a security update on the 12th September 2017 for ColdFusion 11 and ColdFusion 2016 which can be installed through the ColdFusion Administrator application, however this update alone is not sufficient. Adobe ColdFusion comes bundled with its own Java runtime environment (JRE), which must be manually updated for the update to be effective.

The end-of-life ColdFusion 9 is also known to be affected, however no supported fix was available at the time of writing.

Update (13/10/2017): To clarify, this vulnerability affects the Java RMI service and does not affect HTTP(S) services exposed by ColdFusion.

Update (19/03/2018): It seems I made a typo in the blog title, this post is about CVE-2017-11283 and CVE-2017-11284 not 11238! Continue Reading

Exploitation

When Parameterized Queries Won’t Help

The usual recommendation for vulnerabilities that enable us to manipulate database queries (SQL injection) is to use a method such as prepared statements (parameterized queries) to query the database. Correct use of prepared statements prevents SQL injection attacks by ensuring that user input is properly handled by the database management system.

This post is about an edge case where a ‘safe’ database query was manipulated to attack an application.

Continue Reading

Tools

Java’s BaRMIe Back Door

A week ago I released a tool that I have been working on to enable security professionals to interact with applications that utilise Java’s Remote Method Invocation (RMI). This is the first in a series of blog posts covering RMI security and the tool I released, BaRMIe.

Source code for the tool can be found over at GitHub, along with binary releases. Slides for my talk at 44CON 2017 where I presented the results of my research can be found on SlideShare.

Why?

“RMI is outdated”

“Is that still a thing?”

“No one uses RMI anymore”

I first came across RMI during a pentest when nmap reported an “rmiregistry” service. I thought Remote Method Invocation alone sounded like something worth investigating further, but this service turned out to be really easy to attack. A few lines of code compiled against the RMI client’s JAR files was all it took and the service gave me unauthenticated access to the server’s file system (list, read, write, and delete files). Surprised by how easy that was, I wanted to find out how often RMI is used so insecurely and what else I could do with it.

RMI Security

My initial research quickly led to the discovery of many more instances of RMI being used insecurely. A key part of the problem seems to be that RMI was built to serve a specific purpose: invoking Java methods within another Java Virtual Machine (JVM). It was not built with security in mind. We can liken this to HTTP, except that HTTP is far more mature with a much larger user base. Over time a demand for security has led to HTTP evolving to support security. Modern web developers don’t even need to be particularly security aware because application frameworks bake security features in by default. RMI has none of this. Furthermore, the implementation of RMI is so simple and transparent that developers need not even be aware that they are interacting with a remote server.

The RMI protocol has no standard security features. Additional effort is required to incorporate security features like authentication and session management in front of classes/objects that are exposed over RMI.

Attacking RMI

My first attack against an RMI service required code compiled against the JAR files for the original client application. I wasn’t satisfied with that, I really wanted a zero-knowledge attack, which was one of the reasons I started researching the protocol. I later came across Adam Boulton’s presentation from AppSec USA 2008 – Security Assessing Java RMI – where he spoke about a zero-knowledge attack against RMI services. Unfortunately that attack relies on significant brute forcing over the network.

In the absence of a practical zero-knowledge attack, we need details of remote classes including method names, parameter types, and return types, in order to interact with an RMI service. The goal of BaRMIe is to build a set of common classes and methods that are exposed over RMI. Using these, we can enumerate an RMI endpoint to identify known classes and use them to attack the service.

BaRMIe supports three types of attacks against RMI services:

  1. Insecure Methods: RMI services often expose dangerous functionality that can be called directly provided the class/method details are known. Examples include unauthenticated file reading and writing.
  2. Deserialization via Object-type Parameters: RMI uses Java serialization making it a target for deserialization attacks. If a remote method accepts a parameter of the type ‘java.lang.Object’ then it can be used to deliver a deserialization payload.
  3. Deserialization via Illegal Method Invocation: Java does not verify that supplied method parameters are compatible with the actual method parameter type before deserializing the supplied method parameter. This weakness means that any non-primitive remote method parameter can be replaced with an arbitrary object using a TCP proxy, effectively triggering an illegal method call except that a deserialization payload is triggered before Java fails to execute the illegal method call.

Each of these attacks is facilitated using minimal RMI stub classes and interfaces that allow BaRMIe to call the target remote methods. BaRMIe also includes TCP proxying code to support deserialization attacks by enabling payloads to be injected at the network level.

In the next blog post on BaRMIe I’ll look at the technical aspects in more detail and cover some of the code and techniques used by BaRMIe to enumerate and attack RMI services. In the meantime, check it out!

Exploitation

Attacking Java Deserialization

Deserialization vulnerabilities are far from new, but exploiting them is more involved than other common vulnerability classes. During a recent client engagement I was able to take advantage of Java deserialization to gain a foothold on a server from where I was able to obtain root access to tens of servers spanning pre-production and production environments across multiple data centres. The vulnerability I discovered had previously survived multiple pentests and I would have missed it too if I hadn’t had prior exposure to Java (de)serialization.

Continue Reading