콘텐츠로 이동

Jenkins CLI 취약점 2종

Jenkins CLI 취약점 2종 thumbnail
CVE-2024-23897은 args4j의 expandAtFiles가 CLI 인자를 파일 내용으로 펼치는 점에서 시작한다. CVE-2024-23898은 Jenkins CLI WebSocket endpoint의 Origin 검증 부재다. 둘 다 Jenkins CLI 표면에 걸려 있지만 트리거와 관측 지점은 다르다.

핵심 정리

CVE-2024-23897은 args4j의 expandAtFiles가 CLI 인자를 파일 내용으로 펼치는 점에서 시작한다. CVE-2024-23898은 Jenkins CLI WebSocket endpoint의 Origin 검증 부재다. 둘 다 Jenkins CLI 표면에 걸려 있지만 트리거와 관측 지점은 다르다.

수정 버전은 weekly 2.442, LTS 2.426.3, LTS 2.440.1이다. 공개 권고문은 두 취약점의 영향 범위와 완화책을 함께 적고, CVE-2024-23897은 CISA KEV Catalog에도 올라간다. NVD는 2024-08-19 추가와 2024-09-09 조치 기한을 표시한다.

Note

HTTP CLI와 WebSocket CLI를 분리해서 본다. 23897은 파일 확장 경로, 23898은 브라우저 기원 검증 경로다. 같은 "CLI"라도 트리거가 다르다.

항목 CVE-2024-23897 CVE-2024-23898 근거
취약점 유형 CLI @file 확장 악용으로 파일 내용 노출. CLI WebSocket endpoint의 Origin 미검증으로 CSWSH. Jenkins 보안 권고문, SonarSource 분석
영향 버전 Jenkins weekly 2.441 이하, LTS 2.426.2 이하. Jenkins 2.217~2.441, LTS 2.222.1~2.426.2. Jenkins 보안 권고문
수정 버전 weekly 2.442, LTS 2.426.3, 2.440.1. weekly 2.442, LTS 2.426.3, 2.440.1. Jenkins 보안 권고문
코드 포인트 expandAtFiles@path를 파일 내용으로 펼친다. connect-to-noderesolveForCLI() 전에 이 경로를 밟는다. doWs(StaplerRequest req)Origin을 root URL과 비교한다. 불일치하면 403으로 끊는다. SonarSource 분석, Jenkins 보안 권고문

취약점 구조

CVE-2024-23897

Jenkins CLI의 HTTP 흐름은 /cli?remoting=false로 들어오는 두 번의 POST 요청이다. Session UUID와 Side: upload|download 헤더로 요청이 묶인다. CLI 인자 처리는 args4j의 expandAtFiles를 타고, @ 뒤 경로가 파일 내용으로 펼쳐진다. connect-to-node처럼 multiValued 인자를 받는 명령은 여러 줄을 인자로 재사용할 수 있고, resolveForCLI()보다 앞단에서 내용이 노출된다.

권고문은 후속 영향으로 binary secrets 노출, Remember me cookie 위조, crumb 위조, Resource Root URL 경유 영향, secrets 복호화, item 삭제 가능성을 적는다. 다만 공개 자료만으로 공격 체인 전체를 단정할 수는 없다.

CVE-2024-23898

이 취약점은 Jenkins CLI의 WebSocket 경로를 건다. 문제는 WebSocket endpoint에서 Origin 검증이 없었던 점이다. Jenkins는 수정본에서 doWs(StaplerRequest req)에 Origin 비교를 넣고, 요청의 Origin이 예상 root URL과 다르면 403을 반환한다. 브라우저가 중간에 끼는 구조라서, 쿠키가 실린 상태에서 잘못된 기원 요청이 통과할 수 있는지가 핵심이다.

탐지 포인트

네트워크

  • /cli?remoting=false로 이어지는 두 단계 POST 흐름이 있는지 본다. Session UUID와 Side: upload|download 조합이 보이면 HTTP CLI 경로다.
  • WebSocket 업그레이드가 살아 있는지 본다. 101 Switching Protocols 뒤에 CLI 세션이 열리면 WebSocket 경로가 노출된 상태다.
  • 403 Forbidden이 기대 지점에서 나는지 본다. Origin 검증이 제대로 걸리면 WebSocket 경로는 여기서 끊긴다.
grep -E '/cli\?remoting=false|Session:|Side: (upload|download)|101 Switching Protocols|403 Forbidden' access.log

엔드포인트

  • /cli는 HTTP POST와 WebSocket 두 경로를 모두 쓴다.
  • HTTP 경로는 SessionSide 헤더로 묶인다.
  • WebSocket 경로는 Origin 검증이 핵심이다. Origin이 root URL과 맞지 않으면 차단되어야 한다.

서버

  • hudson.cli.CLICommand.allowAtSyntax=true는 23897의 기본 차단을 되돌린다.
  • hudson.cli.CLIAction.ALLOW_WEBSOCKET=true는 23898의 방어를 되돌리는 예외 스위치다.
  • legacy, Allow anonymous read access, signup 조합은 익명 read 범위를 넓혀 23897의 노출 폭을 키운다.
  • UTF-8이 아닌 인코딩 환경에서는 노출 양상이 달라질 수 있다. 공개 권고문은 Windows-1252 같은 환경을 언급한다.

대응 포인트

  • Jenkins core를 weekly 2.442, LTS 2.426.3, 또는 2.440.1로 올린다.
  • 급하면 CLI를 끈다. CLI 경로 자체를 비활성화하는 우회책이다.
  • reverse proxy 뒤에 있으면 WebSocket upgrade를 막는다.
  • allowAtSyntax=trueALLOW_WEBSOCKET=true는 호환성 예외가 필요할 때만 둔다.
  • 침해가 의심되면 Jenkins가 접근할 수 있는 secrets 범위를 다시 본다. 권고문이 직접 적는 후속 영향은 binary secrets, Remember me cookie, crumb, Resource Root URL, item deletion, secrets decrypt다.

참고 자료