0
0
Lập trình
Hưng Nguyễn Xuân 1
Hưng Nguyễn Xuân 1xuanhungptithcm

Tấn công Prototype Pollution: Phân tích Kỹ thuật và Hệ quả (Phần 4)

Đăng vào 3 tuần trước

• 4 phút đọc

IV. Phân tích và Khai thác Kỹ thuật Phát hiện Tấn công Server-side - Prototype Pollution (tiếp theo)

5. Sử dụng Các Phương thức Ghi đè để Kiểm Tra Lỗ Hổng

5.1. Ghi đè Status Code

Trong quá trình tương tác với trang web, người dùng thường gặp phải các tình trạng không thể truy cập vào một endpoint nhất định. Nguyên nhân có thể là do thiếu quyền truy cập hoặc các lý do kỹ thuật khác. Khi sử dụng BurpSuite, phản hồi từ một endpoint không khả dụng có thể trả về trạng thái lỗi như sau:

Copy
HTTP/1.1 200 OK
...
{
    "error": {
        "success": false,
        "status": 401,
        "message": "Bạn không có quyền truy cập vào tài nguyên này."
    }
}

Phản hồi như vậy có thể bị khai thác thông qua lỗ hổng Prototype Pollution, ví dụ như sử dụng hàm createError() trong module http-errors của Node.js. Theo tài liệu từ NPM:

Copy
function createError () {
    //...
    if (type === 'object' && arg instanceof Error) {
        err = arg
        status = err.status || err.statusCode || status
    } else if (type === 'number' && i === 0) {
    //...

Trong đoạn mã trên, giá trị status được xác định tùy thuộc vào err.status hoặc err.statusCode. Để khai thác thành công, kẻ tấn công có thể thay đổi thuộc tính status trong Object.prototype. Tuy nhiên, cần chú ý để đảm bảo giá trị ghi đè nằm trong khoảng từ 400 đến 599, bởi nếu không, giá trị sẽ được mặc định là 500.

5.2. Ghi đè Charset

Charset (Bảng mã) được sử dụng để xác định cách thức mã hóa ký tự. Khi tải một trang web, charset thường được xác định trong thẻ meta để trình duyệt biết cách hiển thị ký tự:

Copy
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Trang web ví dụ</title>
</head>
<body>
  <!-- Nội dung trang web -->
</body>
</html>

Đối với Express, middleware body-parser cung cấp tùy chọn defaultCharset cho phép xác định charset mặc định nếu không có charset nào được chỉ định trong header Content-Type của yêu cầu. Điều này được thể hiện thông qua đoạn mã:

Copy
function getCharset (req) {
  try {
    return (contentType.parse(req).parameters.charset || '').toLowerCase()
  } catch (e) {
    return undefined
  }
}

Bằng cách nào đó, nếu contentType.parse(req).parameters.charset bị thay đổi, nó có thể ảnh hưởng đến quá trình giải mã dữ liệu. Một ví dụ điển hình là sử dụng định dạng UTF-7 để gửi yêu cầu:

Copy
{
    "username":"viblo",
    "role":"+AGYAbwBv-"
}

Trong trường hợp ứng dụng bị lỗ hổng Prototype Pollution, kết quả có thể dẫn đến chuỗi foo được trả về qua việc giải mã.

6. Phát hiện Lỗ Hổng Tự Động bằng Công Cụ

Ngoài việc kiểm tra thủ công, người dùng cũng có thể sử dụng các công cụ tự động để phát hiện lỗ hổng Prototype Pollution, tiết kiệm thời gian và công sức đặc biệt trong các tình huống kiểm thử ứng dụng quy mô lớn. Một trong những công cụ hiệu quả là extension Server-Side Prototype Pollution Scanner từ BurpSuite.

Người dùng có thể kiểm tra từng yêu cầu hoặc nhóm yêu cầu qua BurpSuite. Khi kiểm tra một tính năng như /my-account/change-address, chỉ cần nhấp chuột phải vào yêu cầu > Chọn Extensions > Server-Side Prototype Pollution Scanner > Thực hiện quét. Chế độ quét có thể bao gồm nhiều kỹ thuật, thậm chí có tùy chọn kiểm tra tổng quát với Full scan.

7. Từ Lỗ Hổng Prototype Pollution đến Remote Code Execution (RCE)

Lỗ hổng Prototype Pollution có thể dẫn đến các hậu quả nghiêm trọng như Remote Code Execution (RCE). Nếu một ứng dụng cho phép dữ liệu không tin cậy để cập nhật đối tượng JavaScript, kẻ tấn công có thể chèn mã độc qua lỗ hổng này.

Một số chức năng có khả năng bị lợi dụng bao gồm child_process.fork(), child_process.spawn(), và child_process.execSync(). Đặc biệt phương thức child_process.fork() cho phép tạo một quá trình Node.js mới:

Copy
child_process.fork(modulePath[, args][, options])

Giá trị thuộc tính execArgv có thể được kẻ tấn công thay đổi, gây ra RCE:

Copy
"__proto__": {
    "execArgv":[
        "--eval=require('child_process').execSync('lệnh thực thi')"
    ]
}

Ví dụ mã lệnh sau cho thấy một ứng dụng Node.js tồn tại lỗ hổng Prototype Pollution qua hàm merge(), từ đó cho phép tấn công RCE thông qua việc khai thác:

Copy
const { execSync, fork } = require('child_process');

function isObject(obj) {
    console.log(typeof obj);
    return typeof obj === 'function' || typeof obj === 'object';
}

function merge(target, source) {
    for (let key in source) {
        if (isObject(target[key]) && isObject(source[key])) {
            merge(target[key], source[key]);
        } else {
            target[key] = source[key];
        }
    }
    return target;
}

function clone(target) {
    return merge({}, target);
}

clone(USERINPUT);

var proc = fork('a_file.js');

Chương trình này cho thấy việc xác định và lợi dụng lỗ hổng Prototype Pollution thông qua một tiến trình phụ.

Tài liệu tham khảo

©️ Tác giả: Lê Ngọc Hoa từ Viblo.
source: viblo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào