👻
security
  • 计算机技术
  • OWASP TOP 10
  • 名词解释
  • 1
    • 常见端口利用
    • F5 big-ip从环境搭建到漏洞复现
    • 红队资源
  • About
    • APT
      • 海莲花(APT-C-00)
        • 样本分析
      • 毒云藤(APT-C-01)
        • 大规模钓鱼攻击活动披露
        • 2020上半年针对我重要机构定向攻击活动揭秘
      • 响尾蛇(T-APT-04)
        • 利用WebSocket隧道的新型攻击活动披露
      • 蔓灵花(APT-C-08)
        • 移动平台攻击活动揭露
      • 蓝宝菇(APT-C-12)
        • 组织使用云存储技术发起的最新攻击活动披露
      • 双尾蝎组织(APT-C-23)
        • 针对中东地区的最新攻击活动
      • Lazarus(APT-C-26)
        • 暴风行动 -利用MATA框架针对数字货币行业的攻击活动揭秘
      • Fancy Bear(APT-C-28)
        • 携小众压缩包诱饵对北约、中亚目标的定向攻击分析
      • 肚脑虫组织(APT-C-35)
        • 使用升级版数字武器针对周边地区的攻击活动
        • 针对巴基斯坦的攻击活动
      • 拍拍熊(APT-C-37)
      • 军刀狮(APT-C-38)
      • 蓝色魔眼(APT-C-41)
        • 组织首次针对我国重要机构定向攻击活动披露
      • 美人鱼(Infy)
        • 使用最新的Foudre后门进行攻击活动的分析
    • 各类靶场讲解
      • sqli-labs
      • upload-labs
      • xss-labs
    • CISP题库
    • Docker
      • Docker基线
        • docker基线-概述
        • 推荐一
        • 推荐二
        • 推荐三
        • 推荐四
        • 推荐五
        • 推荐六
      • 命令与选项
      • 基于Docker的固件模拟
      • 固件相关
      • Docker 私有仓库搭建
      • 基础命令的背后
      • 渗透思路调研
      • Docker容器环境检测方法【代码】
    • 浏览器
    • markdown
    • 密码学
    • 内网渗透TIPS
    • 网络扫描
    • 正则表达式
  • 操作系统
    • Android
      • APK终端安全分析法
      • 应用审计指南
        • 通用审计方法
    • IOS
      • 应用审计指南
    • Linux
      • 反弹shell
      • 基线检查
      • SHELL编程
      • 实战技能
    • windows
      • BACKDOOR with 权限维持
      • 磁盘取证实验
      • 基线检查
      • 免杀抓取明文
      • payload下载方式
      • powershell
      • 日志分析
        • 分析工具
      • Untitled
  • 数据库
    • db2
    • mysql
      • webshell写入
      • 基础知识
      • 核心技术
      • 高级应用
    • oracle
      • webshell写入
    • SQLserver
      • webshell写入
  • 中间件
    • apache
      • 基线检查
      • 日志审计
    • iis
      • 基线检查
      • 7.5解析绕过漏洞
    • nginx
      • 基线检查
    • tomcat
      • 基线检查
  • 编程语言
    • C
    • Java
      • webshell
        • 查杀Java web filter型内存马
        • Filter/Servlet型内存马的扫描抓捕与查杀
        • 基于内存 Webshell 的无文件攻击技术研究
        • 基于tomcat的内存 Webshell 无文件攻击技术
        • Tomcat 内存马检测
      • 代码审计
      • 代码审计指南
      • 浅析Java命令执行
      • 相关框架简介及漏洞
    • PHP
      • 代码审计
      • 破解DVWA-admin密码
      • webshell
        • 常见php一句话webshell解析
        • PHP Webshell Hidden Learning
        • Webshell免杀研究
        • Webshell那些事-攻击篇
        • 过D盾webshell分享
      • 相关框架简介及漏洞
    • python
      • 安全编码规范-代码审计
      • 编码规范
      • fishc
      • 某教程涉及脚本
      • POC编写相关
      • python秘籍
        • 上半部分
        • 下半部分
      • 安全方面的内容
        • Python Opcode逃逸笔记
        • 虚拟机逃逸
      • with-EXCEL
      • 相关框架简介及漏洞
      • 源码剖析
        • 多线程和GIL锁
        • Set容器
        • 统一内存管理
        • 信号处理机制
        • 循环垃圾回收器
        • 字符串对象PyStringObject
        • 整数对象PyIntObject
        • 字节码和虚拟机
    • 汇编
    • Javascript
      • Tampermonkey Script
  • AIGC
    • howtouse
  • 网络
    • CCNA
  • 漏洞类型及讲解
    • 综合
    • 技术分享
      • 暴力破解与信息泄露
      • 信息泄露漏洞_java
      • sqli-with-java
      • python远程命令执行与SSRF
    • SQL-Injectoin
    • Cross-Site Scripting
      • 跨站的艺术-XSS入门与介绍
      • 跨站的艺术-XSS Fuzzing 的技巧
      • 给开发者的终极XSS防护备忘录
      • AngularJS特性的 XSS
    • 文件操作
      • 文件包含
  • how-to-use
    • Acunetix(AWVS)
      • 安装到使用
      • 编写AWVS脚本探测web services
      • 简单分析-web方面
      • 流量分析特征
    • burpsuite
      • 导出报告方式
      • captcha-killer
      • FAKE-IP
      • JSFind
      • 编写插件绕过WAF
    • Cobalt Strike
      • Cobalt Strike Powershell过360+Defender上线
    • FOFA
    • GDB
    • PowerSh
      • 获得Powershell命令的历史记录
      • 深入分析PowerShell的两面性
      • 内网渗透利器之PowerSploit
      • PoC:滥用PowerShell Core
      • 如何绕过PowerShell访问限制并实现PowerShell代码执行
      • 工具包
      • 无powershell运行powershell方法总结
    • sheji
    • sqlmap
      • Atlas修改SQLMap tampers 绕过WAF/IDS/IPS
      • 内核分析
      • 检测剖析
      • tamper
      • UDF
      • --os-shell
      • sqlmapapi
      • with burp
      • 网络特征
    • Matlab
    • Metasploit
      • 与Powershell
    • NESSUS
      • 流量分析特征
      • Untitled
    • Network MapTools
      • 流量特征修改
      • 识别主机指纹
    • waf
      • ngx-lua-waf
      • modsecurity
由 GitBook 提供支持
在本页
  • 0x01 内存马简历史
  • 0x02 查杀思路
  • 0x03 内存马的识别
  • 0x04 内存马的查杀
  • 0x05 demo展示
  • 0x06 总结

这有帮助吗?

  1. 编程语言
  2. Java
  3. webshell

查杀Java web filter型内存马

上一页webshell下一页Filter/Servlet型内存马的扫描抓捕与查杀

最后更新于4年前

这有帮助吗?

0x01 内存马简历史

其实内存马由来已久,早在17年n1nty师傅的中已初见端倪,但一直不温不火。后经过rebeyong师傅使用加持后,拓展了内存马的使用场景,然终停留在奇技淫巧上。在各类hw洗礼之后,文件shell明显气数已尽。内存马以救命稻草的身份重回大众视野。特别是今年在shiro的回显研究之后,引发了无数安全研究员对内存webshell的研究,其中涌现出了LandGrey师傅构造的。至此内存马开枝散叶发展出了三大类型:

  1. servlet-api类

    • filter型

    • servlet型

  2. spring类

    • 拦截器

    • controller型

  3. Java Instrumentation类

    • agent型

内存马这坛深巷佳酒,一时间流行于市井与弄堂之间。上至安全研究员下至普通客户,人尽皆知。正值hw来临之际,不难推测届时必将是内存马横行天下之日。而各大安全厂商却迟迟未见动静。所谓表面风平浪静,实则暗流涌动。或许一场内存马的围剿计划正慢慢展开。作为攻击方向的研究人员,没有对手就制造对手,攻防互换才能提升内存马技术的发展。

0x02 查杀思路

我们判断逻辑很朴实,利用Java Agent技术遍历所有已经加载到内存中的class。先判断是否是内存马,是则进入内存查杀。

public class Transformer implements ClassFileTransformer {
	public byte[] transform(ClassLoader classLoader, String s, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
	    // 识别内存马
	    if(isMemshell(aClass,bytes)){
	        // 查杀内存马
	        byte[] newClassByte = killMemshell(aClass,bytes);
	        return newClassByte;
	    }else{
	        return bytes;
	    }
    }
}

0x03 内存马的识别

要识别,我们就需要细思内存马有什么特征。下面列下我思考过的检查点。

  1. filter名字很特别

内存马的Filter名一般比较特别,有shell或者随机数等关键字。这个特征稍弱,因为这取决于内存马的构造者的习惯,构造完全可以设置一个看起来很正常的名字。

  1. filter优先级是第一位

为了确保内存马在各种环境下都可以访问,往往需要把filter匹配优先级调至最高,这在shiro反序列化中是刚需。但其他场景下就非必须,只能做一个可疑点。

  1. 对比web.xml中没有filter配置

内存马的Filter是动态注册的,所以在web.xml中肯定没有配置,这也是个可以的特征。但servlet 3.0引入了@WebFilter标签方便开发这动态注册Filter。这种情况也存在没有在web.xml中显式声明,这个特征可以作为较强的特征。

  1. 特殊classloader加载

我们都知道Filter也是class,也是必定有特定的classloader加载。一般来说,正常的Filter都是由中间件的WebappClassLoader加载的。反序列化漏洞喜欢利用TemplatesImpl和bcel执行任意代码。所以这些class往往就是以下这两个:

  • com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl$TransletClassLoader

  • com.sun.org.apache.bcel.internal.util.ClassLoader

这个特征是一个特别可疑的点了。当然了,有的内存马还是比较狡猾的,它会注入class到当前线程中,然后实例化注入内存马。这个时候内存马就有可能不是上面两个classloader。

  1. 对应的classloader路径下没有class文件

所谓内存马就是代码驻留内存中,本地无对应的class文件。所以我们只要检测Filter对应的ClassLoader目录下是否存在class文件。

private static boolean classFileIsExists(Class clazz){
    if(clazz == null){
        return false;
    }

    String className = clazz.getName();
    String classNamePath = className.replace(".", "/") + ".class";
    URL is = clazz.getClassLoader().getResource(classNamePath);
    if(is == null){
        return false;
    }else{
        return true;
    }
}
  1. Filter的doFilter方法中有恶意代码

我们可以把内存中所有的Filter的class dump出来,使用fernflower等反编译工具分析看看,是否存在恶意代码,比如调用了如下可疑的方法:

  • java.lang.Runtime.getRuntime

  • defineClass

  • invoke

  • …

不难分析,内存马的命门在于5和6。简单说就是Filter型内存马首先是一个Filter类,同时它在硬盘上没有对应的class文件。若dump出的class还有恶意代码,那是内存马无疑啦。大致检查的代码如下:

private static boolean isMemshell(Class targetClass,byte[] targetClassByte){
    ClassLoader classLoader = null;
    if(targetClass.getClassLoader() != null) {
        classLoader = targetClass.getClassLoader();
    }else{
        classLoader = Thread.currentThread().getContextClassLoader();
    }

    Class clsFilter =  null;
    try {
        clsFilter = classLoader.loadClass("javax.servlet.Filter");
    }catch (Exception e){
    }

    // 是否是filter
    if(clsFilter != null && clsFilter.isAssignableFrom(targetClass)){
        // class loader 是不是Templates或bcel
        if(classLoader.getClass().getName().contains("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl$TransletClassLoader")
                || classLoader.getClass().getName().contains("com.sun.org.apache.bcel.internal.util.ClassLoader")){
            return true;
        }

        // 是否存在ClassLoader的文件目录下存在对应的class文件
        if(classFileIsExists(targetClass)){
            return true;
        }
        
        // filter是否包含恶意代码。
        String[] blacklist = new String[]{"getRuntime","defineClass","invoke"};
        String clsJavaCode = FernflowerUtils.decomper(targetClass,targetClassByte);
        for(String b:blacklist){
            if(clsJavaCode.contains(b)){
                return true;
            }
        }
    }else{
        return false;
    }
    return false;
}

PS: 本文讨论查杀的思路,给出的代码只是概念正面的伪装代码。完美的方案是将以上6点作为判断指标,并根据指标的重要性赋予不同权重。满足的条件越多越可能是内存马。

0x04 内存马的查杀

内存马识别完成,接下来就是如何查杀了。

方法一: 清除内存马中的Filter的恶意代码

public static byte[] killMemshell(Class clsMemshell,byte[] byteMemshell) throws Exception{
    File file = new File(String.format("/tmp/%s.class",clsMemshell.getName()));
    if(file.exists()){
        file.delete();
    }
    FileOutputStream fos  = new FileOutputStream(file.getAbsoluteFile());
    fos.write(byteMemshell);
    fos.flush();
    fos.close();
    ClassPool cp = ClassPool.getDefault();
    cp.insertClassPath("/tmp/");
    CtClass cc = cp.getCtClass(clsMemshell.getName());
    CtMethod m = cc.getDeclaredMethod("doFilter");
    m.addLocalVariable("elapsedTime", CtClass.longType);
    // 正确覆盖代码:
    // m.setBody("{$3.doFilter($1,$2);}");
    // 方便演示代码:
    m.setBody("{$2.getWriter().write(\"Your memory horse has been killed by c0ny1\");}");
    byte[] byteCode = cc.toBytecode();
    cc.detach();
    return byteCode;
}

方法二: 模拟中间件注销Filter

//反序列化执行代码反射获取到StandardContext
Object standardContext = ...;
Field _filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
_filterConfigs.setAccessible(true);
Object filterConfigs = _filterConfigs.get(standardContext);
Map<String, ApplicationFilterConfig> filterConfigMap = (Map<String, ApplicationFilterConfig>)filterConfigs;
for(Map.Entry<String, ApplicationFilterConfig> map : filterConfigMap.entrySet()){
    String filterName = map.getKey();
    ApplicationFilterConfig filterConfig = map.getValue();
    Filter filterObject = filterConfig.getFilter();
    // 如果是内存马的filter名
    if(filterName.startsWith("memshell")){
        SecurityUtil.remove(filterObject);
        filterConfigMap.remove(filterName);
    }
}

两种方法各有优劣,第一种方法比较通用,直接适配所有中间件。但恶意Filter依然在,只是恶意代码被清除了。第二种方法比较优雅,恶意Filter会被清除掉。但每种中间件注销Filter的逻辑不尽相同,需要一一适配。为了方便演示我们选第一种。

0x05 demo展示

最后给大家展示下,我查杀demo的效果。

查杀演示

0x06 总结

本文我们对Filter型内存马的识别与查杀做了细致的分析,其实Servlet型,拦截器型和Controller型的查杀方法也是万变不离其中,可如法炮制。但这样的思路无法查杀Agent型内存马,Agent型内存马查杀难点在“查”不在“杀”,具体的难点在那,又是如何解决呢?我会在后续的《查杀Java web Agent型内存马》中继续分享我的思考。

查杀演示
《Tomcat源码调试笔记-看不见的shell》
agent技术
Spring controller内存马