原理大致是这样:spring框架在传参的时候会与对应实体类自动参数绑定,通过“.”还可以访问对应实体类的引用类型变量。使用getClass方法,通过反射机制最终获取tomcat的日志配置成员属性,通过set方法,修改目录、内容等属性成员,达到任意文件写入的目的。

环境:

jdk9、springmvc、tomcat8

一、先看下传参:

定义2个实体类

  1. public class User {
  2. private String username;
  3. private String password;
  4.  
  5. public String getPassword() {
  6. return password;
  7. }
  8.  
  9. public void setPassword(String password) {
  10. this.password = password;
  11. }
  12.  
  13. public String getUsername() {
  14. return username;
  15. }
  16.  
  17. public void setUsername(String username) {
  18. this.username = username;
  19. }
  20.  
  21. public SubTest getSub(){
  22. return new SubTest();
  23. }
  24. }
  1. public class SubTest {
  2. public void setsubfunction(String s){
  3. System.out.println("=====");
  4. System.out.println(s);
  5. System.out.println("=====");
  6. }
  7. }

定义一个Controller类

  1. @RestController
  2. public class HelloController {
  3. @RequestMapping("/rce")
  4. @ResponseBody
  5. public String helloTest(User user) throws IOException {
  6. System.out.println(user.getPassword());
  7. System.out.println(user.getUsername());
  8. return "hello spring : ";
  9. }
  10. }

不管是GET还是POST,只要是Controller接受的方式都可以传参赋值。

利用POST方式,传参

  1. POST /rce HTTP/1.1
  2. Host: 127.0.0.1:8083
  3. Cache-Control: max-age=0
  4. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36
  5. Content-Type: application/x-www-form-urlencoded
  6. Accept-Language: zh-CN,zh;q=0.9
  7. Cookie: JSESSIONID=39A8228CB652B1A3CA4E1B49C87C40AF
  8. Connection: close
  9. Content-Length: 15
  10.  
  11. username=vpanda

这里username=vpanda的传参,调用了User的setUsername方法。

  1. POST /rce HTTP/1.1
  2. Host: 127.0.0.1:8083
  3. Cache-Control: max-age=0
  4. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36
  5. Content-Type: application/x-www-form-urlencoded
  6. Accept-Language: zh-CN,zh;q=0.9
  7. Cookie: JSESSIONID=39A8228CB652B1A3CA4E1B49C87C40AF
  8. Connection: close
  9. Content-Length: 25
  10.  
  11. sub.subfunction=aaaaatest

这里sub.subfunction=aaaaatest,实际调用User的getSub方法,获得SubTest对象后实现setsubfunction方法,传参aaaaatest,最终实现SubTest类型的setsubfunction。

输出

  1. =====
  2. aaaaatest
  3. =====

二、接下去直接看POC的利用链:

  1. class.module.classLoader.resources.context.parent.pipeline.first.pattern=
    class.module.classLoader.resources.context.parent.pipeline.first.suffix=
    class.module.classLoader.resources.context.parent.pipeline.first.directory=
    class.module.classLoader.resources.context.parent.pipeline.first.prefix=
    class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

在这里的实现逻辑是当前user对象getclass获得了类对象,Class类中存在getModule,获得module类对象,而Module类又存在getclassloader方法,最终返回一个类加载器。

调试输出当前类加载器名称

  1. ClassLoader classLoader = user.getClass().getModule().getClassLoader();
  1. System.out.println("===classloader===");
  2. System.out.println(classLoader);
  3. System.out.println("===classloadername===");
  4. System.out.println(classLoader.getClass().getName());
  5. System.out.println("========");
  1. ===classloader===
  2. ParallelWebappClassLoader
  3. context: ROOT
  4. delegate: false
  5. ----------> Parent Classloader:
  6. java.net.URLClassLoader@1b7cc17c
  7.  
  8. ===classloadername===
  9. org.apache.catalina.loader.ParallelWebappClassLoader
  10. ========

通过输出结果可以看到当前对象的类加载器是org.apache.catalina.loader.ParallelWebappClassLoader,

ParallelWebappClassLoader继承WebappClassLoaderBase,WebappClassLoaderBase实现了getResources是WebResourceRoot接口类型,

WebResourceRoot接口存在getContext方法,Context接口类型,继承Container,Container实现parent和getPipeline,Pipeline接口实现getfirst,

最终得到Valve类型,通过类对象遍历所有成员。

  1. Valve first = parallelWebappClassLoader.getResources().getContext().getParent().getPipeline().getFirst();
  2. Class<? extends Valve> aClass = first.getClass();
  3. System.out.println("====DeclaredFields=====");
  4. Field[] fields = aClass.getDeclaredFields();
  5. for (Field field : fields) {
  6. System.out.println(field);
  7. }
  8. System.out.println("====Methods=====");
  9. Method[] methods = aClass.getMethods();
  10. for (Method method : methods) {
  11. System.out.println(method);
  12. }

输出结果,可以看到利用链中几个关键成员的set方法。

  1. ====DeclaredFields=====
  2. private static final org.apache.juli.logging.Log org.apache.catalina.valves.AccessLogValve.log
  3. private volatile java.lang.String org.apache.catalina.valves.AccessLogValve.dateStamp
  4. private java.lang.String org.apache.catalina.valves.AccessLogValve.directory
  5. protected volatile java.lang.String org.apache.catalina.valves.AccessLogValve.prefix
  6. protected boolean org.apache.catalina.valves.AccessLogValve.rotatable
  7. protected boolean org.apache.catalina.valves.AccessLogValve.renameOnRotate
  8. private boolean org.apache.catalina.valves.AccessLogValve.buffered
  9. protected volatile java.lang.String org.apache.catalina.valves.AccessLogValve.suffix
  10. protected java.io.PrintWriter org.apache.catalina.valves.AccessLogValve.writer
  11. protected java.text.SimpleDateFormat org.apache.catalina.valves.AccessLogValve.fileDateFormatter
  12. protected java.io.File org.apache.catalina.valves.AccessLogValve.currentLogFile
  13. private volatile long org.apache.catalina.valves.AccessLogValve.rotationLastChecked
  14. private boolean org.apache.catalina.valves.AccessLogValve.checkExists
  15. protected java.lang.String org.apache.catalina.valves.AccessLogValve.fileDateFormat
  16. protected volatile java.lang.String org.apache.catalina.valves.AccessLogValve.encoding
  17. private int org.apache.catalina.valves.AccessLogValve.maxDays
  18. private volatile boolean org.apache.catalina.valves.AccessLogValve.checkForOldLogs
  19. ====Methods=====
  20. public void org.apache.catalina.valves.AccessLogValve.log(java.io.CharArrayWriter)
  21. public synchronized boolean org.apache.catalina.valves.AccessLogValve.rotate(java.lang.String)
  22. public void org.apache.catalina.valves.AccessLogValve.rotate()
  23. public java.lang.String org.apache.catalina.valves.AccessLogValve.getEncoding()
  24. public void org.apache.catalina.valves.AccessLogValve.setEncoding(java.lang.String)
  25. public void org.apache.catalina.valves.AccessLogValve.setRotatable(boolean)
  26. public boolean org.apache.catalina.valves.AccessLogValve.isRenameOnRotate()
  27. public java.lang.String org.apache.catalina.valves.AccessLogValve.getDirectory()
  28. public void org.apache.catalina.valves.AccessLogValve.setCheckExists(boolean)
  29. public void org.apache.catalina.valves.AccessLogValve.setDirectory(java.lang.String)
  30. public boolean org.apache.catalina.valves.AccessLogValve.isRotatable()
  31. public int org.apache.catalina.valves.AccessLogValve.getMaxDays()
  32. public void org.apache.catalina.valves.AccessLogValve.setMaxDays(int)
  33. public boolean org.apache.catalina.valves.AccessLogValve.isCheckExists()
  34. public java.lang.String org.apache.catalina.valves.AccessLogValve.getFileDateFormat()
  35. public java.lang.String org.apache.catalina.valves.AccessLogValve.getSuffix()
  36. public void org.apache.catalina.valves.AccessLogValve.setRenameOnRotate(boolean)
  37. public void org.apache.catalina.valves.AccessLogValve.setBuffered(boolean)
  38. public boolean org.apache.catalina.valves.AccessLogValve.isBuffered()
  39. public void org.apache.catalina.valves.AccessLogValve.setFileDateFormat(java.lang.String)
  40. public void org.apache.catalina.valves.AccessLogValve.setSuffix(java.lang.String)
  41. public synchronized void org.apache.catalina.valves.AccessLogValve.backgroundProcess()
  42. public java.lang.String org.apache.catalina.valves.AccessLogValve.getPrefix()
  43. public void org.apache.catalina.valves.AccessLogValve.setPrefix(java.lang.String)
  44. public void org.apache.catalina.valves.AbstractAccessLogValve.invoke(org.apache.catalina.connector.Request,org.apache.catalina.connector.Response) throws java.io.IOException,javax.servlet.ServletException
  45. public void org.apache.catalina.valves.AbstractAccessLogValve.log(org.apache.catalina.connector.Request,org.apache.catalina.connector.Response,long)
  46. public int org.apache.catalina.valves.AbstractAccessLogValve.getMaxLogMessageBufferSize()
  47. public void org.apache.catalina.valves.AbstractAccessLogValve.setMaxLogMessageBufferSize(int)
  48. public void org.apache.catalina.valves.AbstractAccessLogValve.setLocale(java.lang.String)
  49. public java.lang.String org.apache.catalina.valves.AbstractAccessLogValve.getLocale()
  50. public boolean org.apache.catalina.valves.AbstractAccessLogValve.getEnabled()
  51. public java.lang.String org.apache.catalina.valves.AbstractAccessLogValve.getCondition()
  52. public void org.apache.catalina.valves.AbstractAccessLogValve.setCondition(java.lang.String)
  53. public java.lang.String org.apache.catalina.valves.AbstractAccessLogValve.getPattern()
  54. public void org.apache.catalina.valves.AbstractAccessLogValve.setConditionUnless(java.lang.String)
  55. public void org.apache.catalina.valves.AbstractAccessLogValve.setIpv6Canonical(boolean)
  56. public java.lang.String org.apache.catalina.valves.AbstractAccessLogValve.getConditionUnless()
  57. public void org.apache.catalina.valves.AbstractAccessLogValve.setPattern(java.lang.String)
  58. public boolean org.apache.catalina.valves.AbstractAccessLogValve.getIpv6Canonical()
  59. public java.lang.String org.apache.catalina.valves.AbstractAccessLogValve.getConditionIf()
  60. public void org.apache.catalina.valves.AbstractAccessLogValve.setConditionIf(java.lang.String)
  61. public void org.apache.catalina.valves.AbstractAccessLogValve.setRequestAttributesEnabled(boolean)
  62. public boolean org.apache.catalina.valves.AbstractAccessLogValve.getRequestAttributesEnabled()
  63. public void org.apache.catalina.valves.AbstractAccessLogValve.setEnabled(boolean)
  64. public java.lang.String org.apache.catalina.valves.ValveBase.toString()
  65. public org.apache.catalina.Valve org.apache.catalina.valves.ValveBase.getNext()
  66. public void org.apache.catalina.valves.ValveBase.setNext(org.apache.catalina.Valve)
  67. public java.lang.String org.apache.catalina.valves.ValveBase.getObjectNameKeyProperties()
  68. public void org.apache.catalina.valves.ValveBase.setContainer(org.apache.catalina.Container)
  69. public java.lang.String org.apache.catalina.valves.ValveBase.getDomainInternal()
  70. public org.apache.catalina.Container org.apache.catalina.valves.ValveBase.getContainer()
  71. public boolean org.apache.catalina.valves.ValveBase.isAsyncSupported()
  72. public void org.apache.catalina.valves.ValveBase.setAsyncSupported(boolean)
  73. public final javax.management.ObjectName org.apache.catalina.util.LifecycleMBeanBase.getObjectName()
  74. public final java.lang.String org.apache.catalina.util.LifecycleMBeanBase.getDomain()
  75. public final javax.management.ObjectName org.apache.catalina.util.LifecycleMBeanBase.preRegister(javax.management.MBeanServer,javax.management.ObjectName) throws java.lang.Exception
  76. public final void org.apache.catalina.util.LifecycleMBeanBase.postRegister(java.lang.Boolean)
  77. public final void org.apache.catalina.util.LifecycleMBeanBase.preDeregister() throws java.lang.Exception
  78. public final void org.apache.catalina.util.LifecycleMBeanBase.postDeregister()
  79. public final void org.apache.catalina.util.LifecycleMBeanBase.setDomain(java.lang.String)
  80. public final synchronized void org.apache.catalina.util.LifecycleBase.init() throws org.apache.catalina.LifecycleException
  81. public final synchronized void org.apache.catalina.util.LifecycleBase.start() throws org.apache.catalina.LifecycleException
  82. public final synchronized void org.apache.catalina.util.LifecycleBase.stop() throws org.apache.catalina.LifecycleException
  83. public final synchronized void org.apache.catalina.util.LifecycleBase.destroy() throws org.apache.catalina.LifecycleException
  84. public org.apache.catalina.LifecycleState org.apache.catalina.util.LifecycleBase.getState()
  85. public java.lang.String org.apache.catalina.util.LifecycleBase.getStateName()
  86. public void org.apache.catalina.util.LifecycleBase.addLifecycleListener(org.apache.catalina.LifecycleListener)
  87. public void org.apache.catalina.util.LifecycleBase.removeLifecycleListener(org.apache.catalina.LifecycleListener)
  88. public org.apache.catalina.LifecycleListener[] org.apache.catalina.util.LifecycleBase.findLifecycleListeners()
  89. public boolean org.apache.catalina.util.LifecycleBase.getThrowOnFailure()
  90. public void org.apache.catalina.util.LifecycleBase.setThrowOnFailure(boolean)
  91. public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
  92. public final void java.lang.Object.wait() throws java.lang.InterruptedException
  93. public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
  94. public boolean java.lang.Object.equals(java.lang.Object)
  95. public native int java.lang.Object.hashCode()
  96. public final native java.lang.Class java.lang.Object.getClass()
  97. public final native void java.lang.Object.notify()
  98. public final native void java.lang.Object.notifyAll()

三、复现

在本地测试实现任意文件写入

将war包传到服务器,dnslog测试

如果使用root权限拉起了tomcat,尝试将ssh公钥写入服务器。

Spring rce CVE-2022-22965的更多相关文章

  1. Spring官宣网传大漏洞,并提供解决方案

    Spring沦陷了!这样的标题这几天是不是看腻了?然而,仔细看看都是拿着之前的几个毫不相干的CVE来大吹特吹.所以,昨天发了一篇关于最近网传的Spring大漏洞的文章,聊了聊这些让人迷惑的营销文.以及 ...

  2. Intellij IDEA 2022 正式发布,这些功能真不错

    Intellij IDEA 2022 正式发布了,作为正版用户,胖哥赶紧更新了一波,好家伙!这几个功能确实很香啊.新版更新的东西真不少,不愧是一个大版本更新. 依赖分析 IDEA的依赖检查.依赖冲突解 ...

  3. Spring 官宣发布 Spring Boot 3.0 第一个里程碑 M1,从 Java 8 提升到 Java 17!

    Spring官方于2022年1月20日发布Spring Boot 3.0.0-M1版本,预示开启了Spring Boot 3.0的里程碑,相信这是通往下一代Spring框架的激动人心的旅程. 接下来一 ...

  4. Spring 6 源码编译和高效阅读源码技巧分享

    一. 前言 Spring Boot 3 RELEASE版本于 2022年11月24日 正式发布,相信已经有不少同学开始准备新版本的学习了,不过目前还不建议在实际项目中做升级,毕竟还有很多框架和中间件没 ...

  5. Apache Dubbo 官方正式发布 Spring 6 & Spring Boot 3 支持

    Dubbo 简介 Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java.Golang 等多语言 SDK 实现.使用 Dubbo 开发的 ...

  6. Spring4Shell的漏洞原理分析

    Spring框架最新的PoC 这两天出来的一个RCE漏洞,但是有以下的条件限制才行: 必须是jdk9及以上 必须是部署在tomcat的应用 是springmvc的或者webflux的应用 具体的可以查 ...

  7. 警惕!Python 中少为人知的 10 个安全陷阱!

    作者:Dennis Brinkrolf 译者:豌豆花下猫@Python猫 原题:10 Unknown Security Pitfalls for Python 英文:https://blog.sona ...

  8. SpringBoot3正式版将于11月24日发布:都有哪些新特性?

    从 2018 年 2 月 28 号发布 Spring Boot 2.0 版本开始,整个 2.X 版本已经经过了 4 年多的时间,累计发布了 95 个不同的版本,而就在前不久,2.X 系列的也已经迎来了 ...

  9. 是时候考虑升级 JDK 17 了

    Spring,作为 Java EE 的事实规范,在2022年11月16日发布了最新的 6.0.0 GA 版本.这个版本是框架后续新生代的初始版本,拥抱持续创新的 OpenJDK 和 Java 生态.新 ...

  10. Nacos详解

    Nacos是什么 欢迎来到Nocos的世界! 组成部分 全称 描述 Na naming/nameServer 即服务注册中心,与 Spring Cloud Eureka 的功能类似. co confi ...

随机推荐

  1. 如何让你的.NET WebAPI程序支持HTTP3?

    下面我将总结构建Http3的经验,以Token Gateway的项目为例,请注意使用Http3之前你需要知道它的限制, Windows Windows 11 版本 22000 或更高版本/Window ...

  2. [转帖]Prometheus 监控之 Blackbox_exporter黑盒监测 [icmp、tcp、http(get\post)、dns、ssl证书过期时间]

    Blackbox_exporter 主动监测主机与服务状态 Prometheus 官方提供的 exporter 之一,可以提供 http.dns.tcp.icmp 的监控数据采集 官方github: ...

  3. [转帖]s3fs - 使用S3FS存储桶目录允许其他用户使用权限

    https://www.coder.work/article/6661505   我在使用S3FS时遇到问题.我正在使用 ubuntu@ip-x-x-x-x:~$ /usr/bin/s3fs --ve ...

  4. [转帖]记录自己安装内存带宽测试工具——Stream过程

    测试环境: CPU:Kunpeng 920 8Core MEM:16G Storage:200G OS:openEuler 20.03 (LTS-SP3) 1 服务器资源监控工具--Stream 1. ...

  5. 手工创建一个带sticky模块的nginx镜像 并且实现容器化负载均衡的方法

    最近想进行容器化运行的nginx反向代理负载均衡服务. 找了一下 dockerhub上面的 nginx 发现里面不包含 sticky模块. 会报错为: nginx: [emerg] unknown d ...

  6. [译]深入了解现代web浏览器(一)

    本文是根据Mariko Kosaka在谷歌开发者网站上的系列文章https://developer.chrome.com/blog/inside-browser-part1/ 翻译而来,共有四篇,该篇 ...

  7. IdentityServer4 系列文章01---密码授权模式

    IdentityServer4实现.Net Core API接口权限认证(快速入门)   什么是IdentityServer4 官方解释:IdentityServer4是基于ASP.NET Core实 ...

  8. 字节码编程,Javassist篇五《使用Bytecode指令码生成含有自定义注解的类和方法》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 到本章为止已经写了四篇关于字节码编程的内容,涉及了大部分的API方法.整体来说对 J ...

  9. 字节码编程,Javassist篇四《通过字节码插桩监控方法采集运行时入参出参和异常信息》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 字节码编程插桩这种技术常与 Javaagent 技术结合用在系统的非入侵监控中,这样 ...

  10. requests模块的高级应用

    requests抓取数据报错 - HttpConnectinPool: - 原因: - 1.短时间内发起了高频的请求导致ip被禁 - 2.http连接池中的连接资源被耗尽 - 解决: - 1.代理 - ...