Two Tricks Of CAS-CLIENT AUTH Bypass

首发于先知社区

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>

这样配置看起来似乎没有问题
image.png

利用

但是其实可以被花式绕过。

image.png

原理

原因有两点,第一org.jasig.cas.client.authentication.AuthenticationFilter,在匹配时候获取了原生url(未处理../),甚至包括? 后的内容。

image.png

第二,filter的匹配模式有四种,默认是按正则匹配。
image.png

image.png

同理如果配置成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这个路由看起来似乎也没有什么问题。

image.png

常规的绕过方式也不起作用
image.png

image.png

利用

但在低版本的springboot上还是能绕过(本地环境是1.5.9.RELEASE)。

image.png

原理

原理是在springboot 1.x中useSuffixPatternMatch默认为true,springboot会对路由进行正则匹配。

断点下在org.springframework.web.servlet.mvc.condition.PatternsRequestCondition#getMatchingPattern。

image.png

/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;
}

}