0
0
Lập trình
Flame Kris
Flame Krisbacodekiller

Biện pháp ngăn chặn tấn công lỗ hổng Prototype Pollution (Phần 5)

Đăng vào 1 tháng trước

• 3 phút đọc

V. Biện pháp ngăn chặn lỗ hổng Prototype Pollution

1. Kiểm tra và loại bỏ giá trị property key

Hầu hết các kỹ thuật khai thác lỗ hổng Prototype Pollution sử dụng property key __proto__. Một trong những biện pháp đơn giản nhất để ngăn chặn tấn công này là phát hiện và loại bỏ chuỗi từ khóa này trong ứng dụng. Đối với các ứng dụng sử dụng Node.js, lập trình viên có thể sử dụng các flags command-line như --disable-proto=delete hoặc --disable-proto=throw để xóa hoặc ném lỗi khi cố gắng sử dụng __proto__.

Tuy nhiên, phương pháp này tương tự như blacklist và không hoàn toàn bảo vệ khỏi các kỹ thuật tấn công khác có thể sử dụng các "con đường" khác như constructor để vượt qua các biện pháp bảo vệ này.

2. Giới hạn property keys thông qua whitelist

Để tăng tính bảo mật, chúng ta nên sử dụng whitelist để chỉ định các giá trị property key được phép. Dưới đây là ví dụ về hàm sanitizeObject():

javascript Copy
const whitelist = ['allowedProperty1', 'allowedProperty2']; // Danh sách các property keys cho phép

function sanitizeObject(obj) {
  const sanitizedObj = {};

  for (const key in obj) {
    if (obj.hasOwnProperty(key) && whitelist.includes(key)) {
      sanitizedObj[key] = obj[key];
    }
  }

  return sanitizedObj;
}

Trước khi sử dụng dữ liệu người dùng, các đối tượng sẽ được lọc thông qua hàm này.

3. Đóng băng nguyên mẫu (Prototype Freezing)

Một phương pháp khác là không cho phép thay đổi các giá trị nguyên mẫu bằng cách sử dụng Object.freeze(). Khi gọi phương thức này, đối tượng không thể bị thay đổi:

javascript Copy
const obj = { prop: 42 };

Object.freeze(obj);

obj.prop = 33; // Không thể thực hiện điều này trong chế độ nghiêm ngặt
console.log(obj.prop); // Kết quả dự kiến: 42

Tuy nhiên, nhược điểm là các đối tượng trở nên "cứng nhắc". Thay vào đó, có thể sử dụng Object.seal() để chỉ cho phép thay đổi giá trị thuộc tính hiện tại mà không thể thêm mới hay xóa thuộc tính:

javascript Copy
const object1 = { property1: 42 };
Object.seal(object1);
object1.property1 = 33;
console.log(object1.property1); // Kết quả: 33

4. Sử dụng đối tượng Set / Map

Một cách ngăn chặn khác là sử dụng các đối tượng Set hoặc Map để thay thế cho đối tượng thông thường. Cả Set và Map không kế thừa giá trị thuộc tính từ Object.prototype:

javascript Copy
const myMap = new Map();
myMap.set("key", "value");
console.log(myMap.get("key")); // Kết quả: "value"
console.log(myMap.hasOwnProperty("toString")); // Kết quả: false
javascript Copy
const mySet = new Set();
mySet.add("value1");
console.log(mySet.has("value1")); // Kết quả: true
console.log(mySet.hasOwnProperty("toString")); // Kết quả: false

5. Ngăn chặn kế thừa thuộc tính bằng Null prototype

Khi cần sử dụng các đối tượng thông thường mà không muốn kế thừa thuộc tính từ Object.prototype, chúng ta có thể tạo một đối tượng với Null prototype:

javascript Copy
let myObject = Object.create(null);
Object.getPrototypeOf(myObject); // null

Khi đó, đối tượng này sẽ không kế thừa bất kỳ thuộc tính nào từ nguyên mẫu.

VI. Tấn công Prototype Pollution trong CTF

Tấn công Prototype Pollution cũng là một chủ đề quen thuộc trong các cuộc thi CTF (Capture the Flag). Chúng tôi sẽ giới thiệu một thử thách từ nền tảng Hack the box - Gunship. Dù thử thách này đã được đưa vào mục RETIRED, bạn vẫn có thể tải mã nguồn đầy đủ và dựng môi trường tại nhà.

1. Dựng môi trường challenge

Challenge có thể dễ dàng dựng tại local bằng Docker với file build-docker.sh đã được cung cấp.

2. Tổng quan chức năng

Thử thách yêu cầu gửi tên của favourite artist đến server qua phương thức POST tại endpoint /api/submit.

3. Review source code

Trong mã nguồn, tại route /api/submit, nếu tên artist chứa từ khóa như Haigh, Westaway, hoặc Gingell, server sẽ trả về thông báo hợp lệ.

4. Xây dựng payload

Chúng ta có thể ghi đè thuộc tính name trong Object.prototype để thực hiện tấn công:

javascript Copy
{
    "artist": {},
    "__proto__": {
        "name": "Gingell"
    }
}

Payload khai thác sẽ là:

javascript Copy
{"artist.name":"Haigh","__proto__.block": { "type": "Text", "line": "process.mainModule.require('child_process').execSync('$(id)')" }}

Điều này cho phép chúng ta vượt qua xác thực và thực hiện mã tùy ý để lấy flag. Thử thách này cho thấy tầm quan trọng của việc sử dụng các phiên bản mới nhất của các công nghệ để giảm nguy cơ lỗ hổng.

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