Web安全漏洞之:JDK1.5环境下扫描远程调试端口导致JVM崩溃【JDWP exit error JVMTI_ERROR_NONE(0)】

2023-11-10

问题描述:

对运行在JDK 1.5版本下的java应用服务器进行端口扫描,扫描的方式可以用相关扫描软件,最简单的是直接用ping/telnet命令,有闲情还可以自己写一段代码进行socket连接,扫描时会发现java进程crash,经测试百发百中;查看运行日志显示:
ERROR: transport error 202: handshake failed - received >GET / HTTP/1.0< - excepted >JDWP-Handshake< ["transport.c",L41]
JDWP exit error JVMTI_ERROR_NONE(0): could not connect, timeout or fatal error

问题原因:

该故障是JVM远程debug存在的缺陷,只有在开启远程debug端口时才会出现;原因是由于接收到不符合JDWP协议的数据包,导致JVM崩溃。
该问题早已确认为JDK的一个bug,具体见6339385:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6339385 中的描述;
要确认系统中是否存在该漏洞,可以检查java启动参数中是否有如下相关配置:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8787
或者-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787
若存在相关配置,那就说明java启动了远程调试端口,就会存在该漏洞;此时JVM虚拟机作为调试的服务提供端,通过8787端口监听一个连接,而调试器通过该连接与虚拟机进行交互。
目前,Windows平台的JVM提供了两种方式的连接:共享内存和 Socket连接,共享内存的服务提供端和调试端只能位于同一台机,而Socket连接则支持不同异机调试,即远程调试。
关于jdwp的参数列表详见官方文档:http://download-llnw.oracle.com/javase/1.5.0/docs/guide/jpda/conninv.html#Invocation
从官方文档中摘录几个配置事例:
-Xrunjdwp:transport=dt_socket,server=y,address=8000
在8000端口监听Socket连接,挂起VM(suspend默认为y)并且不加载运行主函数直到调试请求到达
-Xrunjdwp:transport=dt_shmem,server=y,suspend=n
选择一个可用的共享内存(因为没有指定address)并监听该内存连接,同时加载运行主函数,不挂起VM
-Xrunjdwp:transport=dt_socket,address=myhost:8000
连接到myhost:8000提供的调试服务(server=n,以调试客户端存在),挂起VM并且不加载运行主函数
-Xrunjdwp:transport=dt_shmem,address=mysharedmemory
通过共享内存的方式连接到调试服务,挂起VM并且不加载运行主函数
-Xrunjdwp:transport=dt_socket,server=y,address=8000,onthrow=java.io.IOException,launch=/usr/local/bin/debugstub
等待java.io.IOException被抛出,然后挂起VM并监听8000端口连接,在接到调试请求后以命令/usr/local/bin/debugstub dt_socket myhost:8000执行
-Xrunjdwp:transport=dt_shmem,server=y,onuncaught=y,launch=d:/bin/debugstub.exe
等待一个RuntimeException被抛出,然后挂起VM并监听一个可用的共享内存,在接到调试请求后以命令d:/bin/debugstub.exe dt_shmem <address>执行,<address>是可用的共享内存

问题解决:

应该说该问题并不算太严重,因为一般线上运行的应用都不会开启远程Debug模式,各应用服务器的默认配置也是不开启的,就算开启了该debug端口也会有防火墙保护,外网访问不到。
彻底解决该问题的方法有两种,任选其一即可:
1、在JDK1.5环境下关闭远程调试模式,开发测试环境下无所谓,但线上环境的部署脚本一定要仔细review才行;
2、升级JDK到1.6b49以上版本,这就要看应用的兼容性了,一般来说不会有什么问题;

再往前试试:深入Java调试体系JPDA(Java Platform Debugger Architecture)

对于Java虚拟机接口熟悉的人来说,您一定还记得Java提供了两个接口体系,JVMPI(Java Virtual Machine Profiler Interface)和 JVMDI(Java Virtual Machine Debug Interface),而它们,以及在 Java SE 5 中准备代替它们的 JVMTI(Java Virtual Machine Tool Interface),都是 Java 平台调试体系(Java Platform Debugger Architecture,JPDA)的重要组成部分。 Java SE 自 1.2.2 版就开始推出 Java 平台调试体系结构(JPDA)工具集,而从 JDK 1.3.x 开始,Java SDK 就提供了对 Java 平台调试体系结构的直接支持。顾名思义,这个体系为开发人员提供了一整套用于调试 Java 程序的 API,是一套用于开发 Java 调试工具的接口和协议。本质上说,它是我们通向虚拟机,考察虚拟机运行态的一个通道,一套工具。理解这一点对于学习 JPDA 非常重要。
换句话说,通过 JPDA 这套接口,我们就可以开发自己的调试工具。通过这些 JPDA 提供的接口和协议,调试器开发人员就能根据特定开发者的需求,扩展定制 Java 调试应用程序,开发出吸引开发人员使用的调试工具。前面我们提到的 IDE 调试工具都是基于 JPDA 体系开发的,区别仅仅在于它们可能提供了不同的图形界面、具有一些不同的自定义功能。另外,我们要注意的是,JPDA 是一套标准,任何的 JDK 实现都必须完成这个标准,因此,通过 JPDA 开发出来的调试工具先天具有跨平台、不依赖虚拟机实现、JDK 版本无关等移植优点,因此大部分的调试工具都是基于这个体系的。

JPDA 组成模块

JPDA 定义了一个完整独立的体系,它由三个相对独立的层次共同组成,而且规定了它们三者之间的交互方式,或者说定义了它们通信的接口。这三个层次由低到高分别是 Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP)以及 Java 调试接口(JDI)。这三个模块把调试过程分解成几个很自然的概念:调试者(debugger)和被调试者(debuggee),以及他们中间的通信器。被调试者运行于我们想调试的 Java 虚拟机之上,它可以通过 JVMTI 这个标准接口,监控当前虚拟机的信息;调试者定义了用户可使用的调试接口,通过这些接口,用户可以对被调试虚拟机发送调试命令,同时调试者接受并显示调试结果。在调试者和被调试着之间,调试命令和调试结果,都是通过 JDWP 的通讯协议传输的。所有的命令被封装成 JDWP 命令包,通过传输层发送给被调试者,被调试者接收到 JDWP 命令包后,解析这个命令并转化为 JVMTI 的调用,在被调试者上运行。类似的,JVMTI 的运行结果,被格式化成 JDWP 数据包,发送给调试者并返回给 JDI 调用。而调试器开发人员就是通过 JDI 得到数据,发出指令。下图就展示了三者间的交互过程:

下面就简单介绍下这三个模块的主要功能:

Java 虚拟机工具接口(JVMTI)

JVMTI(Java Virtual Machine Tool Interface)即指 Java 虚拟机工具接口,它是一套由虚拟机直接提供的 native 接口,它处于整个 JPDA 体系的最底层,所有调试功能本质上都需要通过 JVMTI 来提供。通过这些接口,开发人员不仅调试在该虚拟机上运行的 Java 程序,还能查看它们运行的状态,设置回调函数,控制某些环境变量,从而优化程序性能。我们知道,JVMTI 的前身是 JVMDI 和 JVMPI,它们原来分别被用于提供调试 Java 程序以及 Java 程序调节性能的功能。在 J2SE 5.0 之后 JDK 取代了 JVMDI 和 JVMPI 这两套接口,JVMDI 在最新的 Java SE 6 中已经不提供支持,而 JVMPI 也计划在 Java SE 7 后被彻底取代。

Java 调试交互协议(JDWP)

JDWP(Java Debug Wire Protocol)是一个为 Java 调试而设计的一个通讯交互协议,它定义了调试器和被调试程序之间传递的信息的格式。在 JPDA 体系中,作为前端(front-end)的调试者(debugger)进程和后端(back-end)的被调试程序(debuggee)进程之间的交互数据的格式就是由 JDWP 来描述的,它详细完整地定义了请求命令、回应数据和错误代码,保证了前端和后端的 JVMTI 和 JDI 的通信通畅。比如在 Sun 公司提供的实现中,它提供了一个名为 jdwp.dll(jdwp.so)的动态链接库文件,这个动态库文件实现了一个 Agent,它会负责解析前端发出的请求或者命令,并将其转化为 JVMTI 调用,然后将 JVMTI 函数的返回值封装成 JDWP 数据发还给后端。
另外,这里需要注意的是 JDWP 本身并不包括传输层的实现,传输层需要独立实现,但是 JDWP 包括了和传输层交互的严格的定义,就是说,JDWP 协议虽然不规定我们是通过 EMS 还是快递运送货物的,但是它规定了我们传送的货物的摆放的方式。在 Sun 公司提供的 JDK 中,在传输层上,它提供了 socket 方式,以及在 Windows 上的 shared memory 方式。当然,传输层本身无非就是本机内进程间通信方式和远端通信方式,用户有兴趣也可以按 JDWP 的标准自己实现。

Java 调试接口(JDI)

JDI(Java Debug Interface)是三个模块中最高层的接口,在多数的 JDK 中,它是由 Java 语言实现的。 JDI 由针对前端定义的接口组成,通过它,调试工具开发人员就能通过前端虚拟机上的调试器来远程操控后端虚拟机上被调试程序的运行,JDI 不仅能帮助开发人员格式化 JDWP 数据,而且还能为 JDWP 数据传输提供队列、缓存等优化服务。从理论上说,开发人员只需使用 JDWP 和 JVMTI 即可支持跨平台的远程调试,但是直接编写 JDWP 程序费时费力,而且效率不高。因此基于 Java 的 JDI 层的引入,简化了操作,提高了开发人员开发调试程序的效率。
如下就总结了三个模块的不同点:

Java 调试接口的特点

Java 语言是第一个使用虚拟机概念的流行的编程语言,正是因为虚拟机的存在,使很多事情变得简单而轻松,掌握了虚拟机,就掌握了内存分配、线程管理、即时优化等等运行态。同样的,Java 调试的本质,就是和虚拟机打交道,通过操作虚拟机来达到观察调试我们自己代码的目的。这个特点决定了 Java 调试接口和以前其他编程语言的巨大区别。
以 C/C++ 的调试为例,目前比较流行的调试工具是 GDB 和微软的 Visual Studio 自带的 debugger,在这种 debugger 中,首先,我们必须编译一个“ debug ”模式的程序,这个会比实际的 release 模式程序大很多。其次,在调试过程中,debugger 将会深层接入程序的运行,掌握和控制运行态的一些信息,并将这些信息及时返回。这种介入对运行的效率和内存占用都有一定的需求。基于这些需求,这些 Debugger 本身事实上是提供了,或者说,创建和管理了一个运行态,因此他们的程序算法比较复杂,个头都比较大。对于远端的调试,GDB 也没有很好的默认实现,当然,C/C++ 在这方面也没有特别大的需求。
而 Java 则不同,由于 Java 的运行态已经被虚拟机所很好地管理,因此作为 Java 的 Debugger 无需再自己创造一个可控的运行态,而仅仅需要去操作虚拟机就可以了。 Java 的 JPDA 就是一套为调试和优化服务的虚拟机的操作工具,其中,JVMTI 是整合在虚拟机中的接口,JDWP 是一个通讯层,而 JDI 是前端为开发人员准备好的工具和运行库。
从构架上说,我们可以把 JPDA 看作成是一个 C/S 体系结构的应用,在这个构架下,我们可以方便地通过网络,在任意的地点调试另外一个虚拟机上的程序,这个就很好地解决了部署和测试的问题,尤其满足解决了很多网络时代中的开发应用的需求。前端和后端的分离,也方便用户开发适合于自己的调试工具。
从效率上看,由于 Java 程序本身就是编译成字节码,运行在虚拟机上的,因此调试前后的程序、内存占用都不会有大变化(仅仅是启动一个 JDWP 所需要的内存),任意程度都可以很好地调试,非常方便。而 JPDA 构架下的几个组成部分,JDWP 和 JDI 都比较小,主要的工作可以让虚拟机自己完成。
从灵活性上,Java 调试工具是建立在强大的虚拟机上的,因此,很多前沿的应用,比如动态编译运行,字节码的实时替换等等,都可以通过对虚拟机的改进而得到实现。随着虚拟机技术的逐步发展和深入,各种不同种类,不同应用领域中虚拟机的出现,各种强大的功能的加入,给我们的调试工具也带来很多新的应用。
总而言之,一个先天的,可控的运行态给 Java 的调试工作,给 Java 调试接口带来了极大的优势和便利。通过 JPDA 这个标准,我们可以从虚拟机中得到我们所需要的信息,完成我们所希望的操作,更好地开发我们的程序。

 

 

更多关于JPDA的详细介绍可参考:
JVMTI 和 Agent 实现:http://www.ibm.com/developerworks/cn/java/j-lo-jpda2/index.html
Java 调试接口(JDI):http://www.ibm.com/developerworks/cn/java/j-lo-jpda4/index.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Web安全漏洞之:JDK1.5环境下扫描远程调试端口导致JVM崩溃【JDWP exit error JVMTI_ERROR_NONE(0)】 的相关文章

随机推荐

  • Android studio 向项目里倒入model

    第一步 选择对应的model 倒入 第二步 完成第一步后 在项目列表里出现倒入的model 修改倒入的model的build gradle 1 如果有 apply plugin com android application 改为 appl
  • Android 7.1 GUI系统-surfaceflinger(四)

    surfaceflinger的启动 Android P 图形显示系统 https www jianshu com u f92447ae8445 Android GUI系统之SurfaceFlinger https blog csdn net
  • 使用libcurl下载文件小例

    libcurl是一个很强大的开源网络处理库 支持包括HTTP HTTPS FTP 一系列网络协议 用它来进行HTTP的get post 或者下载文件更是小菜一碟 chrome内核都用到了它 本文主要讲解一个使用curl下载文件的小例 首先是
  • 数据库的导入导出及授权

    目录 数据库导出 数据库导入 数据库授权 1 忘记root密码 2 创建表时 colume使用的时 mysql 保留字导致报错 数据库导出 1 导出数据库为bname的表结构 其中用户名为root 密码为dbpasswd 生成的脚本名为db
  • 判断素数 C C++两个版本

    题目 输入一个数 判断是否是素数 C代码 include
  • Midjourney2023下载使用详细操作方法教程

    手把手教你入门绘图超强的AI绘画程序Midjourney 用户只需要输入一段图片的文字描述 即可生成精美的绘画 下面是Midjourney注册和使用的方法 第一步 先注册一个Discord账号https discord gg 注册的时候要人
  • 第三十四章、PyQt中的输入部件:QComboBox组合框功能详解

    专栏 Python基础教程目录 专栏 使用PyQt开发图形界面Python应用 专栏 PyQt入门学习 老猿Python博文目录 一 概述 Designer中输入工具部件中的Combo Box组合框与其他可视化工具组合框功能相同 组合了按钮
  • 《QDebug 2023年1月》

    一 Qt Widgets 问题交流 二 Qt Quick 问题交流 三 其他 1 QScreen grabWindow 截屏 如果没有指定范围 默认是截取对应屏幕的区域 QScreen文档https doc qt io qt 5 15 qs
  • 在控制台打印1000以内的所有素数(质数)

    素数 质数 的定义 质数是指在大于1的自然数中 除了1和它本身以外不再有其他因数的自然数 编程思路 根据定义可以知道 代码应该包括两个循环 外层循环用于遍历范围内的每一个数 可以定义为i 内存循环则用来遍历由2至小于i的数 此处在遍历1和i
  • 挂马方式研究、挂马检测技术研究

    1 挂马定义 所谓的挂马 就是黑客通过各种手段 包括SQL注入 网站敏感文件扫描 服务器漏洞 网站程序0day 等各种方法获得网站管理员账号 然后登陆网站后台 通过数据库 备份 恢复 或者上传漏洞获得一个webshell 利用获得的webs
  • 目标检测算法之YOLOV2

    YOLOV2论文对v1中许多地方都进行了相关的改进和提升 其将骨干网络也进行了更换 不在使用v1的骨干网络 其v2骨干模型结构图如下 作者删去了骨干网络最下面的三层操作 接上了三个卷积核一个高维度特征与低维度特征的融合 并最终生成模型输出
  • 获取进程pid并添加数组,去重。

    var cmd process platform win32 tasklist ps aux var exec require child process exec var qqname qq Array prototype unique1
  • TV模型图像修复 matlab

    原lena 随手截的噪声图 合成的需要修复的图 修复后的图 没有处理边界 对于从来没有接触过图像修复的我来说 效果真是惊艳了 下面介绍运算步骤 和各项异性扩散类似 整个算法也是基于迭代的 迭代公式如下 其中Io代表当前处理的像素 Ip代表邻
  • Java代码规范检查插件调研及总结

    代码规范工具对比 代码规范工具是什么 大家应该都有过写完代码后review的情况 用于提高编码质量 尽早的发现问题 节约开发时间和成本 但review 这个过程往往要消耗 更多的开发资源 所以就出现 自动检测可能代码中存在的问题的工具 我们
  • nrichIP分析command tools(Sodan接口调用查询)

    nrichIP分析command tools 一 项目简介 nrich是一种命令行工具 可快速分析文件中的所有 IP 并查看哪些具有开放端口 漏洞 也可以从标准输入输入数据以在数据管道中使用 二 项目本地部署 1 项目地址 https gi
  • OpenCV样本训练经验

    从下述几篇文章中总结 OpenCV中Adaboost训练的经验总结 采用opencv cascadetrain进行训练的步骤及注意事项 使用opencv traincascade训练遇到的问题总汇 在讲下面内容时首先应先清楚一件事情 自己收
  • 微信营销最重要的是什么

    随着移动互联网的迅速发展 微信已经成为了企业进行营销的重要平台之一 然而 众多企业在微信上进行营销 不同的策略和方法层出不穷 那么 微信营销最重要的是什么呢 本文将深入探讨这个问题 揭示微信营销的核心要素 1 用户价值和体验 微信营销最重要
  • CSDN 添加目录及基本操作(保姆级教程)

    文章目录 1 步骤 1 步骤 1 点击发布 2 这里点击右上角的使用MD编辑器 3 界面介绍 最左边是编辑区 中间视图区 最右边是语法说明区 也就是直接引用区 4 目录操作 toc 文章名称 在使用完在使用完 toc 操作后 对应的我们复制
  • spring boot和activiti的demo

    开发十年 就只剩下这套Java开发体系了 gt gt gt 1 添加依赖
  • Web安全漏洞之:JDK1.5环境下扫描远程调试端口导致JVM崩溃【JDWP exit error JVMTI_ERROR_NONE(0)】

    问题描述 对运行在JDK 1 5版本下的java应用服务器进行端口扫描 扫描的方式可以用相关扫描软件 最简单的是直接用ping telnet命令 有闲情还可以自己写一段代码进行socket连接 扫描时会发现java进程crash 经测试百发