Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to conduct depth analysis of Fastjson 1.2.24 deserialization vulnerabilities

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)05/31 Report--

How to carry out Fastjson 1.2.24 deserialization vulnerability in-depth analysis, I believe that many inexperienced people do not know what to do, so this paper summarizes the causes of the problem and solutions, through this article I hope you can solve this problem.

Preface

FastJson is an open source JSON parsing library for alibaba that can be used to convert Java objects to their JSON representations or to convert JSON strings into equivalent Java objects. Fastjson vulnerabilities have emerged one after another in recent years. We will talk about fastjson in recent years.

Source of RCE vulnerability: 1.2.24 deserialization vulnerability exposed by fastjson in 17 years. Based on this vulnerability, some details of fastjson vulnerability are analyzed in detail.

With regard to the Fastjson 1.2.24 deserialization vulnerability, many people have analyzed it since 17 years ago, and some of the basics will not be covered in this article. To put it simply, this vulnerability is caused by a lack of reasonable checking when Fastjson deserializes the incoming string into a Java object through parseObject/parse

The editor will focus on analyzing the details of this loophole that have not been described in detail, as follows:

1. What is the difference between the three methods parseObject (String text), parse (String text) and parseObject (String text, Class\ clazz) at the code level?

2. Why is it necessary to construct _ tfactory and _ name fields when using TemplatesImpl attacks to invoke link construction poc?

3. How to solve the problem that _ outputProperties is not exactly the same as the name of its getter method getOutputProperties () method?

In addition, when introducing the TemplatesImpl attack calling link, it simulates the idea of looking for the vulnerability exploitation chain, starts from the final execution point to find the entrance upward, and simulates the complete process of mining the TemplatesImpl utilization chain.

Loophole analysis

With regard to the three methods parse (String text), parseObject (String text) and parseObject (String text, Class\ clazz), we conduct a test.

The variables in the FastJsonTest class and their setter/getter relationships are as follows

| | public String T1 | private int T2 | private Boolean T3 | private Properties T4 | private Properties T5 |

| |-|-|

| | setter | Yes | Yes | none | none | Yes |

| | getter | Yes |

Next, we use the following three ways to deserialize JSON strings into Java objects

1. Object obj = JSON.parse (jsonstr)

2. Object obj = JSON.parseObject (jsonstr, FastJsonTest.class)

3. Object obj = JSON.parseObject (jsonstr)

First let's run Object obj = JSON.parse (jsonstr); this way

Results:

SetT1 (), setT2 (), getT4 (), setT5 () are called

JSON.parse (jsonstr) finally returns the object of the FastJsonTest class

Then we run Object obj = JSON.parseObject (jsonstr, FastJsonTest.class)

Results:

Same as JSON.parse (jsonstr); in this way, setT1 (), setT2 (), getT4 (), setT5 () are called

JSON.parse (jsonstr) finally returns the object of the FastJsonTest class

Finally, we run Object obj = JSON.parseObject (jsonstr)

Results:

The result this time is quite different from the last two. All getter and setter in the FastJsonTest class are called, and JSON.parseObject (jsonstr); returns a JSONObject object

From the above running results, it is not difficult to find three problems.

1. Using JSON.parse (jsonstr); and JSON.parseObject (jsonstr, FastJsonTest.class); the results after execution are exactly the same, and the getter and setter method calls in the FastJsonTest class are exactly the same, what is the relationship between parse (jsonstr) and parseObject (jsonstr, FastJsonTest.class)?

two。 Using JSON.parse (jsonstr); and JSON.parseObject (jsonstr, FastJsonTest.class); in both ways, the getter and setter methods called are setT1 (), setT2 (), setT5 (), getT4 (), respectively. There are five getter methods in the FastJsonTest class, namely getT1 (), getT2 (), getT3 (), getT4 (), and getT5 (). Why is only getT4 called?

3. JSON.parseObject (jsonstr); why the return value is a JSONObject class object, and all getter and setter in the FastJsonTest class are called

One answer to the question

After debugging, you can find that whether you use JSON.parse (jsonstr) or JSON.parseObject (jsonstr)

FastJsonTest.class); parses the json string, and the program will eventually call JavaBeanInfo.build () located in com/alibaba/fastjson/util/JavaBeanInfo.java

Method to get and save the member variables in the target Java class and their corresponding setter and getter

First, let's take a look at JSON.parse (jsonstr), when the program executes to JavaBeanInfo.build ()

Method is shown in the following figure

The call chain at this time is shown below.

At this point, the parameter values passed into the JavaBeanInfo.build () method are as follows

Let's take a look at JSON.parseObject (jsonstr).

FastJsonTest.class) in this way, the scenario when the program executes to the JavaBeanInfo.build () method is as follows

The call chain at this time is shown below.

At this point, the parameter values passed into the JavaBeanInfo.build () method are as follows

The comparison between the two call chains when they execute to the JavaBeanInfo.build () method is as follows

It can be seen that the call chain behind the two is exactly the same. The difference between the two is that the call JavaBeanInfo.build ()

The source of the clazz parameter passed in the method is different:

JSON.parseObject (jsonstr, FastJsonTest.class) is calling JavaBeanInfo.build ()

The clazz parameter passed in the method is derived from the "FastJsonTest.class" specified in the second parameter in the parseObject method.

JSON.parse (jsonstr); call JavaBeanInfo.build () in this way

The clazz parameter passed in the method gets the value of the\ @ type field in the json string.

About JSON.parse (jsonstr); get the clazz parameter from the\ @ type field in the json string, as follows

The program parses the\ @ type field value of the passed-in json string to get the JavaBeanInfo.build () passed in later.

The clazz parameter of the method

Therefore, as long as the\ @ type field value of the Json string is matched with JSON.parseObject (jsonstr)

FastJsonTest.class); the class name in the second parameter is the same, as shown in the following figure

The process and result of JSON.parse (jsonstr) and JSON.parseObject (jsonstr,FastJsonTest.class) are exactly the same. The only difference between the two is that the way to get clazz parameters is different.

Answer to question two

> when using JSON.parse (jsonstr) and JSON.parseObject (jsonstr, FastJsonTest.class), the called getter and setter methods are setT1 (), setT2 (), setT5 () and getT4 (), respectively. There are five getter methods in the FastJsonTest class, namely getT1 (), getT2 (), getT3 (), getT4 (), and getT5 (). Why is only getT4 called?

Get the answer to this question from the JavaBeanInfo.build () method:

From the above analysis, it can be found that the program uses JavaBeanInfo.build ()

Method to parse the incoming json string. In JavaBeanInfo.build ()

Method, the program will create an fieldList array to hold the setter of the target class that will be processed later

Method and getter of some specific conditions

Method. As can be seen from the above results, all the setter methods in the target class can be called, but only the getter of getT4 () is called, so what kind of getter?

Method can meet the requirements and be added to the fieldList array?

You can see the following code in the JavaBeanInfo.build () method

The program gets all the public methods in this class and its parent class or interface through getMethods from the clazz (target class object), and then loops to determine whether these methods can be added to the fieldList for subsequent processing.

Condition 1. The method name should be longer than 4.

Condition 2. Not a static method.

Condition 3. Start with a get string, and the fourth character needs to be an uppercase letter

Condition 4. The method cannot have parameters passed in.

Condition 5. Inherited from Collection\ |\ | Map\ |\ | AtomicBoolean\ |\ | AtomicInteger\ |\ |

AtomicLong

Condition 6. This getter cannot have a setter method (the program will first add all the setter in the target class to the fieldList list, so you can determine whether the getter method in this class has setter by reading the fieldList list.)

Answer to question three

Why JSON.parseObject (jsonstr) returns a JSONObject class object and calls all getter and setter in the FastJsonTest class

Through the above analysis, it can be found that JSON.parse (jsonstr) and JSON.parseObject (jsonstr)

FastJsonTest.class) the execution process is almost the same and the result is exactly the same; however, using JSON.parseObject (jsonstr), the execution result and the return value are different from the former two: JSON.parseObject (jsonstr) returns a value of the JSONObject class object, and all getter and setter in the FastJsonTest class are called.

By reading the source code, you can find that the JSON.parseObject (String text) implementation is as follows

ParseObject (String text) actually executes parse (), and then converts the returned Java object through JSON.toJSON () to

JSONObject object.

The JSON.toJSON () method records all getter methods in the target class, as shown in the following figure

All getter methods in the target class are then called in turn through reflection

The complete call chain is as follows

Summary:

In the above example, JSON.parse (jsonstr) and JSON.parseObject (jsonstr, FastJsonTest.class) can be considered exactly the same, while parseObject (String text) executes JSON.toJSON () on the basis of both.

Parse (String text), parseObject (String text) and parseObject (String text, Class\ clazz) target class Setter\\ Getter invocation

| | parse (String text) | parseObject (String text) | parseObject (String text, Class\ clazz) |

| |-- |-- |

| | Setter call status | all | |

| | Getter call | partial | partial | all | |

In addition, if the private variable in the target class does not have a setter method, but still wants to assign a value to the variable when deserializing, you need to use the Feature.SupportNonPublicField parameter. (in the following section, this is the knowledge point used for private variables _ tfactory and _ name assignments without setter methods in the TemplatesImpl class)

TemplatesImpl attack invocation link

Based on the above analysis, it can be found that no matter which way you use to deal with JSON strings, you will have the opportunity to call the Getter method in the target class that meets the requirements.

If the Getter method in a class satisfies the call condition and there is an available point, then the attack chain is generated.

The TemplatesImpl class exactly meets this requirement:

There is a private variable named _ outputPropertiesget in com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl, and there is a utilization point in its getter method. This getter method just satisfies the call condition. It can be called when the JSON string is parsed and will be called when the FastJson.parseObject () is serialized into a Java object. Let's explain it in detail:

First of all, let's start with the leak point and go to the entrance layer by layer: first take a look at the getTransletInstance method in the TemplatesImpl class.

Line 455 calls the newInstance () method of _ class [_ transletIndex] to instantiate the operation of the object.

Let's take a look at how class [_ transletIndex] is obtained and whether it can be controlled.

The\ _ class and _ transletIndex values are both obtained from the defineTransletClasses () method at line 451

Let's follow the defineTransletClasses () method to find out.

In the defineTransletClasses () method, first determine whether the _ bytecodes value is empty at line 393

It is worth noting that the _ bytecodes variable is a member variable of the TemplatesImpl class

Therefore, the _ bytecodes variable can be passed in when constructing the json string, and it is a controllable variable when constructing poc.

When the\ _ bytecodes variable is not null, the program will continue execution to the red box in the following figure

At this point, it is necessary to satisfy that the _ tfactory variable is not null, otherwise it will cause the program to exit abnormally. This is why the public poc needs to set _ tfactory to {

The reason for}. Because _ tfactory is a private variable and there is no setter method, you need to specify the Feature.SupportNonPublicField parameter to assign a value to _ tfactory

Next, the program will loop out the value in the _ bytecodes variable and assign it to _ class [I] after being processed by loader.defineClass.

Let's first take a look at what the loader.defineClass method is.

It can be seen that the loader.defineClass method is actually a method for ClassLoader.

Rewriting of defineClass. The defineClass method can be converted from incoming bytecode to Class

Go back and analyze the above process.

When the\ _ bytecodes variable is non-null, the program loops out the value in the _ bytecodes array, converts the bytecode into a Class object using the loader.defineClass method, and then assigns a value to _ class [I].

If the class is main at this time

The value of the class,_transletIndex variable will be the subscript value in the _ bytecodes array at this time

So when we construct a json string such as _ bytecodes: [evilCode] (the evilCode string is the bytecode of the malicious class we constructed), the program will turn evilCode into a Class object and assign a value to _ class [0]

Now go back to the getTransletInstance () method

The _ class [_ transletIndex] at this time is to construct the incoming evilCode class for us.

The program instantiates the operation of the object by calling the newInstance () method of the evilCode class, which will cause the malicious code in the evilCode class we constructed to be executed.

But before that, you need to make the member variable _ name not empty when poc constructs the json string, otherwise the program will return ahead of time before instantiating the evilCode class.

Note: since the private variable _ name does not have a setter method, you need to use the Feature.SupportNonPublicField parameter to assign a value to this variable when deserializing.

After analyzing the vulnerable getTransletInstance method, we need to find a call chain that needs to be successfully concatenated to the vulnerable getTransletInstance method when using fastjson to process json strings.

We continue to trace the code up.

Com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java

GetTransletInstance () is called in the newTransformer () method

Keep tracking up.

Com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java

NewTransformer () is called in the getOutputProperties () method

The getOutputProperties () method is a getter method with _ outputProperties member variables

Careful readers may find that the member variable _ outputProperties is not exactly the same as its getter method getOutputProperties () method name. With an extra underscore, how does fastjson correspond to it?

In fact, fastjson calls a smartMatch () method when parsing

When looking for the getter method of _ outputProperties, the program leaves the underscore empty, resulting in the form of the member variable _ outputProperties corresponding to the getter method getOutputProperties ().

Interesting combination of FastJson and TemplatesImpl

Let's start with the TemplatesImpl class. After the above analysis, it is found that there is a deserialization utilization chain in TemplatesImpl, and if the getOutputProperties () method of this class is called during deserialization, the code execution vulnerability can be successfully triggered.

Then let's analyze FastJson: according to the condition that the getter method is called when FastJson handles JSON strings in three different ways, the getter method of the TemplatesImpl class _ outputProperties member variable satisfies the condition to be called. No matter how the json string is parsed through fastjson, the getOutputProperties () method is triggered.

The two hit it off: when FastJson deserializes the TemplatesImpl class, it happens to trigger the getOutputProperties () method of the TemplatesImpl class; the trigger of the getOutputProperties () method of the TemplatesImpl class causes a deserialization code execution vulnerability. So this loophole is ingenious to exploit.

After reading the above, do you know how to do in-depth analysis of Fastjson 1.2.24 deserialization vulnerabilities? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report