Apache Struts2 취약점(CVE-2017-5638)은 원격 코드 실행 취약점입니다. HTTP Request 헤더의 Content-Type 값을 변조하여 원격 코드실행을 가능하게 합니다. 취약점에 대한 설명을 찾아보면 Content-Type 헤더 필드에 OGNL 표현식을 삽입할 경우 Struts2의 Jakarta 플러그인 오류 처리 과정에서 임의의 코드가 실행될 수 있음을 알 수 있습니다.
본 문서에서는 Struts 2.3.31 버전을 대상으로 취약점을 분석해 보았습니다.
공격 코드 동작 확인
공격 코드를 사용해서 “dir” 명령을 전달하면 다음과 같이 취약한 서버의 파일 목록을 확인할 수 있습니다.
[취약한 서버의 파일 목록을 확인]
취약한 서버로 전달되는 패킷입니다. Content-Type 항목에 OGNL 표현식으로 작성된 공격코드가 포함되어 있습니다.
[취약한 서버로 전달되는 패킷]
공격 코드 확인
[공격 코드 확인]
서버에 전달되는 매개 변수 중에 #nike='multipart / form-data'는 공격코드 실행의 토대를 마련합니다.
#cmd 매개 변수에는 도스 명령어가 지정됩니다. 그리고 취약한 서버의 운영체제를 확인한 뒤에 유형별 공격 명령을 완성합니다.
마지막으로 공격 명령을 실행합니다.
서버 취약 코드 확인
서버는 request 요청이 넘어오면 FilterDispatcher Class의 doFilter 메서드를 사용해서 필터 작업을 수행합니다. 그 과정에서 prepareDispatcherAndWrapRequest를 호출하게 됩니다.
[FilterDispatcher.doFilter]
prepareDispatcherAndWrapRequest는 Request Wrapping 메서드입니다. 해당 메서드는 내부적으로 dispatcher.wrapRequst를 호출합니다.
[FilterDispatcher.prepareDispatcherAndWrapRequest]
dispatcher.wrapRequst는 다양한 방식으로 전송된 요청에 대한 Wrapping을 수행하는 메서드입니다. Struts2 원격코드실행 취약점(CVE-2017-5638)의 경우 content_type을 'multipart/form-data'로 설정하고 전송하기 때문에 MultiPartRequestWrapper를 호출하게 됩니다.
[dispatcher.wrapRequst]
MultiPartRequestWrapper.java는 multipart request에 대한 구문을 분석하고 Wrapping 합니다. 이로 인해 구문 분석 메서드인 JakartaMultiPartRequest.parse가 실행됩니다.
[MultiPartRequestWrapper.java]
구문 처리 과정에서 Content-Type 헤더의 형식을 식별하지 못하므로 예외가 발생하게 되고 JakartaMultiPartRequest.buildErrorMessage가 실행됩니다.
[JakartaMultiPartRequest.parse]
JakartaMultiPartRequest.buildErrorMessage 내에 존재하는 LocalizedTextUtil.findText는 OGNL 표현식을 실행합니다.
[JakartaMultiPartRequest.buildErrorMessage]
LocalizedTextUtil.findText의 정의를 살펴보겠습니다. $ {...} 내의 모든 것은 OGNL 표현식으로 간주하고 처리한다고 되어 있습니다. 그 결과 공격코드가 실행되는 것입니다.
\
[LocalizedTextUtil.findText의 정의]
Struts 2 Core 2.3.4 API에 대한 정의를 간략하게 소개해 놓았습니다.
※ FilterDispatcher Class
Master filter for Struts that handles four distinct responsibilities:
- Executing actions
- Cleaning up the ActionContext (see note)
- Serving static content
- Kicking off XWork's interceptor chain for the request lifecycle
IMPORTANT: this filter must be mapped to all requests. Unless you know exactly what you are doing, always map to this URL pattern: /*
※ Method
∙ doFilter: Process an action or handle a request a static resource. The filter tries to match the request to an action mapping.
∙ prepareDispatcherAndWrapRequest: Wrap and return the given request, if needed, so as to to transparently handle multipart data as a wrapped class around the given request.
--------------------------------------------------------------------------------------------------------------
※ dispatcher Class
A utility class the actual dispatcher delegates most of its tasks to. Each instance of the primary dispatcher holds an instance of this dispatcher to be shared for all requests.
※ Method
∙ wrapRequest: Wrap and return the given request or return the original request object. This method transparently handles multipart data as a wrapped class around the given request.
--------------------------------------------------------------------------------------------------------------
※ MultiPartRequestWrapper Class
Parse a multipart request and provide a wrapper around the request.
--------------------------------------------------------------------------------------------------------------
※ JakartaMultiPartRequest Class
Multipart form data request adapter for Jakarta Commons Fileupload package.
※ Method
∙ parse: Creates a new request wrapper to handle multi-part data using methods adapted from Jason Pell's multipart classes (see class description).
해결 방안
취약점이 패치된 버전으로 업데이트 수행
- Apache Struts 2.3.32
- Apache Struts 2.5.10.1
Content-Type에 엄격한 필터링 적용 및 ognl 표현식 사용 금지
commons-fileupload-x.x.x.jar 파일 삭제 (임시조치_삭제 시 업로드 기능 사용 불가)
|
댓글
댓글 쓰기