Shiro注入反序列化内存马流程
零溢出 发表于 江西 WEB安全 783浏览 · 2025-06-16 09:28

Apache Shiro是一个轻量级 Java 安全框架,核心功能包括:认证、授权和会话管理。 框架存在反序列化设计缺陷,HTTP请求的Cookie中的RememberMe值会被反序列化解析为 Java 对象,RememberMe值的编码方式为:Java对象->原生序列化->AES。

若攻击者得到服务端使用的AES秘钥,则可以伪造任意序列化数据,可以进一步利用精心构造的序列化数据在服务端反序列化时触发其他类中的方法,从而实现远程代码执行。

一、shiro环境搭建

本项目使用vulhub项目提供的docker环境,使用方式如下

bash
Plain Text
复制代码
访问ip的8080端口即可看到如下登录页,说明环境搭建成功

image.png


此靶场使用Java库:commons-collections:3.2.1、commons-beanutils:1.8.3

二、执行任意Java代码

仅需3步:

1写一段恶意Java代码

2 利用commons-collections环境TemplatesImpl链加载class字节码

3导出payload

新建一个maven项目,pom.xml配置如下,注意,本项目基于Java8

这里的恶意代码就是在/tmp目录下创建一个文件,文件名touch.java

接下来创建出一个java对象并导出序列化文件,TemplatesImpl链可以帮我们完成这一步。TemplatesImpl 是Java XSLT处理的核心类,其内部 _bytecodes 字段允许直接加载字节码。通过构造特殊的反序列化链触发其 getTransletInstance() 方法,可动态加载并执行恶意类(需继承 AbstractTranslet)。在Shiro漏洞利用中,我们通过 InstantiateTransformer 实例化 TrAXFilter 来触发该方法,最终实现任意代码执行。

在Shiro的RememberMe生成时,AES秘钥使用默认的kPH+bIxk5D2deZiIxcaaaA==,请自行根据实际情况替换,第36行main()方法中的

用于获取某个类的字节码,在后面会多次使用此类,本文不再重复贴出代码,请自行替换"touch"为需要加载的类。运行输出:

测试效果

image.png


image.png


三、尝试注入内存马

准备一个内存马文件MemShell.java,这是一个Filter,若请求中存在cmd参数,则执行命令并返回结果,否则正常返回。

运行如下代码将MemShell类的字节码导出为Base64,并copy输出结果。

新建注入类Inject.java,作用是将这个Filter注册进去。第22行的String code=上一个操作输出的MemShell的Base64字节码。

设置ShiroPayload.java中加载的类为Inject并运行,复制输出结果到剪切板。并在Yakit或BurpSuite中构造http请求。

如果发送这个包,将会看到服务器提示这是一个错误的请求,并发现内存马并未成功注入。

image.png


那么这是为什么呢?是因为tomcat中间件对header长度作出了限制,默认大小为8k。

四、成功的尝试

那么我们现在就要尝试开始着手解决header大小的问题了,一个思路是Shiro的Payload不含内存马注入类,而是做一个ShellLoader,这个ShellLoader负责从post data部分获取类的字节码并加载执行。

问题变成了在全局无request对象的情况下,如何获取一个request,只有拿到了request对象,才能获取到请求包中的相关信息。

这里可以借助TomcatEcho通用回显,其获取顺序如下

通过这个链条,我们最终就拿到一个org.apache.catalina.connector.Request对象,此对象继承javax.servlet.http.HttpServletRequest,同时我们还可以通过request.getResponse()构造响应数据。

最终的ShellLoader实现如下

其中getField()实现链式反射获取对象是作者的得意之作,最终虽然说并不能减少多少payload体积大小,但是能以一种非常优雅和直观的方式实现对目标对象的链式反射获取。支持语法如下

1.获取对象下的变量

2.类型标注和强制转换

3.数组和List下标取值

4.组合下标取值和强制转换

5.组合实现TomcatEcho链获取RequestInfo

优雅,非常优雅,对链式调用过程非常直观。

对于缩小编译后的字节码体积,还有一个办法:设置maven编译选项,修改pom.xml

接下来,让我们将这个ShellLoad用ShiroPayload导出吧。记得设置code=...getCtClass("ShellLoader")...再运行。得到payload。(这是RememberMe部分)

我们再生成一下post data部分

输出结果

这部分填充到数据包

yakit可以用这个标签实现url编码

image.png


构造请求包并发出

image.png


成功

image.png


0 条评论
某人
表情
可输入 255