Serialization must perish!

Source: Internet
Author: User
Tags object serialization

When talking about security issues caused by random object serialization, the author Arshan Dabirsiaghi recommends five performance indicators to help us assess the health of enterprise Java applications. @frohoff, @gebl and @breenmachine work together to solve the Java security problem (this article attributed it to the term "sequence event"), the author thought of the deserialization alternative. Where will our customers go? Do they have a brighter future? This article will be one for you to ascertain. In the author's view: The future is dark and pitch.
In this article, we'll look at Kyro, the "go-to-the-tip" serialization database. As we all know, the Kryo framework has been used in many well-known software, but Kryo is also a database, a database that may be used by many downstream enterprises. The following will be carefully decomposed, this article is the domestic ITOM management platform OneAPM compiling and finishing

How many fishes in the water

The amazing thing about Kryo is that you can use it to serialize or deserialize any type of Java, not necessarily those that are tagged with java.io.Serializable. In many cases, this greatly simplifies development, such as serializing features that are already characteristic or uncontrollable.

If you use Kryo to deserialize an object, you must declare the desired type. Here is an example:

// serializingKryo kryo = new Kryo();AcmeMessage message = buildAcmeMessage(); // some domain objectOutput out = new Output(response.getOutputStream())kryo.writeObject(out, myObject);// deserializingInput in = new Input(request.getInputStream());AcmeMessage message = kryo.readObject(in, AcmeMessage.class);

This API design is a big step forward at least for the Java object serialization specification. This specification forces the user to deserialize all content sent by the attacker, and then the user has to pray that the content to be looked up later is splashed--which is somewhat absurd. This is the first hurdle an attacker can encounter: how do you trick users into deserializing any type?

Rescue

This trap is actually easier to avoid. In real life, any domain objects that people send repeatedly have collections-mappings, lists, arrays, or similar data. Consider the following sample object:

/* AcmeMessage.java */private List<AcmeRecipient> recipients;

This code does not exist where it matters. The only thing that matters is the compile time. I was in the running environment when the attack occurred. This means that, for us, the code should be understood in this way instead:

/* AcmeMessage.java */private List<Object> recipients;

So, if our target application deserializes a AcmeMessage type, we can fill in the Receive field with some unexpected arbitrary types, because all types are expanded from Object . Thus, as in the case of sequence event attacks, the type used by an attacker must still be on the classpath of the victim application, library, or server.

Of course, if an application tries to use one of these objects as a acmemessage, it will detonate the problem, but our attack will be fruitful before that. See actual test cases.

Harness Type Bazaar

We can send any type. So, are there any restrictions? There are not many rules for classic serialization-Just a class labeled java.io.Serializable is sufficient. After looking at the code, we seem to find only one rule: the class must have an parameterless constructor. Do you feel it now?

Kryo this model at a higher level:

* *. Gets the 0 parameter constructor for the specified type

1. If it is a private constructor, mark it as accessible

2. Call this constructor

3. For each field in a type:

The field passed in the deserialization message (recursive)

Assign a field to the new type created by step 3rd *

There are many ways to rewrite this behavior as a more abusive behavior, but let's focus on the default settings first. I've actually mentioned the loophole before, have you found it?

Almost a series of events

Launch of a sequence event people want to know this: the problem is not in these four or five classes. The foundation of the model has been broken. How we learned that MD5 had been damaged before the MD5 was completely destroyed, you must know. Here is the same principle.

If you let developers specify arbitrary behavior in their type of Serializable#readobject () method, you can concatenate the side effects of these behaviors to fuel the hidden spark. This is the truth of the matter.

There is no difference here.

I can submit any class on your classpath, and you (the victim application) can also call its constructor. Developers can place arbitrary data in their constructors. But this does not guarantee avoidance of side effects.

Here we analyze some of the attack strategies and the corresponding tools we will use.

Misuse of static side effects in constructors

The following is a class of ColdFusion that can greatly combat a single case that you can control.

package coldfusion.syndication;import com.sun.syndication.io.impl.CFDateParser;public class FeedDateParser implements CFDateParser {    private FeedDateParser() {        DateParser.registerCFDateParser(this);     }        ...}

Obviously, this method can be called only once. What happens if I send you a feeddateparser that is Kryo serialized and has a blank field? Answer: Super effective DoS attack for applications. I'll use my own malicious singleton to rewrite this single example and fill in the various blank field members. Because everyone is in use, it causes nullpointerexceptions exceptions to be triggered everywhere. Just one HTTP request can give you no resistance.

Notice that the constructor here is private. This has no effect on kryo. But it's a little tricky for me. If I mark a constructor as private, I want to create it only in the way I allow it. This may be a good reason-even for security reasons! However, the Kryo user reports "Do not support private constructors" as a program error, and the function library maintainer adds support accordingly. Oddly, the initiator is a security issue in the sense that it is not possible to instantiate an object in a more secure manner in a functional request that is significant. They can implement more secure object instantiation within a few years of seeing this request, but this is still not the default feature.

Constructors can also cause many other destructive effects. Although I am sure there is an impact, I cannot find the fatal remote code execution using the strategy I can find.

Abuse Finalize () Cleanup tool

Constructors are not the only source of side effects that we can use to influence changes.

If a class implements the Object#finalize () method, Java calls this method before the object is garbage collected. Developers use this approach to clean up all non-JVM resources that have not been properly cleaned up. Because it is an automatic call, any side-effects that may occur in this method can be abused, and the application does not have to run on your malicious object at all! In fact, it must be thrown away in the process of exploiting the vulnerability.

You can use some types to play tricks.

Attack No. 1th: Delete arbitrary files (org.jpedal.io.ObjectStore)

So far, the most commonly abused strategy in Finalize () is to disrupt files. This is really useful; the type has a template file "backed up" in some way, and finalize () is a clear signal that the file can be cleaned up.

The first type I found here happened to be among ColdFusion 10: Org.jpedal.io.ObjectStore. When you analyze a class to determine the potential Kryo finalize () Use the tool, you only need to look at two things: the 0 parameter constructor and the Finalize () method. These are the only things that can happen. As long as the field is also an object that can be created with the 0 parameter constructor, you can control the field. The following are the constructors:

public ObjectStore() {  init();    }

The following note shows that the default constructor is called during Kryo call ReadObject ():

I didn't actually do anything. In any case, the act has been revoked, because once the constructor is executed, Kryo replicates our state on top of its state. Then it is finalize ():

protected void finalize() { ... flush(); ...}protected void flush() { .../** * flush any image data serialized as bytes */ Iterator filesTodelete = imagesOnDiskAsBytes.keySet().iterator();     while(filesTodelete.hasNext()) {      final Object file = filesTodelete.next();        if(file! = null){           final File delete_file = new File((String)imagesOnDiskAsBytes.get(file));        if(delete_file.exists()) {         delete_file.delete();    }   }

} ...}
See the Testcf10_jpedal () test Case to verify this tool.

Attack number 2nd: Memory Corruption (multiple types)

I'm not the best person to pursue this clue, but we can create a memory corruption vulnerability primitive in the following ways. They will call free () on the memory address controlled by the user:
* * Com.sun.jna.Memory, together with Vert.x

Com.sun.medialib.codec.jpeg.Encoder (no resources available), part of ColdFusion 10

Com.sun.medialib.codec.png.Decoder (no resources available), part of ColdFusion 10

Part of Com.xuggle.ferry.atomicinteger,liferay (i.e. Xuggle database) *

There are certainly many more, but these are already available for many common platforms. Let's take a look at the Com.sun.jna.memory#finalize () Call:

Free () has indeed been forwarded to the Stdlib.h::free () function. If there is no corresponding primary knowledge, it is extremely dangerous. This test case can confirm memory corruption. The test has been disabled, but you can change it from a public test to a private test to activate it. When activated, the test case causes the JVM to crash, as follows:

I would like to reiterate here that if the Kryo object being read comes from an untrusted resource and has any of these tools, it is susceptible to the impact of a single-excitation application compromise.

Attack No. 3rd: Close all file descriptors (Java.net.DatagramSocket)

These attacks are very similar to other types of attacks, and I have not yet fully explored them. However, the most obvious of these is Java.net.PlainDatagramSocketImpl, along with the JRE.

There is no explicit constructor or superclass in this type until java.lang.Object. Nonetheless, a java.io.FileDescriptor field invokes FD in its grandfather field Java.net.DatagramSocketImpl.

The FileDescriptor type has a 0-parameter constructor and contains only a simple integer that represents the OS-level file descriptor. Finalize () bootable function:

protected void finalize() { close();}/** * Close the socket.  */protected void close() {   if (fd != null) {   datagramSocketClose();   …}

This method is more primitive and, as shown in this code of the HotSpot native layer, is only from Unistd.h's very normal close ().

int os::close(int fd) { return ::close(fd);}int os::socket_close(int fd) { return ::close(fd);}

See the Testdatagramsocket () test Case to verify this tool. An attacker could submit numerous tool instances and close all possible file descriptors. This prevents the user from generating a socket interface for communication, reading the file or writing to, and any IPC.

Summarize

You can let Kryo call other methods, such as CompareTo (), EntrySet (), toString (), and so on, in short, can find a lot of gadgets.

The bottom line should be that any modern application can have a tool that can delete files, close file descriptors, or completely crash the JVM on its classpath. This means that people should generally realize that it is not safe to allow Kryo to operate untrusted data streams.

One might argue strongly that Kryo is much more secure if the default object instantiation policy does not invoke the constructor of the type. This is achieved with the JVM technique, and we'll parse the serialization program in the next article. With less instantiation of this constructor, you can prevent side effects from affecting the constructor and its finalize () method.

But if you do, Kryo no longer need a 0 parameter constructor to create a new object-so that an attacker can instantiate more types! This tradeoff will lead to a lot of tools that can be used by attackers, but there are fewer opportunities to execute methods on those tools-no more constructors, no more stereotyped methods.

Next time, we will analyze a company that has tried the same way but is still in trouble-xstream!

Original address: Https://dzone.com/articles/serialization-must-die

Domestic ITOM Management Platform ONEAPM is committed to helping enterprise users to provide full-stack performance management and IT operations Management services, through a probe can complete log analysis, security protection, APM basic component monitoring, integrated alarm and Big data analysis and other functions. To read more excellent articles, visit the OneAPM Official technology blog.
This article was transferred from OneAPM official blog

Serialization must perish!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.