مصطفی جعفرزاده
مصطفی جعفرزاده
خواندن ۴ دقیقه·۳ ماه پیش

استفاده از Use-After-Free و Prototype Pollution در جاوا اسکریپت: یک مثال ساده از حمله

این کد یک حمله ساده را نشان میدهد که ترکیبی از استفاده پس از آزادسازی حافظه (Use-After-Free) و آلودگی پروتوتایپ (Prototype Pollution) در محیط Node.js است. با استفاده از WeakMap و TypedArray، میتوانیم به حافظه آزاد شده دسترسی پیدا کرده و سپس پروتوتایپ را آلوده کنیم و باعث تغییرات ناخواسته در تمامی اشیاء جدید سیستم شویم.


استفاده پس از آزادسازی حافظه:

در مرحله اول، یک TypedArray ایجاد و در WeakMap ذخیره میشود. پس از حذف مرجع محلی به این آرایه، حافظه برای جمع آوری زباله (Garbage Collection) آماده میشود. این به ما امکان میدهد که پس از آزادسازی حافظه دوباره به داده ها دسترسی پیدا کنیم و شرایط Use-After-Free را فعال کنیم.


آلودگی پروتو تایپ:

پس از دسترسی مجدد به حافظه آزاد شده، از این وضعیت برای اجرای حمله آلودگی پروتوتایپ استفاده میکنیم. با تزریق یک ویژگی جدید به Object.prototype جهانی، تمامی اشیاء سیستم میتوانند به این ویژگی جدید دسترسی پیدا کنند که یک آسیب پذیری امنیتی جدی ایجاد میکند.


server:

const express = require(‘express’);

const bodyParser = require(‘body-parser’);

const app = express();

let weakMap = new WeakMap(); // A WeakMap to hold weak objects

let objReference = null;

let isProcessing = false; // A variable to manage the Race Condition

app.use(bodyParser.json());

app.post(‘/trigger_gc’, (req, res) => {

// Step 1: Create a TypedArray and store it in WeakMap

let typedArray = new Uint8Array(10); // A typed array with binary data

for (let i = 0; i < typedArray.length; i++) {

typedArray[i] = i * 10; // Initialize the array with values

}

weakMap.set(typedArray, ‘weak_value’); // Store the array in WeakMap

objReference = typedArray; // Keep a reference to the array

// Step 2: Release the local reference

typedArray = null; // Remove the local reference

// Check if the prototype has already been polluted

if (Object.prototype.pollutedProperty) {

console.log(‘Prototype already polluted:’, Object.prototype.pollutedProperty);

} else {

console.log(‘Prototype not polluted yet.’);

}

res.status(200).send(‘TypedArray created and ready for GC’);

});

app.post(‘/access_after_gc’, (req, res) => {

setTimeout(() => {

if (!isProcessing) {

isProcessing = true;

// Thread 1: Simulate accessing the array after GC

setTimeout(() => {

if (objReference && weakMap.has(objReference)) {

let data = Array.from(objReference).toString();

// Inject into prototype (Prototype Pollution)

Object.prototype.pollutedProperty = ‘Prototype Pollution Detected’;

// Check the prototype after injection

console.log(‘Prototype polluted with:’, Object.prototype.pollutedProperty);

// Send the response to the client

res.status(200).send(‘Use-After-Free and Prototype Pollution detected: ‘ + data);

} else {

res.status(200).send(‘TypedArray has been garbage collected.’);

}

isProcessing = false;

}, 1000); // Delay to simulate thread 1

// Thread 2: Modify the array data

setTimeout(() => {

if (objReference) {

objReference[0] = 231; // Change the value of the TypedArray

console.log(‘Data changed to:’, Array.from(objReference));

}

}, 500); // Delay for thread 2

} else {

res.status(200).send(‘Race condition in progress…’);

}

}, 2000);

});

// Start the server on port 4000

app.listen(4000, () => {

console.log(‘Server running on port 4000’);

});

client:

const axios = require(‘axios’);

async function testUseAfterFreeWithPrototypePollution() {

try {

// Step 1: Send a request to create a TypedArray

let response = await axios.post(‘http://localhost:4000/trigger_gc');

console.log(‘Server response (create TypedArray):’, response.data);

// Step 2: Attempt to access the TypedArray after GC and check for Prototype Pollution

response = await axios.post(‘http://localhost:4000/access_after_gc');

console.log(‘Server response (access after GC):’, response.data);

// Check if the prototype has been polluted

if (Object.prototype.pollutedProperty) {

console.log(‘Prototype Pollution Detected:’, Object.prototype.pollutedProperty);

} else {

console.log(‘No Prototype Pollution Detected.’);

}

// Create a new object to check if the prototype has been updated

const newObj = {};

if (newObj.pollutedProperty) {

console.log(‘New Object Detected Prototype Pollution:’, newObj.pollutedProperty);

} else {

console.log(‘New Object has no Prototype Pollution.’);

}

} catch (error) {

console.error(‘Error:’, error.message);

}

}

// Run the test

testUseAfterFreeWithPrototypePollution();


این کد یک حمله ساده را نشان میدهد که به مهاجم اجازه میدهد از ضعف در مدیریت حافظه جاوا اسکریپت برای اجرای هر دو نوع حمله استفاده پس از آزادسازی حافظه (Use-After-Free) و آلودگی پروتو تایپ (Prototype Pollution) بهره برداری کند. با آلوده کردن پروتوتایپ، این کد تمام اشیاء موجود در سیستم را تحت تأثیر قرار میدهد که میتواند یک ریسک امنیتی جدی ایجاد کند.

نتیجه گیری:

این تنها یک نسخه ابتدایی از چنین حملهای است. از آنجا که ضعفهای موجود در مدیریت حافظه و پروتوتایپهای جاوا اسکریپت میتوانند آسیبپذیریهای جدی ایجاد کنند، اتخاذ بهترین روشها برای مدیریت حافظه و جلوگیری از آلودگی پروتوتایپ ضروری است.

جاوا اسکریپتattackhackernodejs
برنامه نویس علاقه مند به طراحی الگوریتم
شاید از این پست‌ها خوشتان بیاید