Reading view

There are new articles available, click to refresh the page.

CVE-2015-3269: Apache Flex BlazeDS XXE Vulnerabilty

In a recent Product Security Review, Code White Researchers discovered a XXE vulnerability in Apache Flex BlazeDS/Adobe (see ASF Advisory). The vulnerable code can be found in the BlazeDS Remoting/AMF protocol implementation.

All versions before 4.7.1 are vulnerable. Software products providing BlazeDS Remoting destinations might be also affected by the vulnerability (e.g. Adobe LiveCycle Data Services, see APSB15-20).

Vulnerability Details

An AMF message has a header and a body. To parse the body, the method readBody() of AmfMessageDeserializer is called. In this method, the targetURI, responseURI and the length of the body are read. Afterwards, the method readObject() is called which eventually calls the method readObject() of an ActionMessageInput instance (either Amf0Input or Amf3Input).

In case of an Amf0Input instance, the type of the object is read from the next byte. If type has the value 15, the following bytes of the body are parsed in method readXml() as a UTF string.

The xml string gets passed to method stringToDocument of class XMLUtil where the Document is created using the DocumentBuilder.

When a DocumentBuilder is created through the DocumentBuilderFactory, external entities are allowed by default. The developer needs to configure the parser to prevent XXE.

Exploitation

Exploitation is easy, just send the XXE vector of your choice.

Compromised by Endpoint Protection

In a recent research project, Markus Wulftange of Code White discovered several critical vulnerabilities in the Symantec Endpoint Protection (SEP) suite 12.1, affecting versions prior to 12.1 RU6 MP1 (see SYM15-007).

As with any centralized enterprise management solution, compromising a management server is quite attractive for an attacker, as it generally allows some kind of control over its managed clients. Taking control of the manager can yield a takeover of the whole enterprise network.

In this post, we will take a closer look at some of the discovered vulnerabilities in detail and demonstrate their exploitation. In combination, they effectively allow an unauthenticated attacker the execution of arbitrary commands with 'NT Authority\SYSTEM' privileges on both the SEP Manager (SEPM) server, as well as on SEP clients running Windows. That can result in the full compromise of a whole corporate network.

Vulnerabilities in Symantec Endpoint Protection 12.1

Code White discovered the following vulnerabilities in Symantec Endpoint Protection 12.1:

SEP Manager
Authentication Bypass (CVE-2015-1486)
Allows unauthenticated attackers access to SEPM
Mulitple Path Traversals (CVE-2015-1487, CVE-2015-1488, CVE-2015-1490)
Allows reading and writing arbitrary files, resulting in the execution of arbitrary commands with 'NT Service\semsrv' privileges
Privilege Escalation (CVE-2015-1489)
Allows the execution of arbitrary OS commands with 'NT Authority\SYSTEM' privileges
Multiple SQL Injections (CVE-2015-1491)
Allows the execution of arbitrary SQL
SEP Clients
Binary Planting (CVE-2015-1492)
Allows the execution of arbitrary code with 'NT Authority\SYSTEM' privileges on SEP clients running Windows

The objective of our research was to find a direct way to take over a whole Windows domain and thus aimed at a full compromise of the SEPM server and the SEP clients running on Windows. Executing post exploitation techniques, like lateral movement, would be the next step if the domain controller hasn't already been compromised by this.

Therefore, we focused on SEPM's Remote Java or Web Console, which is probably the most exposed interface (accessible via TCP ports 8443 and 9090) and offers most of the functionalities of SEPM's remote interfaces. There are further entry points, which may also be vulnerable and exploitable to gain access to SEPM, its server, or the SEP clients. For example, SEP clients for Mac and Linux may also be vulnerable to Binary Planting.

Attack Vector and Exploitation

A full compromise of the SEPM server and SEP clients running Windows was possible through the following steps:

  1. Gaining administrative access to the SEP Manager (CVE-2015-1486)
  2. Full compromise of SEP Manager server (CVE-2015-1487 and CVE-2015-1489)
  3. Full compromise of SEP clients running Windows (CVE-2015-1492)

CVE-2015-1486: SEPM Authentication Bypass

SEPM uses sessions after the initial authentication. User information is stored in a AdminCredential object, which is associated to the user's session. Assigning the AdminCredential object to a session is implemented in the setAdminCredential method of ConsoleSession, which again holds an HttpSession object.

This setAdminCredential method is only called at two points within the whole application: once in the LoginHandler and once in the ResetPasswordHandler.

Its purpose in LoginHandler is obvious. But why is it used in the ResetPasswordHandler? Let's have a look at it!

Password reset requests are handled by the ResetPasswordHandler handler class. The implementation of the handleRequest method of this handler class can be observed in the following listing:

After the prologue in lines 72-84, the call to the init method calls the findAdminEmail method for looking up the recipient's e-mail address.

Next, the getCredential method is called in line 92 to retrieve the AdminCredential object of the corresponding administrator. The AdminCredential object holds information on the administrator, e. g., if it's a system administrator or a domain administrator as well as an instance of the SemAdministrator class, which finally holds information such as the name, e-mail address, and hashed password of the administrator.

The implementation of the getCredential method can be seen in the following listing:

Line 367 creates a new session, which effectively results in issuing a new JSESSIONID cookie to the client. In line 368, the doGetAdminCredentialWithoutAuthentication method is called to get the AdminCredential object without any authentication based on the provided UserID and Domain parameters.

Finally – and fatally –, the looked up AdminCredential object is associated to the newly created session in line 369, making it a valid and authentic administrator's session. This very session is then handed back to the user who requested the password reset. So by requesting a password reset, you'll also get an authenticated administrator's session!

An example of what a request for a password reset for the built-in system administrator 'admin' might look like can be seen in the following listing:

And the response to the request:

The response contains the JSESSIONID cookie of the newly created session with the admin's AdminCredential object associated to it.

Note that this session cannot be used with the Web console as it is missing some attribute required for AjaxSwing. However, it can be used to communicate with the other APIs like the SPC web services, which, for example, allows creating a new SEPM administrator.

CVE-2015-1487: SEPM Arbitrary File Write

The UploadPackage action of the BinaryFile handler is vulnerable to path traversal, which allows arbitrary files to be written. It is implemented by the BinaryFileHandler handler class. Its handleRequest method handles the requests and the implementation can be observed in the following listing:

Handling of the UploadPackage action starts at line 189. The PackageFile parameter value is used as file name and the KnownHosts parameter value as directory name. Interestingly, the provided directory name is checked for path traversal by looking for directory separators '/' and '\' (see line 196, possibly related to CVE-2014-3439). However, the file name is not, which still allows to specify any arbitrary file location.

The following request results in writing the given POST request body data to the file located at '[…]\Symantec\Symantec Endpoint Protection Manager\tomcat\webapps\ROOT\exec.jsp':

Writing a JSP web shell as shown allows the execution of arbitrary OS commands with 'NT Service\semsrv' privileges.

CVE-2015-1489: SEPM Privilege Escalation

The Symantec Endpoint Protection Launcher executable SemLaunchSvc.exe is running as a service on the SEPM server with 'NT Authority\SYSTEM' privileges. It is used to launch processes that require elevated privileges (e. g., LiveUpdate, ClientRemote, etc.). The service is listening on the loopback port 8447 and SEPM communicates with the service via encrypted messages. The communication endpoint in SEPM is the SemLaunchService class. One of the supported tasks is the CommonCMD, which results in command line parameters of a cmd.exe call.

Since we are able to execute arbitrary Java code within SEPM's web server context, we can effectively execute commands with 'NT Authority\SYSTEM' privileges on the SEPM server.

CVE-2015-1492: SEP Client Binary Planting

The client deployment process on Windows clients is vulnerable to Binary Planting. It is an attack exploiting the behavior of how Windows searches for files of dynamically loaded libraries when loading them via LoadLibrary only by their name. If it is possible for an attacker to place a custom DLL in one of the locations the DLL is searched in, it is possible to execute arbitrary code with the DllMain entry point function, which gets executed automatically on load.

Symantec Endpoint Protection is vulnerable to this flaw: During the installation of a deployment package on a Windows client, the SEP client service ccSvcHst.exe starts the smcinst.exe from the installation package as a service. This service tries to load several DLLs, e. g., the UxTheme.dll.

By deploying a specially crafted client installation package with a custom DLL, it is possible to execute arbitrary code with 'NT Authority\SYSTEM' privileges.

A custom installation package containing a custom DLL can be constructed and deployed in SEPM with the following steps.

Export Package
Download an existing client installation package for Windows as a template:
  • Go to 'Admin', 'Installation Packages'.
  • Select a directory where you want to export it to.
  • Select one of the existing packages for Windows and click on 'Export a Client Installation Package'.
  • Untick the 'Create a single .EXE file for this package'.
  • Untick the 'Export packages with policies from the following groups'.
  • Click 'OK'.
Modify Package
Tamper with the client installation package template:
  • Within the downloaded installation package files, delete the packlist.xml file.
  • Open the setAid.ini file, delete the PackageChecksum line and increase the values of ServerVersion and ClientVersion to something like 12.2.0000 instead of 12.1.5337.
  • Open the Setup.ini file and increase the ProductVersion value accordingly.
  • Copy the custom DLL into the package directory and rename it UxTheme.dll.
Import and deploy Package
Create a new client installation package from the tampered files and deploy it to the clients:
  • Go to 'Admin', 'Installation Packages'.
  • Click 'Add a Client Installation Package'.
  • Give it a name, select the directory of the tampered client installation package files, and upload it.
  • Click 'Upgrade Clients with Package'.
  • Choose the newly created client installation package and the group it should be deployed to.
  • Open the 'Upgrade Settings', untick 'Maintain existing client features when upgrading' and select the default feature set for the target group, e. g., 'Full Protection for Clients'.
  • Upgrade the clients by clicking 'Next'.

The loading of the planted binary may take some while, probably due to some scheduling of the smcinst.exe service.

Conclusion

We have successfully demonstrated that a centralized enterprise management solution like the Symantec Endpoint Protection suite is a critical asset in a corporate network as unauthorized access to the manager can have unforeseen influence on the managed clients. In this case, an exposed Symantec Endpoint Protection Manager can result in the full compromise of a whole corporate domain.

Reading/Writing files with MSSQL's OPENROWSET

Unfortunately, Microsoft SQL Server's SQL dialect Transact-SQL does not support reading and writing files in an easy way as opposed to MySQL's LOAD_FILE() function and INTO OUTFILE clause.

Of course, with xp_cmdshell being enabled, you can read and write files using OS commands. However, one is not always blessed with the CONTROL SERVER permission, which is generally only granted with the sysadmin role. But if you happen to have the ADMINISTER BULK OPERATIONS permission (implied by the bulkadmin role), then OPENROWSET is a viable option for both reading and writing files.

Granted, using OPENROWSET for reading and writing files is nothing new. However, all examples for writing files that I have seen so far require the access to remote OLE DB providers being enabled, which is controlled by the ad hoc distributed queries configuration option, which is disabled by default. And changing and reconfiguring any configuration option requires ALTER SETTINGS permissions (implied by the sysadmin and serveradmin roles), which are not always available. And, well, in case of the sysadmin role, you could just as well use xp_cmdshell.

So the technique for writing files demonstrated here is a little different as it exploits a side-effect of OPENROWSET, which just requires ADMINISTER BULK OPERATIONS permission. It also does not require any temporary table or whatsoever; everything can be performed in a sub-query.

Checking Prerequisites

For looking up whether the current user has ADMINISTER BULK OPERATIONS permissions, you can use the HAS_PERMS_BY_NAME() function:

The the result should be 1.

Reading Files

Reading a file is pretty straight forward. When OPENROWSET is referenced in the FROM clause, it allows reading from the given file through a built-in BULK provider and returns it as a rowset. The following SELECT reads the C:\Windows\win.ini file and returns a rowset of one single character LOB:

This, of course, can also be used to leak hashes for pass-the-hash.

Writing Files

Writing to a file is a little more difficult. The common approach with OPENROWSET only is calling an external OLE DB provider. But this generally requires ad hoc distributed queries being enabled and has certain caveats like restriction to certain output formats depending on the selected OLE DB provider (e. g., CSV), previous existence of the output file, registration of linked servers, etc.

However, there is a way of writing arbitrary data to an arbitrary file without any of these restrictions or prerequisites by exploiting a side-effect of OPENROWSET.

The feature that is being exploited is the error reporting feature. The reference states the purpose of the ERRORFILE argument as follows:

ERRORFILE = 'file_name'
Specifies the file used to collect rows that have formatting errors and cannot be converted to an OLE DB rowset. These rows are copied into this error file from the data file "as is."

So any erroneous record from the input is directly written to the given error file as is.

The following SELECT reads from \\192.168.13.37\share\input.txt with the format specified in \\192.168.13.37\share\input.fmt and writes to C:\Inetpub\wwwroot\hello.aspx:

The input file input.txt has the following contents:

The non-XML format file input.fmt specifies one single column named BulkColumn of type CHAR with the length of 1 character (fourth column) and the last character in our input file (i. e., >) as terminator:

Since we specified the length with just one byte, a truncation error occurs and the whole record up to and including the final terminator (i. e., >) gets written to the error file:

Msg 4863, Level 16, State 1, Line 1
Bulk load data conversion error (truncation) for row 1, column 1 (BulkColumn).

For binary files, the XML format seems to be better as you can specify the length for both the field input and the column output and don't need a terminator. The following format file input.xml allows writing binary data up to 512 kB:

The length seems to be irrelevant and it certainly raises a data conversion error due to the binary data, resulting in writing the entire data to the error file.

CVE-2015-2079: Arbitrary Command Execution in Usermin

While performing a penetration test for a customer, I stumbled across a command execution vulnerability in Usermin that is pretty trivial to identify and to exploit. The interesting part is that this vulnerability survived for almost 13 years.

Introduction

According to the Usermin Homepage:

Usermin is a web-based interface for webmail, password changing, mail filters, fetchmail and much more. It is designed for use by regular non-root users on a Unix system, and limits them to tasks that they would be able to perform if logged in via SSH or at the console.

Therefore, Usermin can be seen as a web alternative for interactive machine access as a specific system user. But often times in real environments, Usermin is used to limit the user's rights to perform specific actions via the web, for example as a webmailer only. In this case, arbitrary command execution is definitely not a desired feature.

Nonetheless, enter CVE-2015-2079, which affects Usermin versions 0.980 (dating back to 2002-12-16) until 1.650 (latest unpatched version of 2015-02-16) by exploiting a specific behavior of Perl's open() function.

Summary

An authenticated user of Usermin can specify the path to an arbitrary file on the server that should be attached to any new email as a signature via the Signature file configuration in the Other file option.

This is due to the function get_signature in usermin/mailbox/mailbox-lib.pl, which calls open() without any prior validation:

For what it's worth, that alone poses a vulnerability. But according to an old bug report dating back to 2005, this is not a bug but a feature:

This is not really a bug, as normal Unix file permissions still apply, so really critical files like /etc/shadow cannot be used as a signature. Also, the feature for attaching server-side files could be used in the same way

Besides that, due to some specific behavior of the Perl function used to open the user specified file, it is possible to provide and execute shell commands.

Vulnerability Details

Perl's open() function can not just open regular files. If it gets called with just two arguments (i. e., open FILEHANDLE,EXPR), the second argument allows to specify additional behavior via prefixes and suffixes.

For example, the open mode can be specified with the prefix < for reading, > for writing to, or >> for appending to the file. And with the prefix or suffix | it is possible to start interprocess communication:

Perl's basic open() statement can also be used for unidirectional interprocess communication by either appending or prepending a pipe symbol to the second argument to open().

Since Usermin's call to open() uses the two arguments form, we can provide a shell command enclosed in pipes as the Signature file to execute the provided command whenever the user composes a new email and output is shown within the message text window or when the user edits the signature.

Example request as proof-of-concept with a sig_file_free parameter of value |uname -a| which gets sent to /uconfig_save.cgi by a POST request to usermin like this:

Now that the config file of the subsequent user is changed (see sig_file in ~/.usermin/mailbox/config), a GET request to /mailbox/reply_mail.cgi "includes" the evaluation of uname -a in the response in the textarea:

Similarily, the code can be triggered via a GET request to /mailbox/edit_sig.cgi:

There is also a handy proof-of-concept metasploit module for linux for your convenience.

The Fix

The Usermin developers fixed this vulnerability in version 1.660. Although the Usermin changelog does not mention it, the diff between the Usermin versions 1.650 and 1.660 shows that they chose to use the Webmin's custom open_readfile() function instead of Perl's built-in open() function, which basically prepends the given file path with < to open the file in read mode.

However, reading arbitrary files on the server is still possible.

Timeline

  • 2015-02-23: Identification of vulnerability
  • 2015-02-24: Details sent to Usermin developer
  • 2015-02-24: Acknowledge from Usermin developer, will be fixed in next version
  • 2015-02-25: Assignment of CVE-2015-2079 via [email protected]
  • 2015-03-16: Request for status update from Usermin developer
  • 2015-03-16: Answer: fixed version "Probably a couple of weeks" away
  • 2015-05-08: Request for status update from Usermin developer
  • 2015-05-08: Answer: fixed version aimed for next week
  • 2015-05-13: Patched Usermin version 1.660 released (without mentioning the bug)
  • 2015-05-20: Full disclosure 7 days after patch release

CVE-2015-0935: PHP Object Injection in Bomgar Remote Support Portal

Serialization is often used to convert objects into a string representation for communication or to save them for later use. However, deserialization in PHP has certain side-effects, which can be exploited by an attacker who is able to provide the data to be deserialized.

This post will give you an insight on the deserialization of untrusted data vulnerability in the Bomgar Remote Support Portal 14.3.1 (US CERT VU#978652, CVE-2015-0935), which is part of Bomgar's appliance-based remote support software. It covers details on the weakness of Deserializion of Untrusted Data (CWE-502) in PHP applications in general, as well as specific details on the vulnerability and its exploitation in the Bomgar Remote Support Portal 14.3.1.

Note that this post is not about the various bugs in the implementation of the unserialize function itself (see for example Sec Bug #67492, Sec Bug #68594, Sec Bug #68710, and Sec Bug #68942), but about the exploitation on the application level.

Summary

Description from US CERT VU#978652:

Bomgar Remote Support Portal version 14.3.1 and possibly earlier versions deserialize untrusted data without sufficiently verifying the validity of the resulting data. An unauthenticated attacker can inject arbitrary input to at least one vulnerable PHP file, and authenticated attackers can inject arbitrary input to multiple vulnerable PHP files. When malicious data is deserialized, arbitrary PHP code may be executed in the context of the PHP server process.

Vulnerability Details

The PHP function unserialize allows the creation of arbitrary object constructs of any class with arbitrary attributes of almost arbitrary types without any validation. During the deserialization, the lifetime of an object, and the interaction with the object, several methods, including so called magic methods, may get called using these arbitrarily definable attributes. An attacker may be able to utilize the functionality provided within these called methods to his benefit. For more information on deserialization in PHP, have a look at Serialization in the PHP Internals Book and Writing Exploits For Exotic Bug Classes: unserialize() by Stephen Coty of Alert Logic.

In Bomgar Remote Support Portal 14.3.1, unserialize is called several times with user provided data, among them there is one which can be called by an unauthenticated user.

Exploitation

The most challenging part of exploiting such a vulnerability is finding appropriate classes with effects beneficial for an attacker. Therefore, it solely depends on the available classes. If there are no classes with beneficial effects available, it is not exploitable.

Fortunately, there is at least one in Bomgar Remote Support Portal 14.3.1!

One way to exploit this vulnerability is by utilizing the Tracer class. It is used to write stack trace information to a log using a Logger instance, which wraps an instance of PEAR's Log class. By using a Log_file instance as an instance of Log, it is possible to write the arbitrary data <payload> to the arbitrary file <destination>.

A corresponding serialized representation of such an object construct may look like this (\0 represents a NUL byte):

Writing the data to the specified location is triggered by the log method call in the destructor of the Tracer class.

And this is what happens behind the curtain:

  • unserialize creates an instance of the Tracer class, the Logger class, and the Log_file class with the following structure (only relevant members are shown):
  • At the end of the runtime of the request, PHP calls the destructor __destruct of our Tracer object, which eventually calls the log method of the Log_file class with the following behavior:
    • The file specified in _filename gets opened in write mode, if not already opened (line 285-287)
    • The format of the line to be written to the log is specified by _lineFormat, i. e. our <payload> (line 293-295)
    • The log line gets written to the specified log file (line 303)

By injecting a Tracer object as specified, arbitrary data can be written or appended to an arbitrary file.

Additional Information on Exploitation

If the document root location of the web server is unknown, one can utilize PHP's autoload functionality, which allows the inclusion of a '*.php' file from any location as long as the path can be expressed in a class name with '_' instead of '/'.

For example, the deserialization of the following object representation would result in the local file inclusion of '/tmp/poc.php':

The exploitation can then be performed with two serialized objects:

  1. Writing a PHP payload to a known location like '/tmp/poc.php' using the Tracer object structure as mentioned above.
  2. Loading and executing the written PHP payload using an object with the class name like '_tmp_poc' as mentioned above.

Most of the vulnerable unserialize calls are only accessible after successful authentication. However, one is accessible without prior authentication; this requires a particular access token but can also be retrieved without authentication. I leave this as a challenge to the reader. ;-)

Course of events and 'cooperation' with Bomgar

The whole process of the disclosure of this vulnerability took longer than expected: The initial report submission of the vulnerability to US CERT was on 2014-11-14. They instantly replied that they wanted me to first contact Bomgar directly. So I wrote an e-mail to [email protected], asking for a contact person for a confidential disclosure of the vulnerability details. After one week without any reply, I asked US CERT on 2014-11-23 to do the coordination.

Fast forward: on 2015-02-12 I got an answer from US CERT, stating that they have established a contact at Bomgar. This was already 90 days after the initial report.

Immediately after that, I got contacted by Bomgar, asking me how I intended to use the vulnerability information. My reply was that I wanted to write this very blog post, which should contain details on the vulnerability and its exploitation in Bomgar Remote Support Portal 14.3.1. Since an exploitation of this kind of vulnerability depends on the available classes and their functionality, I wanted to show some source code snippets of the involved classes and methods. However, Bomgar insisted on not having any copyrighted source code published and also asked me to remove any explicit details on how to reach the unserialize function calls, especially the one accessible without authentication.

$@|sh – Or: Getting a shell environment from Runtime.exec

If you happen to have command execution via Java's Runtime.exec on a Unix system, you may already have noticed that it doesn't behave like a normal shell. Although simple commands like ls -al, uname -a, or netstat -ant work fine, more complex commands and especially commands with indispensable features like pipes, redirections, quoting, or expansions do not work at all.

Well, the reason for that is that the command passed to Runtime.exec is not executed by a shell. Instead, if you dig down though the Java source code, you'll end up in the UNIXProcess class, which reveals that calling Runtime.exec results in a fork and exec call on Unix platforms.

Nonetheless, I'll show you a way to still get commands executed in a proper shell.

For testing, we'll use this Java example:

We call this class as shown below with single quotes around the command line to ensure that our shell passes the command line argument to Java as is:


$ java Exec 'command arg1 arg2 ...'

Your first thought on a solution to this might be: "Ok, I'll just use sh -c command to execute command in the shell."

That is correct, but here is the catch: Since only the first argument following -c is interpreted as shell command, the whole shell command must be passed as a single argument. And if you take a closer look at how the string passed to Runtime.exec is processed, you'll see that Java uses a StringTokenizer that splits the command at any white-space character.

If you are thinking of quoting the command parameter string like uname -a as follows:


$ java Exec 'sh -c "uname -a"'

this won't work. Remember: We're not in a shell yet, and Runtime.exec does only take white-spaces as argument separators into account.

So, what is the other option that we have?

The key is in the sh -c command, but we won't execute the command directly but build a command that itself spawns another shell that then executes our command. Though it sounds complicated, we'll derive it step by step.

How it works

The secret key to this is the special parameter @, which expands to the positional parameters when referenced with $@, starting from parameter one:


$ java Exec 'sh -c $@'

But how do we pass the actual command? Well, if the shell is invoked with -c, any remaining arguments after the command argument are assigned to the positional parameters, starting with $0. So when $@ is expanded by the shell with the following invocation:


$ java Exec 'sh -c $@ 0 1 2 3 4 5'

It results in 1 2 3 4 5. The 0-th parameter does not appear in the expansion result as it, by convention, should be the file name associated with the file being executed. We can see the result by adding a echo in place of the $1 parameter:


$ java Exec 'sh -c $@ 0 echo 1 2 3 4 5'

Here the shell first expands $@ to echo 1 2 3 4 5 and then executes it.

But this is still not better than the simple sh -c command, as we still have no support of pipes, redirections, quoting or expansion.

The reason for this is that the $@ expansion does not result in a restart of the command interpretation.

The solution to a fully functional shell is sh's ability to allow the commands to be passed via standard input. So, if we use another echo to echo our command and pipe it to sh, we'll get our command executed by sh entirely:


$ java Exec 'sh -c $@|sh . echo command'

Now we have all shell features available!

The only thing to remember is that any white-space sequences vital in your command must be encoded somehow as otherwise it would be eaten by Java's StringTokenizer, e.g.:


$ java Exec 'sh -c $@|sh . echo /bin/echo -e "tab\trequired"'

And to anyone who is interested in what the process tree looks like:


$ java Exec 'sh -c $@|sh . echo ps ft'
PID TTY STAT TIME COMMAND
27109 pts/25 Ss 0:03 /bin/bash
6904 pts/25 Sl+ 0:00 \_ java Exec sh -c $@|sh . echo ps ft
6914 pts/25 S+ 0:00 \_ sh -c $@|sh . echo ps ft
6916 pts/25 S+ 0:00 \_ sh
6917 pts/25 R+ 0:00 \_ ps ft

Exploiting the hidden Saxon XSLT Parser in Ektron CMS

Another vulnerability I came across was in Ektron CMS. It's a .NET-based Web CMS System. If you want to find running instances try "inurl:/workarea filetype:asmx" at Google. The interesting thing about is that Microsoft already reported the initial vulnerability as MSVR12-016 (CVE-2012-5357), but I found a different vector to exploit it.

Summary

From US CERT VU#110652:
Ektron Content Management System version 8.5, 8.7, and 9.0 contain a resource injection vulnerability by using an improperly configured XML parser. By default, Ektron utilizes the Microsoft XML parser to parse XSLT documents, which is not vulnerable. If an attacker specifies use of the Saxon XSLT parser instead, and sends it a specially crafted XSLT document, the attacker may be able to run arbitrary code at the privilege level of the application.

Vulnerability Details

During information gathering, I found several Web services exposed on the Ektron CMS system. One of them was
http://[host]/Workarea/ServerControlWS.asmx
Looking at the WSDL, there was the SOAP method ContentBlockEx, having a parameter that nearly jumped into my face: xslt.

If you can get your data parsed by a XSLT parser, that's almost like hitting the jackpot. The problem was that Ektron already patched the vulnerability by hardening the MSXML parser. Nevertheless, XXE was still possible - but I couldn't get any helpful information out of the system. There was also another vulnerability that allowed me to list directories. Finally, I found the directory with all .net DLL's. After browsing through the directory, I finally found something interesting. There were several saxon9*.dlls. From my former times, I could remember that Saxon allows me to parse XSLT. So I had a look at the documentation at Saxon Function Library.

Looking at the different namespaces, I found several interesting functions working with files, etc. After browsing through the Saxon documentation, I finally found an interesting paragraph Saxon Calling Static Methods in a .NET ClassFrom this, it seemed like I could call static functions of .net CRL classes from Saxon :-)

So I created the following XSLT template:


Putting it all together, the final SOAP request looks like this:

Vendor Response

I wasn't involved, although CERT tried to contact them with no luck.

The fix

Ektron released a Security Update 2 (Releases 8.02 SP5 to 9.10 SP1). To my amazement, Ektron told CERT the following:
This was patched via a cumulative security patcher that was made available Oct 9, 2013 that would apply the updates to versions 8.0.2 to 9.0. The current version of the patcher is available at: https://portal.ektron.com/News/Security/Security_Notice_-_11-25-14/ 8.7sp2 (released 8/16/2013), 9.0sp1 (released 8/19/2013), and 9.1 (released 8/28/2014) were all released with the fix in place. Subsequent service packs also contain the fixes for those versions
To be honest, I don't think this statement is true. What Ektron did in 2013 was to reconfigure Ektron CMS to expose the Web services only on localhost by default. An administrator can still reconfigure it. Nevertheless, with "Security Update 2", all the parser hardening was hopefully implemented. I haven't verified it yet because there is no public download available for the latest version.
❌