Slide 1

Slide 1 text

Заголовок ptsecurity.com JavaScript: анализируем динамику статикой Владимир Кочетков Валерий Пушкарь POSITIVE TECHNOLOGIES

Slide 2

Slide 2 text

Заголовок 2 • Руководитель отдела исследований по анализу защищённости приложений в Positive Technologies • AppSec- и CS-исследователь в области формальных методов анализа и защиты приложений • Активный участник и организатор Positive Development User Group [email protected] :~$ whoami

Slide 3

Slide 3 text

Заголовок 3 • «Сделайте так, чтобы это был анализатор JavaScript и всем нравился» • «Нужно, чтобы всё было, как в других модулях, но только для JavaScript» • «Обязательно обеспечьте поддержку Node.js» • «А ещё фронтенд было бы неплохо. React.js – обязательно, ну и Angular тоже. Наверное» Базовые требования к исследованию

Slide 4

Slide 4 text

Заголовок 4 • Абстрактная интерпретация в symbolic-семантике • Возможность выполнять отдельные фрагменты кода в песочнице • Доказательство существования уязвимостей через построение векторов атак • Генерация информации для ручного доказательства подозрений на уязвимость Чуть более формально

Slide 5

Slide 5 text

Заголовок 5

Slide 6

Slide 6 text

Заголовок 6 • v7 (2016): Array.prototype.includes(), exponentiation operator. • v8 (2017): async/await, shared memory and atomics, Object.values/Object.entries, string padding, Object.getOwnPropertyDescriptors(),trailing commas in function parameter lists and calls. • v9 (2018): shared memory and atomics, the Rest/Spread properties, asynchronous iteration, Promise.prototype.finally, RegExp Features: s (dotAll) flag, named capture groups, lookbehind assertions, unicode property escapes; Развитие JavaScript (ECMAScript)

Slide 7

Slide 7 text

Заголовок 7 • ChakraCore - интерпретатор языка JavaScript от компании Microsoft (https://github.com/Microsoft/ChakraCore) • написан на С++, кроссплатформенный (Windows, Linux, OS X), поддерживает основные архитектуры: x86, x64, arm; • регистровая архитектура (данные хранятся в регистрах); • использование аппаратного обеспечения по максимуму, потребление минимального количества ресурсов; • оптимизация быстрого запуска и выполнения JS кода; Microsoft ChakraCore

Slide 8

Slide 8 text

Заголовок 8 ChakraCore OpCodes Control flow Br - unconditional branch BrEq_A - branch if '==' (general equals) BrNeq_A - branch if '!=' (not general equals) BrGt_A - branch if '>' BrSrEq_A - branch if '===' (strict equals) BeginSwitch - the start of a switch statement EndSwitch - equivalent to Br OpCode Case - equivalent to Branch if '===' (strict equals) Call - call (direct) registered function Throw - throw exception Ret - return from function Object operations LdFld - load from object instance's direct field StFld - store into object instance's direct field InitFld - declare a property with an initial value DeleteFld - remove a property Instancing operations NewScObject - create new object instance NewScArray - create new array instance NewScFunc - create new function instance NewRegEx - create a new RegEx expression

Slide 9

Slide 9 text

Заголовок 9 Ветвления в ChakraCore 0002 ProfiledLdRootMethodFld R5 = root.checkCondition #2 <2> 0008 StartCall ArgCount: 1 000b ArgOut_A Out0 = R2 000e ProfiledCallIWithICIndex R5 = R5(ArgCount: 1) <2> <0> 0018 BrFalse_A x:003e ( 34) R5 001c ProfiledLdRootFld R6 = root.console #1 <1> 0022 ProfiledLdMethodFld R5 = R6.log #0 <0> 0026 StartCall ArgCount: 2 0029 ArgOut_A Out0 = R6 002c ProfiledArgOut_A Out1 = R3 <1> 0031 ProfiledCallIWithICIndex R5(ArgCount: 2) <0> <1> 003b Br x:005d ( 31) 003e ProfiledLdRootFld R6 = root.console #1 <1> 0044 ProfiledLdMethodFld R5 = R6.log #0 <0> 0048 StartCall ArgCount: 2 004b ArgOut_A Out0 = R6 004e ProfiledArgOut_A Out1 = R4 <2> 0053 ProfiledCallIWithICIndex R5(ArgCount: 2) <0> <2> 005d Ret if (checkCondition()) { console.log('True branch') } else { console.log('False branch') }

Slide 10

Slide 10 text

Заголовок 10 Работа с ветвлениями C1 C1 and !C2 False Line Br C2 (C1 and !C2) or (C1 and C2) C1 and C2

Slide 11

Slide 11 text

Заголовок 11 Вычисление условий для значений переменных C1 (C1 and !C2) or (C1 and C2) C1 and !C2 False Line Br C2 Сохраняем значения и их условия Переписываем значения, используя условие С1 and !C2 Мержим текущие значения для условия перехода C1 and C2 C1 and C2

Slide 12

Slide 12 text

Заголовок 12 Слияние состояний OR Ничего не делаем Значения до перехода с их условиями AND условие перехода Fi-нода Множество значений до прыжка и после различаются Множество значений до прыжка и после совпадают Значения и их условия уже верны Значения и их условия на момент слияния

Slide 13

Slide 13 text

Заголовок 13 • string • number • boolean • null • undefined • symbol • object Типы в JavaScript

Slide 14

Slide 14 text

Заголовок 14 Прототипная система типов //Создание нового объекта var foo = {name: "foo", one: 1, two: 2}; //Создание еще одного нового объекта var bar = {two: "two", three: 3}; bar.__proto__ = foo; // foo теперь является прототипом для bar //Если теперь мы попробуем получить доступ к полям foo из bar, то всё получится bar.one // Равно 1 //Свои поля тоже доступны bar.three // Равно 3 //Собственные поля выше по приоритету полей прототипов bar.two; // Равняется "two"

Slide 15

Slide 15 text

Заголовок 15 Конструирование объектов (1/2) var bike = { name: 'SuperSport', manufacturer: 'Ducati', start: function () { console.log('Starting the engine...'); } }; bike.wheelType = 'Alloy'; console.log(bike.wheelType); //Output: Alloy bike.start(); //Output: Starting the engine... //Adding method stop() later to the object bike.stop = function () { console.log('Applying Brake...'); } bike.stop(); //Output: Applying Brake... function Vehicle(name, manufacturer) { this.name = name; this.manufacturer = manufacturer; } var car1 = new Vehicle('Fiesta', 'Ford'); var car2 = new Vehicle('Santa Fe', 'Hyundai’); console.log(car1.name); //Output: Fiesta console.log(car2.name); //Output: Santa Fe

Slide 16

Slide 16 text

Заголовок 16 Конструирование объектов (2/2) var car = Object.create(Object.prototype, { name: { value: 'Fiesta', configurable: true, writable: true, enumerable: false }, manufacturer: { value: 'Ford', configurable: true, writable: true, enumerable: true } }); console.log(car.name); //Output: Fiesta class Vehicle { constructor(name, manufacturer, engine) { this.name = name; this.manufacturer = manufacturer; this.engine = engine; } } var bike1 = new Vehicle('Hayabusa', 'Suzuki', '1340cc'); var bike2 = new Vehicle('Ninja', 'Kawasaki', '998cc'); console.log(bike1.name); //Output: Hayabusa console.log(bike2.maker); //Output: Kawasaki

Slide 17

Slide 17 text

Заголовок 17

Slide 18

Slide 18 text

Заголовок 18 // C# string parm = Request.Params["parm"]; var data = Convert.FromBase64String(parm); string str1 = Encoding.UTF8.GetString(data); Response.Write("" + str1 + ""); // JavaScript const parm = req.query.parm; var str1 = base64decode(parm); res.send("" + str1 + ""); Связывание выражений (1/3)

Slide 19

Slide 19 text

Заголовок 19 // C# string parm = Request.Params["parm"]; var data = Convert.FromBase64String(parm); string str1 = Encoding.UTF8.GetString(data); Response.Write("" + str1 + ""); // JavaScript const parm = req.query.parm; var str1 = base64decode(parm); res.send("" + str1 + ""); Связывание выражений (2/3) ????????????????????????????????????????????????? byte[] global::System.Convert.FromBase64String(string)

Slide 20

Slide 20 text

Заголовок 20 // C# string parm = Request.Params["parm"]; var data = Convert.FromBase64String(parm); string str1 = Encoding.UTF8.GetString(data); Response.Write("" + str1 + ""); // JavaScript const parm = req.query.parm; var str1 = base64decode(parm); res.send("" + str1 + ""); Связывание выражений (3/3) byte[] global::System.Convert.FromBase64String(string) global['require']('nodejs-base64').base64decode()

Slide 21

Slide 21 text

Заголовок 21 • Entity-литералы, суть – именованные ссылки на сущности среды выполнения JavaScript трёх типов: • Объекты • Массивы • Функции • Каждый entity-литерал хранит ссылку на родительскую сущность, скоупу которой он принадлежит • Кроме корневого entity-литерала «global» Entity-литералы

Slide 22

Slide 22 text

Заголовок 22 В определённых ситуациях интерпретатор JavaScript пытается осуществить приведение типов с помощью одного из алгоритмов (набора правил): • ToString • ToBoolean • ToNumber (ToInteger, ToInt32, ToUint32, ToInt16, ToUint16, ToInt8, ToUint8, ToUint8Clamp) • ToPrimitive • OrdinaryToPrimitive • NumberToString • ToObject Неявное приведение типов

Slide 23

Slide 23 text

Заголовок 23 Приведение типов в equality-операторах

Slide 24

Slide 24 text

Заголовок 24 «Всё, что нужно знать» о JavaScript

Slide 25

Slide 25 text

Заголовок 25 Создание точек входа в Express.js (и не только): var express = require('express'); var app = express(); app.get('/', function (req, res) { // это оно и есть res.send('Hello World!'); }); app.listen(3000, function () { console.log('Example app listening on port 3000!'); }); Динамика во всём

Slide 26

Slide 26 text

Заголовок 26

Slide 27

Slide 27 text

Заголовок 27 false => ![] true => !![] undefined => [][[]] NaN => +[![]] 0 => +[] 1 => +!+[] 2 => !+[]+!+[] 10 => [+!+[]]+[+[]] Array => [] Number => +[] String => []+[] Boolean => ![] Function => []["filter"] eval => []["filter"]["constructor"]( CODE )() window => []["filter"]["constructor"]("return this")() ... (ещё «100500» паттернов) JSF**k • Как анализировать ТАКОЕ в статике? • Распознавание и выполнение подобного кода – не сработает • Реализация всех правил неявного преобразования в семантике symbolic вычислений === (слабоумие && отвага || самоубийство)

Slide 28

Slide 28 text

Заголовок 28 var a = "x"; var b = "ss"; var c = a + b; var o = {}; o[c.toUpperCase()] = function () { return http_request_params["param1"]; } http_response.send(o.XSS()); // XSS by param1 Общий случай: динамический код • В JavaScript динамическим является практически всё: • иерархия, структура и состояния объектов; • граф связывания выражений; • структура интерпретируемых модулей; • граф вызовов; • и т.д. • Чтобы проанализировать это в статике нужна… динамика!

Slide 29

Slide 29 text

Заголовок 29 • Частичное вычисление – рекурсивная интерпретация отдельных узлов symbolic-выражений в реальной среде выполнения: • JavaScript runtime • Node.js runtime • Интерпретатор pure-семантики булевых выражений • Основная стратегия: «в любой непонятной ситуации, вычисляй всё, что можно вычислить (но не больше)». Частичное вычисление

Slide 30

Slide 30 text

Заголовок 30 var a = "x"; var b = "ss"; var c = a + b; var o = {}; o[c.toUpperCase()] = function () { return http_request_params["param1"]; } http_response.send(o.XSS()); // XSS by param1 Процесс частичного вычисления "x" – литерал "ss" – литерал Evaluate("x" + "ss") === "xss" {} – пустой объект Evaluate("xss".toUpperCase()) === "XSS" http_request_params["param1"] – неизвестная o.XSS – известная функция, «проваливаемся» в неё и получаем в ответе: http_request_params["param1"]

Slide 31

Slide 31 text

Заголовок 31 Наряду с истинными и ложными булевыми, выражения в JavaScript могут также быть истинноватыми (truthy) и ложноватыми (falsy) – буленоватыми. Буленоватым называют выражение, не принадлежащее множеству { true, false }, но приводимое к одному из этих значений неявно, например, в условных операторах. Может ли данный код вывести в консоль значение 'false': if (x) { console.log(x.valueOf()) } ? Буленоватая логика (1/3)

Slide 32

Slide 32 text

Заголовок 32 Наряду с истинными и ложными булевыми, выражения в JavaScript могут также быть истинноватыми (truthy) и ложноватыми (falsy) – буленоватыми. Буленоватым называют выражение, не принадлежащее множеству { true, false }, но приводимое к одному из этих значений неявно, например, в условных операторах. Может ли данный код вывести в консоль значение 'false': if (x) { console.log(x.valueOf()) } ? Буленоватая логика (2/3)

Slide 33

Slide 33 text

Заголовок 33 Наряду с истинными и ложными булевыми, выражения в JavaScript могут также быть истинноватыми (truthy) и ложноватыми (falsy) – буленоватыми. Буленоватым называют выражение, не принадлежащее множеству { true, false }, но приводимое к одному из этих значений неявно, например, в условных операторах. Может ли данный код вывести в консоль значение 'false': if (x) { console.log(x.valueOf()) } ? Буленоватая логика (3/3)

Slide 34

Slide 34 text

Заголовок 34 SMT-солвер условий JavaScript-выражений?

Slide 35

Slide 35 text

Заголовок 35 Pure-семантика булевых выражений Значения PureTrue PureFalse Boolean PureBoolean JSBoolean Значения: JSTrue JSFalse Операции: JSAnd JSOr JSNot Операторы JS Операции PureAnd PureOr PureNot ToPureBoolean Выражение типа PureBoolean не может содержаться в выражении любого типа JavaScript (но не наоборот, т.к. есть ToPureBoolean)!

Slide 36

Slide 36 text

Заголовок 36 SMT-солвер условий JavaScript-выражений! Преобразование уравнения в формат SMT-LIB Решение уравнения в SMT-солвере Применение «ad-hoc» теорий Преобразование модели решения в symbolic-представление Microsoft Z3 CVC4 SMT via Automata.NET Equality assertions Fixed points Invertible functions Отображение модели решения на исходное уравнение Частичное вычисление узлов уравнения Решены новые узлы? Преобразования в семантике pure boolean Выделение доп.условий Возврат решения да нет

Slide 37

Slide 37 text

Заголовок 37

Slide 38

Slide 38 text

Заголовок 38 • JS Runtime package processor: • require; • console; • promise; • ExpressJS package processor: • get, post, …, all; • use; • send; • listen; • Nodejs-base64 package processor: • base64decode; • base64encode; Package-процессоры

Slide 39

Slide 39 text

Заголовок 39 Верхнеуровневая архитектура анализатора Report Detection manager … CSRF detector Injection detector SMT solver Bytecode interpreter Code provider ChakraCore dumper Project system tooling Package processors … Express.js processor JS runtime processor Register-based symbolic VM Interpretation manager Symbolic scopes Evaluator Pure-Boolean transformer Node.js runtime ChakraCore runtime

Slide 40

Slide 40 text

Заголовок 40 Демо youtu.be/GkbEjqWr5yI

Slide 41

Slide 41 text

Заголовок 41 Экспоненты: M потока управления var express = require('express'); var app = express(); app.get('/', function (req, res) { var response = req.query.param; if (req.query.cond1 == 'ok') { return; } else if (req.query.cond2 == 'ok') { return; } else ... if (req.query.condM == 'ok') { return; } else ; res.send(response); }); app.listen(3000, function () { }); M Память Время 1 20549632 00:00:00.5937500 ... 18 33894400 00:00:00.8750000 19 49442816 00:00:01.2968750 20 75538432 00:00:02.1406250 21 119848960 00:00:04.6875000 22 218234880 00:00:12.8593750 23 398086144 00:00:42.2656250 24 781717504 00:02:25 25 1675882496 00:08:55.1406250 26 3306426368 00:34:33.2343750

Slide 42

Slide 42 text

Заголовок 42 Экспоненты: M потока вычисления var express = require('express'); var app = express(); app.get('/', function (req, res) { var response = req.query.param; if (req.query.cond1 == 'ok') { response = '1'; } else if (req.query.cond2 == 'ok') { response = '2'; } else ... if (req.query.condM == 'ok') { response = 'M'; } else ; res.send(response); }); app.listen(3000, function () { }); M Память Время 1 20828160 00:00:00.5937500 ... 12 25251840 00:00:00.7500000 13 26234880 00:00:00.8437500 14 28987392 00:00:01.1250000 15 34451456 00:00:01.9687500 16 44302336 00:00:05.0781250 17 107339776 00:00:16.3906250 18 276717568 00:01:01.9531250 19 579211264 00:04:16.7812500 20 1014247424 00:18:38.0781250

Slide 43

Slide 43 text

Заголовок 43 Экспоненты: M потока вычисления с обратной связью var express = require('express'); var app = express(); app.get('/', function (req, res) { var response = req.query.param; if (req.query.cond1 == 'ok') { response = response + '1'; } else if (req.query.cond2 == 'ok') { response = response + '2'; } else ... if (req.query.condM == 'ok') { response = response + 'M'; } else ; res.send(response); }); app.listen(3000, function () { }); M Память Время 1 20398080 00:00:00.6562500 ... 8 24850432 00:00:00.7812500 9 25255936 00:00:00.9531250 10 25178112 00:00:01.4062500 11 27291648 00:00:02.8125000 12 30334976 00:00:08.7656250 13 31444992 00:00:29.5156250 14 32161792 00:01:51.1093750 15 37257216 00:07:55.5625000 16 51576832 00:40:27.6718750

Slide 44

Slide 44 text

Заголовок 44

Slide 45

Slide 45 text

Заголовок ptsecurity.com Спасибо! Спасибо!