Introduction
Jenkins là một phần mềm tự động hóa, mã nguồn mở và viết bằng Java giúp tự động hóa các quy trình trong phát triển phần mềm, hiện nay được gọi theo thuật ngữ Tích hợp liên tục, và còn được dùng đến trong việc Phân phối liên tục. Jenkins là một phần mềm dạng server, chạy trên nền servlet với sự hỗ trợ của Apache Tomcat. Nó hỗ trợ hầu hết các phần mềm quản lý mã nguồn phổ biến hiện nay như Git, Subversion, Mercurial, ClearCase... Jenkins cũng hỗ trợ cả các mã lệnh của Shell và Windows Batch, đồng thời còn chạy được các mã lệnh của Apache Ant, Maven, Gradle...CVE-2024-23897
Đầu năm 2024 nay, Jenkins đã tung ra Security Advisory cho mã lỗi CVE-2024-23897 với mô tả có thể đọc file bất kì qua CLI và có nguy cơ dẫn đến RCE. Lỗ hổng này tồn tại Jenkins ở version <= 2.441 và <= LTS 2.426.2 Cho đến thời điểm hiện tại, PoC hay các bài phân tích của CVE này đã đầy rẫy trên các nền tảng Twitter hay Github, nhưng hầu hết chỉ đề cập đến việc đọc file, một nửa còn lại là tấn công sâu hơn từ việc đọc file thì chưa được đề cập nhiều nên bài hôm nay mình sẽ giới thiệu một số hướng khai thác sâu hơn từ việc đọc file trên.Quick Review
Về root cause của bug thì không thiếu các bài phân tích đã nói, ở đây mình sẽ nhắc lại một tí. Nguyên nhân chính là vì Jenkins CLI có sử dụng hàmparseArgument()
của class bên thứ ba org.kohsuke.args4j.CmdLineParser

expandAtFiles()


expandAtFiles()
sẽ nhận dữ liệu từ người dùng, nếu có @
thì nó sẽ thực hiện đọc content của file theo path file đi theo sau @
từ đó expand nội dung file theo ra biến phía sau -> read được content file.

connect-node

Attack time
Mình vừa review sơ về root cause của bug này, giờ mình sẽ tiến hành phân tích 2 trong số các hướng tấn công có thể đạt được thông qua việc đọc được file.Setup
Có thể build Jenkins bằng filejenkins.war
với version bất kì được tải từ trang chủ Jenkins tại https://get.jenkins.io/war/, trong bài này mình dùng ver 2.441. Thực hiện deploy và bật port debug bằng câu lệnh
java -agentlib:jdwp=transport=dt_socket,address=*:5005,server=y,suspend=n -jar jenkins.warĐể thuận tiện cho việc phân tích, mình sẽ build trên môi trường Windows, về lí do thì mình sẽ giải thích ở phần dưới.
Extracting credentials
Jenkins có một plugins là Credentials, dùng để lưu trữ các thông tin đăng nhập theo Domain, các site 3rd party, các storage lưu trữ,... Các thông tin đăng nhập này sẽ được dùng vào các dự án Pipeline khi tương tác với các bên thứ ba. Nếu những thông tin này bị trích xuất ra, những account hay credential dự án/app bên thứ ba sẽ bị lộ lọt, mở đường tấn công vào các hệ thống này.
<jenkins>/credentials.xml
, lợi dụng bug ta có thể đọc được file



hudson.util.Secret
và dùng master key. Binary của class hudson.util.Secret
được lưu tại <jenkins>/secrets/hudson.util.Secret
và key tại <jenkins>/secrets/master.key
, nên ta hoàn toàn có thể đọc và sử dụng để decrypt. Thử dùng file từ chính server để test với tool jenkins-credentials-decryptor

master.key
thì không bàn tới, nhưng việc đọc được file hudson.util.Secret
dưới dạng đúng và làm sao cho sử dụng được lại là một vấn đề










3F
thành một trong các byte 81, 8D, 8F, 90, hoặc 9D. Đây là những byte mà Encoding Windows-1252 không đọc được.
Nguyên nhân các byte này Windows không thể đọc được ta có thể tham khảo Codepage layout của Encoding Windows-1252 tại đây, và tại sao lại thay thế 3F
tại nhiều nguồn khác.


9D
, file hudson đã có thể decrypt thành công.


0D
để ngắt hàng, các byte không được in vẫn có vị trí dùng 90
, 8D
,... Tuy nhiên file của ta vẫn hoạt động mượt :Đ.

9D


8F

Forging Remember-me Cookie
Nếu phía trên chỉ để trích xuất thông tin của bên thứ ba, thì hướng khai thác này sẽ ảnh hưởng trực tiếp lên server Jenkins cụ thể hơn là Admin account. Với Admin account, ta có thể có được tất cả info về project, pipeline,... mọi thứ trong Jenkins và còn có thể chạy lệnh hệ thống thoải mái, cộng thêm chức năng remember me khi đăng nhập được bật default, nên đây là một hướng tấn công có phần vjp pr0 hơn. Để forge được thì ta cần phải biết Jenkins xử lí phần remember cookie này ra sao, sau khi search source theo keywordrememberme
thì tại class AbstractRememberMeServices
sẽ xử lí từ đầu cho phần remember cookie, đặt breakpoint tại rememberMeRequested()

onLoginSuccess()

onLoginSuccess()
, sẽ nhảy vào makeTokenSignature()
để tạo signatureValue, đây có vẻ như là nơi ta cần

makeTokenSignature()
sẽ tạo một String token là chuỗi kết hợp giữa username, userSeed, một timestamp hết hạn token và secret key

Mac.mac(token)
, hàm này đầu tiên sẽ thực hiện getBytes()
token trên sau đó đưa vào hàm mac()


mac()
này đầu tiên thực hiện kiểm tra HMACConfidentialKey có tồn tại hay chưa, chưa thì sẽ tạo mới, không thì sẽ đi vào doFinal()
, ở đây với lần đầu ta dùng chức năng remember me thì nó sẽ vào hàm createMac()

getKey()

load()
Tại load()
, master key và content từ file <jenkins>/secrets/org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices.mac
được đưa vào hàm verifyMagic()



var7
và quay về hàm cha getKey()
, key var7
này sẽ là SecretKeySpec
để tạo mac.

doFinal()
của hàm mac()

Util.toHexString()

doFinal()
cho đi qua một loop xử lí để tạo một String buf
, đây chính là giá trị signatureValue
của hàm onLoginSuccess()
.


doFinal()
-> signatureValue
- master key
Ta còn lấn cấn 2 chỗ file mac và userSeed, với userSeed thì ta có thể get từ việc đọc file tương tự với 2 cái key kia, cụ thể là Jenkins có lưu trữ các thông tin về user tại <jenkins>/users/users.xml

config.xml



signatureValue
, đầu tiên là chuỗi token gồm username, timestamp, userseed và secret key





Remediation
Cập nhật lên phiên bản Jenkins mới nhất hoặc vô hiệu Jenkins CLI để đảm bảo an toàn bảo mật.Tham khảo
- https://www.sonarsource.com/blog/excessive-expansion-uncovering-critical-security-vulnerabilities-in-jenkins - https://www.jenkins.io/security/advisory/2024-01-24/#binary-files-note - https://www.errno.fr/bruteforcing_CVE-2024-23897.html - https://devops.stackexchange.com/questions/2191/how-to-decrypt-jenkins-passwords-from-credentials-xml - https://en.wikipedia.org/wiki/Windows-1252 - https://stackoverflow.com/questions/38896686/urlencoding-form-data-with-windows-1252-charset-in-node-js - https://github.com/hoto/jenkins-credentials-decryptor 856 lượt xem