Java安全之Spring Security

admin 2024年5月19日23:02:09评论27 views字数 10032阅读33分26秒阅读模式

为了整个思路更加清晰,我要需要提前了解的写在前面。后续的调试环境不至于思路飞来打去

FirewalledRequest

HttpFirewall是Spring Security提供的Http防火墙,它可以用于拒绝潜在的危险请求或者包装这些请求进而控制其行为。通过HttpFirewall可以对各种非法请求提前进行拦截并处理,降低损失。代码层面,HttpFirewall被注入到FilterChainProxy中,并在Spring Security过滤器链执行之前被触发。

HttpFirewall一共有两个实现类。
DefaultHttpFirewall:虽然名字包含Default,但这并不是框架默认的Http防火墙,它只是一个检查相对宽松的防火墙。

Java安全之Spring Security


StrictHttpFirewall:这是一个检查严格的Http防火墙,也是框架默认使用的Http防火墙。

Java安全之Spring Security

DelegatingFilterProxyRegistrationBean

返回一个DelegatingFilterProxy,并注入到servletContext中

Java安全之Spring Security

DelegatingFilterProxy

Java安全之Spring Security

Java安全之Spring Security

看上面的截图,可以理解为拿出来自己持有的bean,然后调用dofilter()方法,所以其的bean也是filter。

靶场

https://github.com/XuCcc/VulEnv/tree/master/springboot/cve_2022_22978

参考,师傅总结的感觉很细,建议可以好好看看

https://www.cnblogs.com/nice0e3/p/16798843.html#springsecurit%E4%BD%BF%E7%94%A8https://xie.infoq.cn/article/2dd97f17e618c55976d9dcf4chttps://blog.csdn.net/yang131peng/article/details/118519468

安全框架,简单说是对访问权限进行控制,应用的安全性包括用户认证(Authentication)用户授权(Authorization)两个部分。

  • 用户认证:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码,系统通过校验用户名和密码来完成认证过程。

  • 用户授权:验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。

一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

绕过antMatchers

   http.authorizeHttpRequests((authorize) -> authorize                        .antMatchers("/admin").authenticated()                )

Java安全之Spring Security

不是/**,**的话,就判断字符串是否包含{}?和/**结尾,并且*第一个顺序需要在倒数第二个位置。否则就会硬匹配传入的字符串。所以后面加个/等路径只要硬匹配不到就可以进行绕过。

Java安全之Spring Security修复

根据代码来看的话,可以在后面加/** 进行修复。当/**结尾,会正对/**前面的路径做同统一拦截。举例子/admin/**,则/admin后面的所有路径都会做拦截。

Java安全之Spring Security

Java安全之Spring Security

绕过regexMatchers

和上面的匹配不同没有/**做后续路由捕获,可以看到regexMatchers走的默认正则匹配。

Java安全之Spring Security

绕过的话正常正则绕过就行。

CVE-2022-22978

影响版本

Spring Security 5.5.x < 5.5.7

Spring Security 5.6.x < 5.6.4

代码用靶场代码即可

Java安全之Spring Security

调用栈

admin:22, WebController (person.xu.vulEnv)invoke0:-1, NativeMethodAccessorImpl (sun.reflect)invoke:62, NativeMethodAccessorImpl (sun.reflect)invoke:43, DelegatingMethodAccessorImpl (sun.reflect)invoke:498, Method (java.lang.reflect)doInvoke:205, InvocableHandlerMethod (org.springframework.web.method.support)invokeForRequest:150, InvocableHandlerMethod (org.springframework.web.method.support)invokeAndHandle:117, ServletInvocableHandlerMethod (org.springframework.web.servlet.mvc.method.annotation)invokeHandlerMethod:895, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)handleInternal:808, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)handle:87, AbstractHandlerMethodAdapter (org.springframework.web.servlet.mvc.method)doDispatch:1067, DispatcherServlet (org.springframework.web.servlet)doService:963, DispatcherServlet (org.springframework.web.servlet)processRequest:1006, FrameworkServlet (org.springframework.web.servlet)doGet:898, FrameworkServlet (org.springframework.web.servlet)service:655, HttpServlet (javax.servlet.http)service:883, FrameworkServlet (org.springframework.web.servlet)service:764, HttpServlet (javax.servlet.http)internalDoFilter:227, ApplicationFilterChain (org.apache.catalina.core)doFilter:162, ApplicationFilterChain (org.apache.catalina.core)doFilter:53, WsFilter (org.apache.tomcat.websocket.server)internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)doFilter:162, ApplicationFilterChain (org.apache.catalina.core)doFilter:327, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilterInternal:58, AuthorizationFilter (org.springframework.security.web.access.intercept)doFilter:117, OncePerRequestFilter (org.springframework.web.filter)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilter:122, ExceptionTranslationFilter (org.springframework.security.web.access)doFilter:116, ExceptionTranslationFilter (org.springframework.security.web.access)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilter:126, SessionManagementFilter (org.springframework.security.web.session)doFilter:81, SessionManagementFilter (org.springframework.security.web.session)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilter:109, AnonymousAuthenticationFilter (org.springframework.security.web.authentication)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilter:149, SecurityContextHolderAwareRequestFilter (org.springframework.security.web.servletapi)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilter:63, RequestCacheAwareFilter (org.springframework.security.web.savedrequest)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilterInternal:150, BasicAuthenticationFilter (org.springframework.security.web.authentication.www)doFilter:117, OncePerRequestFilter (org.springframework.web.filter)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilterInternal:58, DefaultLogoutPageGeneratingFilter (org.springframework.security.web.authentication.ui)doFilter:117, OncePerRequestFilter (org.springframework.web.filter)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilter:237, DefaultLoginPageGeneratingFilter (org.springframework.security.web.authentication.ui)doFilter:223, DefaultLoginPageGeneratingFilter (org.springframework.security.web.authentication.ui)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilter:219, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)doFilter:213, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilter:103, LogoutFilter (org.springframework.security.web.authentication.logout)doFilter:89, LogoutFilter (org.springframework.security.web.authentication.logout)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilterInternal:117, CsrfFilter (org.springframework.security.web.csrf)doFilter:117, OncePerRequestFilter (org.springframework.web.filter)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doHeadersAfter:90, HeaderWriterFilter (org.springframework.security.web.header)doFilterInternal:75, HeaderWriterFilter (org.springframework.security.web.header)doFilter:117, OncePerRequestFilter (org.springframework.web.filter)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilter:110, SecurityContextPersistenceFilter (org.springframework.security.web.context)doFilter:80, SecurityContextPersistenceFilter (org.springframework.security.web.context)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilterInternal:55, WebAsyncManagerIntegrationFilter (org.springframework.security.web.context.request.async)doFilter:117, OncePerRequestFilter (org.springframework.web.filter)doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)doFilterInternal:211, FilterChainProxy (org.springframework.security.web)doFilter:183, FilterChainProxy (org.springframework.security.web)invokeDelegate:354, DelegatingFilterProxy (org.springframework.web.filter)doFilter:267, DelegatingFilterProxy (org.springframework.web.filter)internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)doFilter:162, ApplicationFilterChain (org.apache.catalina.core)doFilterInternal:100, RequestContextFilter (org.springframework.web.filter)doFilter:117, OncePerRequestFilter (org.springframework.web.filter)internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)doFilter:162, ApplicationFilterChain (org.apache.catalina.core)doFilterInternal:93, FormContentFilter (org.springframework.web.filter)doFilter:117, OncePerRequestFilter (org.springframework.web.filter)internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)doFilter:162, ApplicationFilterChain (org.apache.catalina.core)doFilterInternal:201, CharacterEncodingFilter (org.springframework.web.filter)doFilter:117, OncePerRequestFilter (org.springframework.web.filter)internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)doFilter:162, ApplicationFilterChain (org.apache.catalina.core)invoke:197, StandardWrapperValve (org.apache.catalina.core)invoke:97, StandardContextValve (org.apache.catalina.core)invoke:541, AuthenticatorBase (org.apache.catalina.authenticator)invoke:135, StandardHostValve (org.apache.catalina.core)invoke:92, ErrorReportValve (org.apache.catalina.valves)invoke:78, StandardEngineValve (org.apache.catalina.core)service:360, CoyoteAdapter (org.apache.catalina.connector)service:399, Http11Processor (org.apache.coyote.http11)process:65, AbstractProcessorLight (org.apache.coyote)process:890, AbstractProtocol$ConnectionHandler (org.apache.coyote)doRun:1743, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)run:49, SocketProcessorBase (org.apache.tomcat.util.net)runWorker:1191, ThreadPoolExecutor (org.apache.tomcat.util.threads)run:659, ThreadPoolExecutor$Worker (org.apache.tomcat.util.threads)run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)run:750, Thread (java.lang)

我们稍微分析一些spring的filter

Java安全之Spring Security

可以看到是StandardWrapperValve#invoke中定义ApplicationFilterChainJava安全之Spring Security

其调用doFilter走入filter流程

Java安全之Spring Security如下,这里我们主要关注ApplicationFilterConfig[name=springSecurityFilterChain, filterClass=org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean$1]

Java安全之Spring Security

继续走回上面的springSecurityFilterChain,发现FilterChain有如下的15和filter,然后在invokeDelegate()进行过滤链的方法调用。delegate.doFilter(request, response, filterChain);

Java安全之Spring Security

Java安全之Spring Security

FilterChainProxy#doFilterInternal

Java安全之Spring Security

这里调用了httpfirewall的getFirewalledRequest()Java安全之Spring Security

Java安全之Spring Security

这里能看到对一些请求 method,url等做了校验。我们需要绕过健全,这一块也是我们必须要关注的

(1)method,允许一下的7种

Java安全之Spring Security(2)url

Java安全之Spring Security

Java安全之Spring Security

encodedUrlBlocklist = {HashSet@7373}  size = 18 0 = "//" 1 = "" 2 = "%2F%2f" 3 = "%2F%2F" 4 = "%00" 5 = "%25" 6 = "%2f%2f" 7 = "%2f%2F" 8 = "%5c" 9 = "%5C" 10 = "%3b" 11 = "%3B" 12 = "%2e" 13 = "%2E" 14 = "%2f" 15 = "%2F" 16 = ";" 17 = ""decodedUrlBlocklist = {HashSet@7374}  size = 16 0 = "//" 1 = "" 2 = "%2F%2f" 3 = "%2F%2F" 4 = "%00" 5 = "%" 6 = "%2f%2f" 7 = "%2f%2F" 8 = "%5c" 9 = "%5C" 10 = "%3b" 11 = "%3B" 12 = "%2f" 13 = "%2F" 14 = ";" 15 = ""

当url包含上诉字符会报错,导致验证不通过。

同时需要满足字符不在以下的条件,否则也会返回false

!"#$%&'()*+,-./:;<=>?@[]^_`{|}~

Java安全之Spring Security

不允许出现”.”, “/./“  “/.”

Java安全之Spring Security

上诉验证全部通过,返回StrictFirewalledRequest对象

Java安全之Spring Security

后续就是调用virtualFilterChain.doFilter(firewallRequest, firewallResponse);调用之前截图的filter,不再过过多分析了。后续的调用就是前面我们分析的不同的匹配函数绕过。在java的Pattern.compile的.*规则正则匹配中。默认是不会匹配回车换行的。所以导致了绕过了spring路径的校验,在securty的正则规则中也能正则绕过。

fuzz了一下,也确实是如下的结果

Java安全之Spring Security

原文始发于微信公众号(e0m安全屋):Java安全之Spring Security

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月19日23:02:09
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Java安全之Spring Securityhttps://cn-sec.com/archives/2019558.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息