[하루한줄] CVE-2022-22978: Spring Security 정규식 필터 우회 취약점

URL

Spring Security RegexRequestMatcher Authentication Bypass Vulnerability Analysis (CVE-2022-22978)

Target

  • Spring Security
    • 5.5.x ~ 5.5.7
    • 5.6.x ~ 5.6.4

Explain

Spring Security는 Spring의 인증과 권한, 인가등 보안을 담당하는 프레임워크 입니다.

접근통제 대상에 정규식을 사용하여 필터링 시 5.6.4 이전 버전 프레임워크에서 이를 우회할 수 있는 취약점이 발견되었습니다.

/*
 * web/src/main/java/org/springframework/security/web/util/matcher/RegexRequestMatcher.java
 * commit : 708639
 */
public final class RegexRequestMatcher implements RequestMatcher {
...
-	private static final int DEFAULT = 0;
+	private static final int DEFAULT = Pattern.DOTALL;

+	private static final int CASE_INSENSITIVE = DEFAULT | Pattern.CASE_INSENSITIVE;
...
}

5.6.3 → 5.6.4 패치내역을 보았을 때 Pattern.DOTALL 이 눈에 띄는데요

Pattern.DOTALL\n 과 같은 개행문자를 포함한 모든 문자와 매칭하는 플래그 입니다.

플래그를 설정안했을 때와 Pattern.DOTALL로 설정하는 것은 무슨 차이가 있을까요?

이는 UnitTest 코드에서 확인할 수 있습니다.

/*
 * web/src/test/java/org/springframework/security/web/util/matcher/RegexRequestMatcherTests.java
 */
@Test
public void matchesWithCarriageReturn() {
    RegexRequestMatcher matcher = new RegexRequestMatcher(".*", null);
    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/blah%0a");
    request.setServletPath("/blah\n");
    assertThat(matcher.matches(request)).isTrue();
}

@Test
public void matchesWithLineFeed() {
    RegexRequestMatcher matcher = new RegexRequestMatcher(".*", null);
    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/blah%0d");
    request.setServletPath("/blah\r");
    assertThat(matcher.matches(request)).isTrue();
}

테스트 코드를 보시면 대표적인 개행문자인 \n\r에 대해서 .* 정규식을 통과하는지 판단하고 있습니다. .*는 0개 이상의 모든 문자라고 할 수 있는데요. 하지만 모든 문자에 개행문자는 제외하게 됩니다.

이를 이용하여 간단하게 인증우회가 가능합니다.

public class SecurityConfigDemo1 extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequest().regexMatchers("/admin/.*").authenticated();
    }
}

위와 같이 /admin/ 엔드포인트 진입 시 인증을 요구하도록 설계되어있을 때 /admin/%0d, /admin/%0a과 같이 개행문자를 집어넣으면 해당 필터에 걸리지 않아 우회할 수 있습니다.



본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.