Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
shiro-cve-2020-17523 — shiro-cve-2020-17523 취약점의 두 가지 우회 방식 분석 및 관련 취약점 환경 | Kitploit
도구/GitHubGitHub/jweny/shiro-cve-2020-17523
Authentication & AuthorizationVulnerability AnalysisWeb Application ExploitationPenetration TestingLearning & EducationLabs & Practice
GitHubjweny/shiro-cve-2020-17523

shiro-cve-2020-17523

shiro-cve-2020-17523 취약점의 두 가지 우회 방식 분석 및 관련 취약점 환경

저장소 보기
118115년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Apache Shiro 두 가지 방식 인증 우회 분석 (CVE-2020-17523)

0x01 취약점 설명

Apache Shiro는 강력하고 사용하기 쉬운 Java 보안 프레임워크로, 인증, 권한 부여, 암호 및 세션 관리를 수행합니다. Shiro의 이해하기 쉬운 API를 사용하면 가장 작은 모바일 애플리케이션에서 가장 큰 네트워크 및 엔터프라이즈 애플리케이션에 이르기까지 모든 애플리케이션을 빠르고 쉽게 구현할 수 있습니다.

Spring과 함께 사용할 때, 특정 권한 매칭 규칙 하에서 공격자는 특수하게 조작된 HTTP 요청 패킷을 구성하여 인증을 우회할 수 있습니다.

영향 범위: Apache Shiro < 1.7.1

0x02 취약점 환경 구축

shiro 1.7.0

https://github.com/jweny/shiro-cve-2020-17523 두 가지 방식의 취약점 환경이 모두 업데이트되었습니다.

0x03 poc 테스트

방식 1:

http://127.0.0.1:8080/admin/%20 또는 http://127.0.0.1:8080/admin/%20/

공백 등의 빈 문자를 사용하여 shiro 인증을 우회할 수 있습니다.

image-20210205120522547

방식 2:

p0desta 님과의 논의 결과, 또 다른 특수 시나리오에서의 이용 방식이 발견되었습니다.

http://127.0.0.1:8080/admin/%2e 또는 http://127.0.0.1:8080/admin/%2e/

하지만 . (그리고 /)는 Spring의 경로 매칭 규칙에서 경로 구분자로 취급되며, 일반 문자로 매칭되지 않습니다. 따라서 기본 조건에서 /admin/.에 접근하면 404가 반환됩니다.

그러나 전체 경로 모드가 활성화된 경우 setAlwaysUseFullPath(true)에서는 정상적으로 매칭됩니다.

image-20210205102100797

0x04 취약점 분석

Shiro에서 URL을 가져오고 매칭하는 부분은 org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain에 있습니다.

먼저 getChain 메서드를 간단히 살펴보겠습니다.

carbon (2)

image-20210205103341569

이 메서드는 먼저 requestURI가 /로 끝나는지 확인하고, 그렇다면 마지막 /를 제거합니다.

그런 다음 경로 매칭 루프에서 먼저 경로 규칙 pathPattern이 /로 끝나는지 확인하고, 그렇다면 역시 제거합니다. 그런 다음 pathMatches() 메서드를 호출하여 경로 매칭을 수행합니다.

따라서 두 가지 이용 방식에서 /로 끝나는지 여부는 중요하지 않습니다. getChain 메서드를 통과하면 제거되기 때문입니다.

4.1 공백 우회 분석

pathMatches() 메서드를 살펴보겠습니다.

Evaluate를 열어 pathMatches("/admin/*","/admin/1")와 pathMatches("/admin/*","/admin/ ")를 각각 계산해 보면, 전자는 정상적으로 매칭되고 후자는 매칭에 실패합니다.

image-20210203134044268

image-20210203134119174

디버깅을 시작합니다. 오랜 F7 과정을 거쳐 doMatch("/admin/*","/admin/ ")에 도달합니다. tokenizeToStringArray가 반환한 pathDirs에 두 번째 경로 레벨이 없는 것을 확인할 수 있습니다. 따라서 /admin/*와 /admin 이 매칭되지 않습니다.

image-20210203150854085

tokenizeToStringArray 메서드를 따라가 보면, 해당 메서드를 호출할 때 trimTokens 매개변수가 true임을 확인할 수 있습니다.

image-20210203150959413

tokenizeToStringArray 메서드는 trimTokens가 true일 때 trim() 처리를 거치므로 공백이 제거됩니다. 다시 getChain으로 돌아가면 마지막 /가 제거됩니다. 따라서 tokenizeToStringArray가 반환한 pathDirs에 두 번째 경로 레벨이 없습니다.

image-20210203151053344

요약하자면, 취약한 shiro 버전에서는 tokenizeToStringArray 메서드 호출 시 trimTokens 매개변수가 기본적으로 true이므로 공백이 trim() 처리되어 제거됩니다. 다시 getChain으로 돌아가면 마지막 /가 제거되므로 /admin과 /admin/*의 매칭이 실패하여 인증 우회가 발생합니다. 반면 Spring이 수신하는 접근 경로는 /admin/%20이므로 정상적인 로직으로 응답을 반환하여 권한 우회가 발생합니다.

4.2 /./ 우회 분석

두 번째 방식인 /.와 /./을 보면, 익숙한 메서드가 떠오르지 않나요? 바로 normalize()입니다.

carbon (3)

간단히 번역하면 다음과 같습니다.

조건예시
슬래시를 백슬래시로 처리\ -> /
이중 슬래시를 슬래시로 처리// -> /
/. 또는 /..로 끝나면 끝에 / 추가/. -> /./ /.. -> /../
/./ 정규화 처리

따라서 /admin/.는 /admin/./로 처리된 후 /admin/이 됩니다.

image-20210205113301788

org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain 처리를 거쳐, /로 끝나므로 마지막 /를 제거하여 /admin이 됩니다. /admin은 /admin/*와 매칭되지 않으므로 shiro 인증을 우회합니다.

image-20210205113518970

이때 Spring이 수신한 요청은 /admin/.입니다. 전체 경로 매칭이 활성화되지 않은 경우, Spring에서 .와 /는 경로 구분자로 취급되어 경로 매칭에 참여하지 않습니다. 따라서 매핑을 찾을 수 없어 404를 반환합니다.

image-20210205114350972

전체 경로 매칭이 활성화된 경우 전체 URL을 매칭하므로 Spring이 200을 반환합니다.

여기에 전체 경로 매칭을 활성화하는 코드를 첨부합니다.

root@kitploit:~
@SpringBootApplication
public class SpringbootShiroApplication extends SpringBootServletInitializer implements BeanPostProcessor {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(SpringbootShiroApplication.class);
    }

    public static void main(String[] args) {

        SpringApplication.run(SpringbootShiroApplication.class, args);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof RequestMappingHandlerMapping) {
            ((RequestMappingHandlerMapping) bean).setAlwaysUseFullPath(true);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }
}

0x05 공식 수정 방안

위 분석을 통해 shiro 권한 우회의 원인은 두 가지입니다.

  1. tokenizeToStringArray 함수가 공백을 올바르게 처리하지 않음.
  2. 마지막 /를 처리하는 로직이 경로 매칭 루프 이전에 위치해서는 안 됨.

따라서 공식 수정 방안은 다음과 같습니다.

https://github.com/apache/shiro/commit/0842c27fa72d0da5de0c5723a66d402fe20903df

  1. tokenizeToStringArray의 trimTokens 매개변수를 false로 설정. image-20210203154342100
  2. 마지막 /를 제거하는 로직 조정. 먼저 원래 경로를 매칭하고, 매칭 실패 시에만 마지막 /를 제거하는 로직을 수행하도록 수정. image-20210205115522098

0x06 trim에 관하여

원리적으로 trim()은 문자열 앞뒤의 모든 공백 문자(whitespace)를 제거합니다. 공백은 그중 하나일 뿐입니다. 그러나 테스트 결과 공백 외의 다른 공백 문자(예: %08, %09, %0a)는 spring+tomcat에서 처리 시 400을 반환합니다.

따라서 첫 번째 방식에서는 공백 외에 유용한 payload는 아직 발견되지 않았습니다.

0x07 참고

https://github.com/apache/shiro/commit/0842c27fa72d0da5de0c5723a66d402fe20903df

https://www.anquanke.com/post/id/216096

https://www.cnblogs.com/syp172654682/p/9257282.html

도구 다운로드
/./ -> /
경로 점프/aaa/../bbb -> /bbb