RSS Feed
更好更安全的互联网

Fastjson Deserialization Vulnerability History

2020-11-02

Author:Longofo@Knownsec 404 Team 
Time: April 27, 2020 
Chinese version:https://paper.seebug.org/1192/

Fastjson doesn't have a cve number, so it's difficult to find the timeline. At first,I wrote something slowly. Fortunately, fastjson is open source and there are hard work records of other security researchers. This article will give the key updates and vulnerability timelines related to Fastjson and the vulnerabilities,I will test and explain some of the more classic vulnerabilities, and give some check payloads and rce payloads.

Fastjson Parsing Process

You can refer to fastjson process analysis written by @Lucifaer. I will not write it here, and it will occupy a lot of space. In this article said that fastjson has byte code generated using ASM. Since many classes are not native in actual use, fastjson serializes/deserializes most classes will be processed by ASM. You can use idea to save byte files during dynamic debugging:

The inserted code is:

Generated class:

But this class cannot be used for debugging, because the code generated by ASM in fastjson does not have linenumber, trace and other information.However, it should be feasible to generate bytecode by rewriting part of the code in the Expression window.(I have not tested it. If you have enough time or interest, you can see how ASM generates bytecode that can be used for debugging).

Fastjson Demo Test

First test the following example with multiple versions:

Tips:

  • @Type here corresponds to the commonly autotype function , simply understood that fastjson will automatically map the value of key: value of json to the class corresponding to @type.
  • Several methods of the sample User class are relatively common methods, the naming and return values are all conventionally written in accordance with the requirements of the bean, so some special calls in the following sample test will not be covered, but in the vulnerability analysis , We can see some special cases.
  • Parse uses four types of writing, all of which can cause harm (however, whether it can actually be used depends on the version and whether the user has turned on certain configuration switches, see later).
  • The sample tests all use jdk8u102, and the code is the source code test. It mainly uses samples to explain the process of autotype default opening, the appearance of checkautotype, and the version of the black list and white list from which it appears and enhancement methods.
1.1.157 Test

This should be the original version (the earliest tag is this), the result:

Below is a brief explanation of each result.

JSON.parse(serializedStr)

When @type is specified, the default constructor of the User class is automatically called. The setter method(setAge, setName) corresponding to the User class is the final result. It is an instance of the User class, but it is worth noting that the public sex is successfully assigned,while private address is not successfully assigned, but after 1.2.22, 1.1.54.android, a SupportNonPublicField feature is added. If this feature used, private address can be successfully assigned even without setter, getter, this feature is also related to a later vulnerability. Pay attention to the order of the default constructor and setter method. The default constructor comes first. At this time, the property value has not been assigned, so even though there are dangerous methods in the default constructor, the harmful value has not been passed in.The default constructor is logical and will not be a method of exploit, but for the inner class, the outer class first initializes some of its own attribute values, but the inner class default constructor uses some values of the attributes of the parent class, which may still cause harm.

It can be seen that the autotype function has been available since the original version, and autotype is enabled by default. At the same time, there is no blacklist in the ParserConfig class.

JSON.parseObject(serializedStr)

When @type is specified, the default constructor of the User class is automatically called, the setter method (setAge, setName) corresponding to the User class and the corresponding getter method (getAge, getName), and the final result is a string. There are more getter methods (note that the bool type starts with is), because parseObject calls JSON.toJSON (obj) when there are no other parameters, and the obj property value will be obtained through the gettter method later:

JSON.parseObject(serializedStr, Object.class)

When @type is specified, there is no difference between this type of writing and the first type of JSON.parse(serializedStr).

JSON.parseObject(serializedStr, User.class)

When @type is specified, the default constructor of the User class is automatically called, the setter method (setAge, setName) corresponding to the User class, and the final result is an instance of the User class. This way of writing clearly specifies that the target object must be of type User. If the type corresponding to @type is not User or its subclass, a mismatch exception will be thrown. However, even if a specific type is specified, there is still a way before the type matches To trigger the vulnerability.

1.2.10 Test

For the above User class, the test result is the same as 1.1.157, so I won't write it here.

In this version, autotype is still enabled by default. However, from this version, fastjson added denyList in ParserConfig, until version 1.2.24, this denyList has only one class (however, this java.lang.Thread is not used for exploits):

1.2.25 Test

The test result is that an exception is thrown:

Starting from 1.2.25, autotype is turned off by default. For autotype to be turned on, later vulnerability analysis will be involved. And from 1.2.25, the checkAutoType function is added. Its main function is to detect whether the class specified by @type is in the white list or black list (using the startswith method)

And whether the target class is a subclass or subinterface of two dangerous classes (Classloader, DataSource), where the whitelist has the highest priority, and the whitelist does not detect blacklists and dangerous classes if allowed, otherwise it continues to detect blacklists and dangerous classes:

The number of blacklist classes and packages has been increased, and the whitelist has also been added. Users can also call related methods to add blacklist/whitelist to the list:

Many of the latter vulnerabilities are due to the repair of checkautotype and some of its own logical defects, as well as the increasing blacklist.

1.2.42 Test

As with 1.2.25, autotype is not enabled by default, so the result is the same, directly throwing the exception that autotype is not enabled.

From this version, the denyList and acceptList have been replaced with decimal hashcode, which makes the security research more difficult (however, the calculation method of hashcode is still public. If you have a large number of jar packages, such as maven warehouse, you can crawl the jar package, run the class name and package name in batches.But if the blacklist is the package name, it will take some time to find the specific available class):

The detection in checkAutotype has also been modified accordingly:

1.2.61 Test

As the 1.2.25, autotype is not enabled by default, so the result is same, directly throwing the exception that autotype is not enabled.

From 1.2.25 to 1.2.61, a lot of bypasses and blacklists have actually been added, but this part of the vulnerability version line is written specifically. The 1.2.61 version is written here mainly to illustrate the blacklist defens means. In version 1.2.61, fastjson changed the hashcode from decimal to hexadecimal:

However, the hexadecimal representation is the same as the decimal representation, and jar packages can also be run in batches. In version 1.2.62, hex capital was added for uniformity:

The later version is the increase of blacklist.

Fastjson vulnerability version line

The following vulnerabilities will not be analyzed too much. Too many will only briefly explain and give the payload to test and explain the repair method.

ver<=1.2.24

As you can see from the above test, there are no defense in 1.2.24 and before, autotype is enabled by default. Below a few classic payloads.

com.sun.rowset.JdbcRowSetImpl

payload:

Test(jdk=8u102,fastjson=1.2.24):

result:

Brief analysis of triggering reasons:

JdbcRowSetImpl object recovery-> setDataSourceName method call-> setAutocommit method call-> context.lookup (datasourceName) call

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

payload:

Test(jdk=8u102,fastjson=1.2.24):

result:

Brief analysis of triggering reasons:

TemplatesImpl object recovery-> JavaBeanDeserializer.deserialze-> FieldDeserializer.setValue-> TemplatesImpl.getOutputProperties-> TemplatesImpl.newTransformer-> TemplatesImpl.getTransletInstance-> Through defineTransletClasses, newInstance triggers the static code block of our own constructed class

Brief description:

This vulnerability needs to enable the SupportNonPublicField feature, which was also mentioned in the sample test. There is no corresponding setter for _bytecodes,_tfactory_name,_outputProperties and _class in the TemplatesImpl class, so to assign values to these private properties, you need to enable the SupportNonPublicField feature. The specific construction process of the poc will not be analyzed here, you can see Master Liao's this, involving some details.

ver>=1.2.25&ver<=1.2.41

Before 1.2.24, there are no autotype restriction. Starting from 1.2.25, autotype support was turned off by default, and checkAutotype was added. A blacklist and whitelist was added to prevent autotype from being turned on. Between 1.2.25 and 1.2.41, a checkAutotype bypass occurred.

The following is checkAutoType code:

Four position marks were made on it, because the following bypasses are also related to these positions. This time the bypass is through the previous 1, 2, 3 and successfully entered the location 4 to load the target class. Position 4 loadclass is as follows:

Removed the L and ; before and after className, in the form of Lcom.lang.Thread;, this representation method is similar to the representation method of classes in the JVM, and fastjson handles this representation method. The previous blacklist detection was startedwith detection, so you can add L and ; to the class specified by @type to bypass the blacklist detection.

Use the above JdbcRowSetImpl:

Test(jdk8u102,fastjson 1.2.41):

result:

ver=1.2.42

In 1.2.42, the checkAutotype bypass of 1.2.25 ~ 1.2.41 was fixed, the blacklist was changed to decimal, and the checkAutotype detection was changed accordingly:

The blacklist has been changed to decimal, and the detection has been hashed accordingly. However, it is consistent with the detection process in 1.2.25 above, except the tests with startswith are replaced with hash operations. The fix for bypassing checkAutotype of 1.2.25 ~ 1.2.41 is the red box, judging whether the className is L and;, if it is, then intercept the second character and the penultimate character . Therefore, the bypass of checkAutotype in version 1.2.42 is to double write LL and;;. After interception, the process is the same as that of versions 1.2.25 ~ 1.2.41.

Use the above JdbcRowSetImpl:

Test(jdk8u102,fastjson 1.2.42):

结果:

ver=1.2.43

1.2.43 For the bypass repair method of 1.2.42:

Under the first if condition (beginning with L and ending with;), a condition starting withLL is added. If the first condition is met and starting with LL, an exception is thrown directly. So this repair method cannot be bypassed. In addition to the special processing of L and;[ is also treated specially, checkAutoType is bypassed again:

Use the above JdbcRowSetImpl:

Test(jdk8u102,fastjson 1.2.43):

result:

ver=1.2.44

The 1.2.44 version fixes 1.2.43 bypass and handles [:

Deleted the previous judgment of the beginning of L, the end of;, and the beginning ofLL, changed it to an exception of [ at the beginning or an exception at the end of ;, So the previous bypasses were fixed.

ver>=1.2.45&ver<=1.2.46

During these two versions, a blacklist was added and no checkAutotype bypass occurred. Several payloads in the blacklist are given in the RCE Payload at the back, so I won't write them here.

ver=1.2.47

This version has been successfully bypassed without enabling autotype. Analyze this bypass: 1. The use of java.lang.class, this class is not in the blacklist, so checkAutotype can be over. 2. The deserializer corresponding to this java.lang.class class is MiscCodec. When deserialize, it will take the val key value in the json string and load the class corresponding to this val. If fastjson cache is true, it will cache the class corresponding to this val to In the global map 3. If the class with val name is loaded again, autotype is not enabled (because it will detect the black and white list first, so this vulnerability autotype is turned on but not successful), the next step is try to obtain this class from the global map, if it is , return directly.

There have been many analysis of this vulnerability. For details, please refer to this article.

payload:

Test(jdk8u102,fastjson 1.2.47):

result:

ver>=1.2.48&ver<1.2.68

Fixed the bypass of 1.2.47 in 1.2.48. In MiscCodec, where the loadClass is processed, the cache is set to false:

Between 1.2.48 and the latest version 1.2.68, there are added blacklist categories.

ver=1.2.68

1.2.68 is the latest version at present. Safemode was introduced in 1.2.68. When safemode is turned on, @type this specialkey is completely useless. Both whitelist and blacklist do not support autoType.

In this version, in addition to adding a blacklist, a blacklist is also subtracted:

I don't know if there is any other security personnel running out of this blacklist, whether it is a package name or a class name, and then it can be used for malicious exploitation. It is a bit strange anyway.

Detect Fastjson

The more commonly method of detecting Fastjson is to use the dnslog. After detecting it, use RCE Payload one by one. Colleagues said that it is possible to get the paylaod of the echo, but the target container/framework is different, and the echo method will be different. This is a bit difficult ..., let's use dnslog.

dnslog detect

At the present, fastjson detection is common to detect by dnslog mode, in which Inet4Address and Inet6Address are available until 1.2.67. Here are some payloads to be seen (combined with the rand: {} method above, which is more general):

Some RCE Payload

I didn't collect the payload about fastjson before, and I didn't run the jar package .... The following lists are the payloads circulated on the network and some of them deducted from marshalsec and transformed into a payload suitable for fastjson. The jdk version for each payload will not be tested one by one, I don't know how much time it takes to test this. The actual use basically can't be know in this version, whether autotype is turned on or not, the user's configuration, and the user added the blacklist/white or not. so just pass the constructed payload one by one. The basic payload:

The following is a small script that can transfer the basic payload out of various bypass variants, and also adds \u,\x encoding forms:

For example JdbcRowSetImpl results:

Some people also scan maven warehouse packages to find malicious exploits to conform jackson and fastjson. It seems that most of them are looking for jndi-type vulnerabilities. For the blacklist, you can look at this project, it ran to version 1.2.62, most blacklists ran out, but many were package, which specific class still have to look for one by one in the package.

Reference

  1. https://paper.seebug.org/994/#0x03
  2. https://paper.seebug.org/1155/
  3. https://paper.seebug.org/994/
  4. https://paper.seebug.org/292/
  5. https://paper.seebug.org/636/
  6. https://www.anquanke.com/post/id/182140#h2-1
  7. https://github.com/LeadroyaL/fastjson-blacklist
  8. http://www.lmxspace.com/2019/06/29/FastJson-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%AD%A6%E4%B9%A0/#v1-2-47
  9. http://xxlegend.com/2017/12/06/%E5%9F%BA%E4%BA%8EJdbcRowSetImpl%E7%9A%84Fastjson%20RCE%20PoC%E6%9E%84%E9%80%A0%E4%B8%8E%E5%88%86%E6%9E%90/
  10. http://xxlegend.com/2017/04/29/title-%20fastjson%20%E8%BF%9C%E7%A8%8B%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96poc%E7%9A%84%E6%9E%84%E9%80%A0%E5%92%8C%E5%88%86%E6%9E%90/
  11. http://gv7.me/articles/2020/several-ways-to-detect-fastjson-through-dnslog/#0x03-%E6%96%B9%E6%B3%95%E4%BA%8C-%E5%88%A9%E7%94%A8java-net-InetSocketAddress
  12. https://xz.aliyun.com/t/7027#toc-4
  13. <https://zhuanlan.zhihu.com/p/99075925
  14. ...

Too many, thanks all people for their hard work.


Paper

本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1193/

作者:江 | Categories:技术分享 | Tags:

发表评论