
CVE-2014-0094 test program for struts1
CVE-2014-0094의 struts1 영향에 대해 정리한다. 별도 언급이 없는 한, 각 버전은 java 1.7.0_02, struts 1.3.10, apache-tomcat-6.0.39, FreeBSD 8.2에서 확인했다.
또한, 어떠한 경우라도 소스, 문서 등의 내용에 대해 보증하지 않는다. 또한, 어떤 현상이 발생하더라도 나는 관여하지 않는다. 특히 이 내용을 악용한 경우에도 나는 일절 관여하지 않는다.(그렇다고 해도 새로운 것은 없지만)
이번에 여러 웹을 참고하여 해결책의 구체적인 예시를 제시했다. 알려진 사실을 제외하고, 참고한 URL을 소스 등에 기재했다. 정보를 공개해 주신 것에 감사드린다.
가능한 전문 용어를 사용하지 않고, 오해의 소지가 있을 수 있지만 알기 쉬운 말로 기재했다.
struts1에서의 이번 취약점은, CVE-2014-0094, S2-020 등 호칭이 있는 것 같기도 하고 없는 것 같기도 하여 잘 모르겠지만, 일단 CVE-2014-0094라고 부르기로 한다.
새삼 설명할 필요도 없이, CVE-2014-0094는 매우 큰 문제를 안고 있다.
http://www.nta.go.jp/sonota/sonota/osirase/service.htm
「e-Tax 소프트웨어 (WEB版)」「확정신고서 등 작성 코너」「NISA (일본판 ISA) 코너」 서비스 중단 안내 (중요) 2014년 4월 25일 에 따르면, 국세청의 웹 서비스가 struts1을 사용하고 있으며, 발견된 당일에 서비스를 중단했다.
피해를 최소화하기 위해 조속한 중단을 실시한 것으로 보인다.
여기서 실증 실험을 한 결과, URL에 접근하는 것만으로 서비스 중단, 임의의 파일 유출을 확인했다.
URL에 접근하는 것만으로, 익명 메일 주소로 URL이 적힌 메일을 ML에 보내는 것만으로 범인 특정이 어렵고, 쉽게 서비스 중단을 할 수 있다.
이렇게 간단히 공격할 수 있는 문제인가 싶다.
이것이 가장 중요하다고 생각한다. 적어도 영향이 있을 것이라고 제3자 기관에서 발표가 있었다면, 우선 중단시키고 피해 확대를 막는 것이 본래의 방법. 만약 이후 조사에서 영향이 없다고 밝혀져도, 유출된 정보는 되돌릴 수 없다. 물론 정치적 판단이 필요한 사항이다. 기업의 경우 윤리의식, 평소의 문제 의식, 리스크 대응 등이 시험대에 오른다.
이 문제는 시스템이 보유한 설정값 일부를 변경 가능한 것에 기인한다. 어떤 설정값이 변경 가능한지 조사할 필요가 있다. 그 값에 따라 어떤 공격이 가능한지 판단한다.
이 설정값은 Servlet 컨테이너에 따라 다르다. tomcat6에서는 임의의 코드 실행은 아마 불가능하다고 생각되지만, tomcat8에서는 임의 실행이 가능하다. 그 외 jetty, WebSphere Application Server 등, 사용 환경에 따라 어떤 설정값이 있는지 확인할 필요가 있다.
tomcat6의 경우 23개의 설정 변경이 가능하다고 알려져 있으며, class.classLoader.resources.dirContext.docBase 를 변경한 경우, 정상적인 시스템 가동이 불가능해지고, 또한 JSP를 표시하는 대신 서버 상의 파일을 지정함으로써 임의의 파일 획득 (유출)이 가능해진다.
tomcat8의 경우 임의의 코드 실행이 가능하지만, 이는 tomcat6에 비해 설정할 수 있는 값이 증가했기 때문이다. 그 설정값이 사용 중인 Servlet 컨테이너에 존재하지 않으면 현재로서는 문제가 적다고 생각된다.
이번 설정값 변경은 URL에 그 문자열을 포함시키는 것 외에도, 일반 요청의 숨김 항목으로도 가능하며, 또한 쿠키에 그 값을 포함시켜도 가능하다고 알려져 있다.
액세스 로그만으로는 숨김 항목에 설정한 경우를 알 수 없다.
일요일 심야에 재시작을 하는 경우가 자주 있지만, 그보다 조금 전에 docBase의 변경 및 파일 획득을 하고, 이후 시스템에 재시작이 걸리므로, 시스템 관리자 입장에서는 이상을 알아차리기 어렵다. 그 시간대를 노려 status 404, 500 등이 다발했다면, 아마 어떤 파일이 유출되었을 가능성이 높을 수 있다.
struts1은 지원이 종료되었으며 (오픈소스의 지원이 무엇인가? 라는 이야기는 제쳐두고), 보안 패치가 나오지 않는다. 자력으로 해결할 필요가 있다.
이 사건의 발단은 BeanUtil의 문제이며, 여기에 부적절한 문자열이 올 경우 무시하는 구현을 할 필요가 있다. BeanUtil이란, 객체의 설정값을 변경하는 도구이다 (상당히 오해의 소지가 있는 표현이다).
구현 예시는
com.haselab.struts.filter
web.xml
이다.
간단히 설명하면, web.xml에 시스템 기동 시 BeanUtil의 동작을 변경하는 프로그램을 호출한다. SafeResolverListener.java가 호출되어, 향후 BeanUtil이 SafeResolver.java를 사용하게 된다. SafeResolver.java에서는 해석할 문자열이 (대소문자를 무시하고) 'classLoader'라면 ""를 반환한다. 즉, classLoader에 대해 임의의 값을 설정할 수 없게 한다. 이 주변의 동작에 대해서는 https://gist.github.com/nakamura-to/11347570 를 참고했다. (짧은 프로그램이므로 그대로 사용)
애플리케이션 측에서 classLoader라는 설정을 변경할 필요가 있는 경우, 이 방법에서는 이 설정을 할 수 없게 되므로 대응이 아니다. 하지만 일반적으로 우선 classLoader라는 이름을 붙이는 일은 없을 것이므로, 우선 문제없다. 불안하다면 애플리케이션 측 전체 소스에 대해 grep -r -i classLoader * 등을 수행하여 존재하지 않음을 확인하면 된다.
docBase의 변경에 대해 검증해 보았다. mvn으로 deploy 후, struts 하위를 브라우저에서 보아 주십시오. 버튼을 누를 때마다 docBase의 변경과 /etc/passwd 파일 표시를 수행한다.