محققان مرکز امنیت اطلاعات هلمهولتز (CISPA) و مؤسسه سلطنتی فناوری (سوئد) کاربرد تکنیک آلایندگی نمونه اولیه جاوا اسکریپت را برای ایجاد حملات بر روی پلتفرم Node.js و برنامه های محبوب مبتنی بر آن تجزیه و تحلیل کردند که منجر به اجرای کد می شود.
روش آلودگی نمونه اولیه از ویژگی زبان جاوا اسکریپت استفاده می کند که به شما امکان می دهد ویژگی های جدیدی را به نمونه اولیه اصلی هر شی اضافه کنید. برنامهها ممکن است حاوی بلوکهای کد (ابزارکها) باشند که عملکرد آنها تحت تأثیر یک ویژگی جایگزین قرار میگیرد؛ برای مثال، کد ممکن است حاوی ساختاری مانند 'const cmd = options.cmd || "/bin/sh"'، که اگر مهاجم بتواند ویژگی "cmd" را در نمونه اولیه اصلی جایگزین کند، منطق آن تغییر خواهد کرد.
یک حمله موفقیت آمیز مستلزم آن است که برنامه بتواند از داده های خارجی برای ایجاد یک ویژگی جدید در نمونه اولیه اصلی شی استفاده کند و اجرا با ابزاری مواجه شود که به ویژگی اصلاح شده بستگی دارد. تغییر نمونه اولیه با پردازش ویژگی های سرویس "__proto__" و "constructor" در Node.js انجام می شود. ویژگی "__proto__" نمونه اولیه کلاس شی را برمی گرداند و ویژگی "constructor" تابعی را که برای ایجاد شیء استفاده شده است، برمی گرداند.
اگر کد برنامه حاوی تخصیص "obj[a][b] = value" باشد و مقادیر از داده های خارجی تنظیم شده باشند، مهاجم می تواند "a" را روی مقدار "__proto__" تنظیم کند و به نصب ویژگی خود دست یابد. با نام "b" و مقدار "value" در نمونه اولیه شی (obj.__proto__.b = value;)، و ویژگی تنظیم شده در نمونه اولیه در همه اشیا قابل مشاهده خواهد بود. به طور مشابه، اگر کد حاوی عباراتی مانند “obj[a][b][c] = مقدار باشد، با تنظیم “a” به مقدار “constructor” و “b” به “prototype” در تمام اشیاء موجود، میتوانید یک ویژگی جدید با نام "c" و مقدار "value" تعریف کنید.
مثالی از تغییر نمونه اولیه: const o1 = {}; const o2 = New Object(); o1.__proto__.x = 42; // ایجاد ویژگی "x" در نمونه اولیه console.log (o2.x)؛ // دسترسی به ویژگی "x" از یک شی دیگر // خروجی 42 خواهد بود، زیرا نمونه اولیه از طریق شی o1 تغییر کرده است، که در شی o2 نیز استفاده می شود.
نمونه ای از کد آسیب پذیر: تابع enterPoint (arg1, arg2, arg3){ const obj = {}; const p = obj[arg1]; p[arg2] = arg3; بازگشت p; }
اگر آرگومان های تابع enterPoint از داده های ورودی تشکیل شده باشند، مهاجم می تواند مقدار "__proto__" را به arg1 منتقل کند و یک ویژگی با هر نامی در نمونه اولیه root ایجاد کند. اگر arg2 مقدار "toString" و arg3 مقدار 1 را ارسال کنید، می توانید خاصیت "toString" را تعریف کنید (Object.prototype.toString=1) و برنامه را در طول تماس با toString() از کار بیندازید.
نمونه هایی از موقعیت هایی که می توانند منجر به اجرای کد مهاجم شوند عبارتند از ایجاد ویژگی های "main"، "shell"، "exports"، "contextExtensions" و "env". به عنوان مثال، یک مهاجم می تواند یک ویژگی "main" در نمونه اولیه یک شی ایجاد کند و مسیر اسکریپت خود را در آن بنویسد (Object.prototype.main = "./../../pwned.js") و این ویژگی در زمان اجرا در کد ساختار require("my-package") فراخوانی می شود، اگر بسته موجود به صراحت خاصیت "اصلی" را در package.json تعریف نکند (اگر ویژگی تعریف نشده باشد، از نمونه اولیه ریشه به دست خواهد آمد). خصوصیات "شل"، "اکسپورت" و "env" را می توان به طور مشابه جایگزین کرد: اجازه دهید rootProto = Object.prototype; rootProto["exports"] = {".":"./changelog.js"}; rootProto["1"] = "/path/to/npm/scripts/"; // باعث فراخوانی نیاز ("./target.js"); Object.prototype.main = "/path/to/npm/scripts/changelog.js"; Object.prototype.shell = "گره"; Object.prototype.env = {}; Object.prototype.env.NODE_OPTIONS = "—inspect-brk=0.0.0.0:1337"; // باعث فراخوانی نیاز ("بایت");
محققان 10 بسته NPM را با بیشترین تعداد وابستگی تجزیه و تحلیل کردند و دریافتند که 1958 مورد از آنها ویژگی اصلی در package.json ندارند، 4420 بسته از مسیرهای نسبی در دستورات مورد نیاز خود استفاده می کنند و 355 مورد به طور مستقیم از API جایگزینی دستور استفاده می کنند.
یک مثال کاربردی، یک اکسپلویت برای حمله به باطن سرور Parse است که ویژگی evalFunctions را لغو میکند. برای سادهسازی شناسایی چنین آسیبپذیریهایی، یک جعبه ابزار ایجاد شده است که روشهای تحلیل استاتیک و پویا را ترکیب میکند. در طول آزمایش Node.js، 11 ابزار شناسایی شدند که می توانند برای سازماندهی حملاتی که منجر به اجرای کد مهاجم می شوند، استفاده شوند. علاوه بر سرور پارس، دو آسیبپذیری قابل بهرهبرداری نیز در NPM CLI شناسایی شد.
منبع: opennet.ru