PHÂN TÍCH VÀ XÂY DỰNG POC KHAI THÁC CVE-2022-22980

03/08/2022

Cách thức khai thác lỗ hổng CVE-2022-22980 – Spring Data MongoDB Remote Code Execution (RCE)
[+] Introduction:
CVE-2022-22980 là một lỗ hổng bảo mật của thư viện Spring Data MongoDB với version 3.4.0, 3.3.0 to 3.3.4, cho phép kẻ tấn công thực thi bất cứ câu lệnh nào trên server chỉ bằng việc truyền vào 1 đoạn mã độc ở user input để trigger thư viện thực thi nếu ứng dụng Spring Boot + MongoDB sử dụng JSON Based query methods với @Query, @Aggregation annotation có chứa parameter expression SpEL – Spring Expression Language tươn tự như sau:
cách thức khai thác lỗ hổng CVE-202-22980 – Spring Data MongoDB Remote Code Execution (RCE)
[+] Introduction:
CVE-2022-22980 là một lỗ hổng bảo mật của thư viện Spring Data MongoDB với version 3.4.0, 3.3.0 to 3.3.4, cho phép kẻ tấn công thực thi bất cứ câu lệnh nào trên server chỉ bằng việc truyền vào 1 đoạn mã độc ở user input để trigger thư viện thực thi nếu ứng dụng Spring Boot + MongoDB sử dụng JSON Based query methods với @Query, @Aggregation annotation có chứa parameter expression SpEL – Spring Expression Language tương tự như sau:

anh-0.png
Vậy tại sao ở đây lại bị lỗi, thì ở đây tôi có build 1 ví dụ sử dụng Spring Expression để chứng minh có thể chạy được command:
- Đầu tiên, chương trình này sử dụng thư viện Spring Expression ver 5.2.1
- Sau đó, chương trình nhận input từ người dùng rồi sử dụng class Expression để parse input đấy từ người dùng
- Cuối thì dùng toString() để in ép dạng chuỗi và in output ra màn hình


anh-1-anh-bia-(1).png
Ảnh 1: Spring Expression có thể chạy command (có thể gọi calc.exe)
- Tại đây, muốn truyền câu lệnh
- T(java.lang.Runtime).getRuntime().exec("calc.exe")
- Nói sơ 1 chút về câu lệnh, về cơ bản thì class <T> chính là 1 class đa hình, nếu ta truyền vào class này 1 cái gì đó, thì class này sẽ trở thành cái đó. Cụ thể ở đây ta truyền vào class java.lang.Runtime. Như vậy <T> đã trở thành java.lang.Runtime. Từ đó gọi tới hàm getRuntime()exec()
- Như vậy, về cơ bản thì Spring Expression Language có thể chạy được command
[+] Phân tích:
Sau nỗ lực tìm kiếm thông tin về CVE này thì tôi đọc được thông tin trên trang chủ của Spring đề cập về lỗ hổng này:


anh-2.png
Ảnh 2: Nguồn: https://spring.io/security/cve-2022-22980
Như vậy, chúng ta thật sự xác định được các annotation là @Query @Aggregation sẽ chịu trách nhiệm cho lỗ hổng này.
Vậy trước khi bắt đầu phân tích, ta cần phải tìm hiểu cách hoạt động của Spring Boot Framework khi xử lý SpEL Query thông qua 2 annotation trên:
- Khai báo CustomerRepository:


anh-3.png
Ảnh 3: Khai báo CustomerRepository
- Tiến hành gọi câu truy vấn:

anh-4.png
Ảnh 4: Gọi câu truy vấn ?query= và đã hit được debug
- Step into:

anh-5-(1).png
Ảnh 5: Step into - invoke()
 
Sau khi debug và step into vài lần, có thể thấy Spring Boot Framework gọi qua rất nhiều class, tuy nhiên, ta có thể tóm gọn và hiểu đơn giản workflow của chúng như sau:
- Khi gọi đến phương thức findByFirstname() trong CustomerRepository, thì tất cả mọi lời gọi phương thức đều phải đi qua một handler duy nhất – đó chính là phương thức invoke()
Bên trong phương thức invoke() này, ứng dụng sẽ tiến hành thực thi các bước tiền xử lý trước khi được đưa vào database để truy vấn dữ liệu. Ví dụ như hàm createQuery() trong class StringBasedMongoQuery().
Tuy nhiên, trước khi gọi được hàm này thì Spring Boot Framework cần binding parameter vào câu query trước thông qua hàm getBindingContext():


anh-6-(1).png
Ảnh 6: Bind Param bằng hàm getBindingContext()
 
Có thể biết được thông qua Step into để biết rằng ứng dụng sẽ gọi từ getBindingContext() -> captureExpressionDependencies() ->  ParameterBindingJsonReader() dùng để parse JSON ra từ request -> bindableValueFor() để gán giá trị vào tham số sau khi parse. Tại đây có thể biết được sau khi gán mọi thứ xong, biến expression không hề phát hiện được input ta truyền vào là 1 đoạn mã chứ không phải 1 giá trị thông thường vì đoạn mã T(java.lang.Runtime).getRuntime().exec("calc.exe") vẫn được giữ nguyên:

anh-7-(1).png
Ảnh 7: Đoạn mã truyền vào vẫn được giữ nguyên

Lỗ hổng thực sự xảy ra khi sau đó đoạn mã độc của chúng ta được truyền vào hàm evaluateExpression() và thực thi command được truyền vào là mở calc.exe lên (chúng ta đã xác định ngay từ đầu là Spring Expression có thể thực thi command)

anh-8-(1).png
Ảnh 8: Đoạn mã được truyền thẳng vào hàm evaluateExpression()

+ PoC:
anh-9-(1).png
[+] Debug CallStack:

anh-10-(1).png
 
anh-11-(1).png
anh-12-(1).png
Những công cụ được sử dụng:
- IDE: IntelliJ Community Edition
- IDE: Visual Studio Code for testing SpEL Expression
- Spring Data MongoDB 3.3.4
- MongoDB version 4.2.21
- Brave
- Docker
REFERENCES:
- Spring Data MongoDB SpEL Expression Injection Vulnerability (CVE-2022-22980) xem thêm qua đường dẫn
- CVE-2022-22980: Spring Data MongoDB SpEL Expression injection vulnerability through annotated repository query methods xem thêm qua đường dẫn 
- [CVE-2022-22980] Spring Data MongoDB SpEL Expression Injection xem thêm qua đường dẫn
- PoC CVE-2022-22980 xem thêm qua đường dẫn
- Code được fix như thế nào sau khi ra bản patch xem thêm qua đường dẫn