이 컴포넌트의 취약점은 오래전에 드러났는데, 최근 직장에서 다시 접하게 되어서 최근 Java deserialization 관련 내용을 보다가 꺼내서 분석하게 되었습니다. 또 그 과정에서 이상한 질문을 접하기도 했습니다.
인터넷에 있는 대부분의 분석 기사는 ysoserial에서 생성된 CommonsCollections2 페이로드를 사용하기 위해 commons-collections4-4.0의 종속성을 수동으로 추가합니다. 그러나 제가 직면한 상황은 CommonsBeanutils1을 사용하면 바로 성공할 수 있다는 것입니다. CommonsCollections2 온라인 분석을 반복하지 마십시오.
디버깅 환경:
JDK 1.8.0_72
Tomcat 8.0.30
먼저 shiro의 소스 코드를 복제하고 문제가 있는 분기로 잘라냅니다.
git clone https://github.com/apache/shiro.git shiro-rootcd shiro-root git checkout 1.2.0
Shiro와 함께 제공되는 샘플을 실행하려면 샘플/web/pom.xml 파일을 일부 수정해야 합니다. jstl 버전을 1.2로 변경하고 servlet-api의 범위 필드를 삭제해야 합니다. . WEB-INF/lib 디렉터리에 jstl-1.2.jar을 넣습니다. 그런 다음 실행하고 디버깅할 수 있어야 합니다.
org.apache.shiro.mgt.DefaultSecurityManager의solvePrincipals 메소드에 중단점을 설정하고 RememberMe 쿠키로 요청을 보내면 중단될 수 있습니다.
계속해서 getRememberedIdentity 메소드를 따릅니다:
계속해서 getRememberedSerializedIdentity 메소드를 따릅니다:
이 메소드에서는 우리가 전달한 쿠키를 읽고 base64로 디코딩합니다.
Connect 다음으로 shiro가 호출합니다.
함수 이름을 통해 추측할 수도 있습니다. 즉, 복호화와 역직렬화를 먼저 살펴보겠습니다. 단순 디버깅 결과, AES 복호화였으며 사전 설정된 키 Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");가 있는 것으로 확인되었습니다. Shiro와 함께 제공된 샘플에서는 이를 설정하는 다른 방법을 전달하지 않았습니다. 비밀 키이므로 여기서는 기본값이 사용됩니다.
AES 암호 해독에서 발견되는 IV도 우리가 전달한 쿠키의 처음 몇 바이트에서 얻어지므로 모든 콘텐츠가 포함된 쿠키 값을 쉽게 구성할 수 있으며, 해독된 일반 텍스트는 콘텐츠가 직렬화되고, 역직렬화를 위해 deserialize가 호출됩니다.
마지막으로 org.apache.shiro.io.DefaultSerializer#deserialize 메소드가 역직렬화를 위해 호출됩니다.
전체 프로세스는 매우 간단합니다: 쿠키 읽기 -> decryption -> 역직렬화
그래서 우리의 페이로드는 구성하기가 매우 간단합니다. 전체 PoC를 GitHub에 올려 놓겠습니다.
디버깅 과정에서 몇 가지 문제가 발생하여 계산기가 성공적으로 팝업되지 않았습니다.
이 문제를 오랫동안 디버깅하면서 페이로드 문제이거나 시간이 지남에 따라 Shiro의 코드가 변경된 것이라고 생각했습니다. 왜냐하면 그 당시 제가 접한 사례는 페이로드가 영혼에 도입되었다는 것이었기 때문입니다. 매우 혼란. 나중에 우리가 github에서 복제한 샘플에서 commons-beanutils의 종속 버전은 1.8.3이고 ysoserial에서 생성된 페이로드 버전은 1.9.2이므로 성공적으로 실행할 수 없다는 것을 발견했습니다. 기본 샘플. 그래서 버전번호를 1.9.2로 바꿨더니 히트를 쳤습니다.
그래서 우리가 만난 경우에는 실제 종속 환경 버전도 이와 같을 수 있으므로 직접 성공할 수 있습니다.
이 프로젝트가 복제되면 commons-collections 패키지가 있음을 확인할 수 있습니다.
ysoserial에서 제공하는 CommonsCollections1을 사용하려고 하면 예외가 발생하며 성공할 수 없습니다.
디버깅할 때 여기에 던져진 것을 발견했습니다. 예외, 바이트 배열을 역직렬화할 수 없는 이유는 매우 혼란스럽습니다
Java에서 Class.forName()과 ClassLoader.loadClass()의 차이점을 확인한 결과 forName()은 항상 호출자의 ClassLoader()를 사용하는 반면, loadClass()는 다른 ClassLoader를 지정할 수 있다는 것을 발견했습니다. 그렇다면 shiro의 ClasssLoader는 어디에서 왔습니까? 이는 WebappClassLoader인 Thread.currentThread().getContextClassLoader();를 통해 획득됩니다. 그런데 바이트 배열을 로드할 수 없다는 메시지가 표시되는 이유는 무엇입니까? 한동안 검색한 후 오렌지 블로그에서 아래 토론을 보고 모든 사실을 알게 되었습니다.
Shiro resovleClass는 대신 ClassLoader.loadClass()를 사용합니다. Class.forName(), ClassLoader.loadClass는 배열 유형 클래스 로드를 지원하지 않습니다.
위 내용은 Apache Shiro 1.2.4 역직렬화 취약점 예시 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!