首发于先知社区
cas client 用于限制匿名用户对某些特定api的访问,在一些特殊的环境下可能会有权限绕过问题。下面分享两个实际生活中遇到的案例。
bypass trick1 ignorePattern
场景
/api/admin这个url是需要cas登陆才能访问的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package today.redteam.controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController public class AdminController {
@RequestMapping("/api/admin") public String admin(){ return "hello admin"; }
}
|
/api/guest这个是公共页面,所有人都可以看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package today.redteam.controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController public class GuestController {
@RequestMapping("/api/guest") public String guest(){ return "hello guest"; } }
|
假设此程序的技术比较老旧,为了实现上面这种需求,那么开发可能会在web.xml中这么配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <filter> <filter-name>CAS Authentication Filter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> <init-param> <param-name>casServerUrlPrefix</param-name> <param-value>https://battags.ad.ess.rutgers.edu:8443/cas</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://www.acme-client.com</param-value> </init-param> <init-param> <param-name>ignorePattern</param-name> <param-value>/api/guest</param-value> </init-param> </filter> <filter-mapping> <filter-name>CAS Authentication Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
这样配置看起来似乎没有问题
利用
但是其实可以被花式绕过。
原理
原因有两点,第一org.jasig.cas.client.authentication.AuthenticationFilter,在匹配时候获取了原生url(未处理../),甚至包括?
后的内容。
第二,filter的匹配模式有四种,默认是按正则匹配。
同理如果配置成CONTAINS也会有类似的问题。
同理封装了这个库的三方库也会有问题,比较流行的是**cas-client-autoconfig-support** ,它常与springboot集成使用,如果有如下配置也会出问题。
1
| cas.ignorePattern=/api/guest
|
修复
所以正确的配置应该改为
1 2 3 4
| <init-param> <param-name>ignorePattern</param-name> <param-value>^/api/guest$</param-value> </init-param>
|
个人认为这个可以算洞(没处理../而且contains这种选项就不应该存在),也可以甩锅给开发没仔细看文档。
bypass trick2 useSuffixPatternMatch
场景
这里假设/admin系列的路由都不允许访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package today.redteam.controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;
@RestController public class AdminController {
@RequestMapping( value = {"/admin"}, method = {RequestMethod.GET} ) public String admin(){ return "hello admin"; }
@RequestMapping( value = {"/admin/api"}, method = {RequestMethod.GET} ) public String admin1(){ return "hello admin1"; }
}
|
这一次开发认真看了文档做了以下配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package today.redteam.config;
import net.unicon.cas.client.configuration.CasClientConfigurerAdapter; import net.unicon.cas.client.configuration.EnableCasClient; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Configuration; import today.redteam.aop.CasAspect;
@Configuration @EnableCasClient public class CasConfig extends CasClientConfigurerAdapter { public CasConfig() { }
public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) { super.configureAuthenticationFilter(authenticationFilter); authenticationFilter.addUrlPatterns(new String[]{"/admin/*"}); }
static { System.setProperty("cas.serverUrlPrefix", "https://cashost.com/cas"); System.setProperty("cas.serverLoginUrl", "https://cashost.com/cas/login"); System.setProperty("cas.clientHostUrl", "http://localhost:8888/"); System.setProperty("cas.validationType", "CAS"); } }
|
/admin这个路由看起来似乎也没有什么问题。
常规的绕过方式也不起作用
利用
但在低版本的springboot上还是能绕过(本地环境是1.5.9.RELEASE)。
原理
原理是在springboot 1.x中useSuffixPatternMatch默认为true,springboot会对路由进行正则匹配。
断点下在org.springframework.web.servlet.mvc.condition.PatternsRequestCondition#getMatchingPattern。
/admin.*自然能匹配上/admin.也就绕过了。
修复
如下关闭setUseSuffixPatternMatch或升级到2.x
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package today.redteam.config;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration @ComponentScan @EnableWebMvc public class AppConfig {
@Bean public HandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping(); mapping.setUseSuffixPatternMatch(false); return mapping; }
}
|