Как стать автором
Обновить
33.02
Рейтинг

Web Security Testing Starter Kit

Блог компании Semrush Информационная безопасность *Тестирование веб-сервисов *
Всем привет!

Меня зовут Андрей. Уже 10 лет я занимаюсь поиском уязвимостей в различных веб-сервисах. и готов поделиться своими знаниями с вами. В мае прошлого года я выступал с докладом про это на конференции Heisenbug, а теперь готов поделиться своими знаниями еще и здесь, на просторах Хабра. Итак, начнем.

Однажды я нашел уязвимость на серверах небезызвестной компании Facebook. Ребята забыли обновить ImageMagick (библиотеку по обработке изображений) и поплатились за это:) Этим примером я хотел показать, что все мы люди, и все можем допускать ошибки, неважно, в каких компаниях и на каких должностях мы работаем. Проблема только в том, что эти ошибки могут приводить к разного рода рискам.
Чем сложнее у вас приложение/сайт/инструмент, тем больше вероятность того, что что-то может пойти не так.
Проверять на уязвимости нужно. Глупо не делать этого совсем.

Этапами проверки web приложений могут стать следующие пункты:
  • Подготовка:
    • Определить точки входа — по сути дела откуда в приложение могут поступить данные;
    • Определить скоп технологий;
    • Определить на какие уязвимости имеет смысл проверять;
  • Проверка. Необходимо проверить все уязвимости, которые применимы к скопу технологий вашего веб-приложения;
  • Анализ кода. Не ленитесь, не пропускайте этот пункт. В некоторых случаях без доступа к коду сложно найти какие-либо уязвимости, а еще это позволяет обойти фильтрации, которые могут быть заложены в ваше приложение.

Обо всем этом расскажу подробно.

Итак, подготовка. Не буду заострять внимание на всех типах уязвимостей, иначе количество текста в статье превысит все мыслимые и немыслимые размеры. Советую начать изучение со списка OWASP Top Ten Project. Раз в несколько лет консорциум OWASP формирует лист наиболее актуальных на данный момент уязвимостей. Несколько из них мы рассмотрим детально.

XSS


XSS (межсайтовый скриптинг) — атака на пользователя, которая позволяет атакующему выполнить произвольный сценарий в контексте браузера его жертвы. Чаще всего подразумевается внедрение HTML-тегов и JS-сценариев.
Пример: был в свое время такой сервис Yahoo! Ad Exchange. В форме восстановления пароля был параметр "URL возврата". В нем можно было указать, на какую страницу нужно вернуться после процесса сброса пароля. Если туда вставить тот или иной вектор, который приводит к исполнению JS-кода, можно получить все cookies пользователя. Разберем, как это происходит и почему.


Вот сам вектор. Весь сразу:

Чтобы произвести инъекцию, нужно выйти из контекста той переменной, в которой мы находились по умолчанию (по умолчанию — это то, что предполагал программист, когда писал код).
Ниже представлено исходное значение. Это является валидным поведением.

Видим, что returnURL=/login.jsp
Это попадает в значение тэга <input>.
Если мы добавим кавычку после jsp, то увидим, что посыпался синтаксис HTML. Благо, HTML язык не строгий, парсер пропустит и проблем не будет:

Добавим еще один символ. Здесь мы полностью выходим из контекста тэга <input>:

Теперь добавляем открытие тега <svg>, и получаем два валидных тега с точки зрения синтаксиса:

Далее добавляем весь вектор атаки:

В данном случае отрисовывается svg картинка. С помощью JavaScript хэндлера "onload" выполняем алерт с cookies документа. Все! Атакующий получил ваши cookies.
Если в пруфе мы показываем только сам алерт, то атакующему не составит труда послать куки на подконтрольный ему сервер и, в самом худшем случае, захватить ваш аккаунт. Давайте еще раз посмотрим как это выглядит:


Векторов атаки на клиента также существует больше количество. Приведу несколько примеров с кратким описанием. Но для начала надо понять, как выйти из контекста:
  • Выход из контекста. Эти 6 символов помогут выйти не только из контекста значения параметра HTML, но и из многих других:
    -->'">

Ну и, собственно, два простейших вектора атаки:
  • Вставка ссылки, в частности. А в общем случае — изменение внешнего вида страницы. Например, в вашу страницу могут внедрить html-код и выводить какое-нибудь фейковое окно с запросом данных:

    Строка "аааа" указывает на google.com. Вы можете увидеть, что ссылка отрисовалась на странице, а можете не увидеть, но это не отменяет ее присутствия в коде. И в том, и другом случае дело можно считать сделанным;
  • Исполнение скрипта, например, перехват cookies пользователя:



Где и как искать XSS?


Для начала найдите функции вывода информации/данных на страницу. Проанализируйте, какие данные туда попадают? Здесь появляется такое понятие, как недоверенный источник. И таковым, в первую очередь, является ваш пользователь. Векторы атаки могут содержаться и в любых других источниках: RSS ленты, другие сервисы, как внешние, так и внутренние.
Вот пример из жизни: я работаю в IT компании SEMrush. Мы разрабатываем онлайн-платформу, которая является универсальным инструментом для интернет-маркетологов. Так вот, один сервис у нас сохранял данные, другой выводил, каждая из команд понадеялась друг на друга, получилось так, что на втором сервисе XSS возник из-за отсутствия должной обработки выводимых данных, а первая команда не сочла необходимым входящие данные вообще фильтровать каким-либо образом и хранила их "как есть". Вывод: если вы не знаете, как хранятся те или иные данные, их нужно считать недоверенными. Или заранее договориться о том кто и как хранит, фильтрует, выводит данные.

Если у вас уже присутствуют данные из недоверенных источников, то рекомендую:
  • Изучить фильтрацию поступающих данных;
  • Изучить контекст выводимых данных. Далеко не во всех случаях ХSS может быть исполнена, даже при отсутствии фильтрации. Например, если Content-type ответа: text/plain;
  • Не надеяться на фильтрацию встроенных систем защиты framework-ов.


SQL injection




Внедрение SQL-кода (англ. SQL injection) — внедрение в запрос к базе данных инструкций, которые там не подразумевались.

Пример (не из жизни, но тоже хороший):
Видим скрипт, который выводит таблицу пользователей. В данном случае он умеет осуществлять поиск по имени пользователя.
Справа показано, как выглядит запрос к базе данных, а слева — результат работы скрипта в браузере.

Дальше для того, чтобы протестировать и получить хоть какой-нибудь первичный результат, вставляем две кавычки в значение параметра name. Одинарную и двойную:

Видим, что с точки зрения вывода у нас все развалилось, таблица пропала полностью. В запросе также получаются лишние 2 кавычки. Нарушается весь синтаксис SQL запроса.
Если далее мы возьмем и добавим вот такую конструкцию в значение параметра (прим.ред.: смотри в желтой рамочке), мы получаем абсолютно валидный запрос. Вывод страницы полностью идентичен первому запросу, который не включал в себя инъекцию:

Для того, чтобы полностью убедиться, что уязвимость есть, добавляем вместо единицы двойку:

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

Чтобы не перечислять все то, что может быть в разных движках баз данных и запросах разных типов, я свел все в одну строку:

Это то, что вы можете попробовать ввести в параметр, а далее уже, по разницам в ответах попытаться понять, что происходит, есть там уязвимость или нет. Где-то 80% случаев вы сможете покрыть данной манипуляцией.
Остается 20% сложных ситуаций, в которых это не даст вам никакой информации, например: вложенные запросы/фильтрации и прочее. В своей практике я встречался с подобным только однажды. Тогда мне пришлось обойти фильтрацию на стороне сервиса.

Какую же опасность несет в себе SQL?
  • Из очевидного — утечка информации. Если атакующий смог сформировать запросы к вашим базам данных, он может тем или иным образом получить значения, которые не предполагались для вывода (хэши паролей, адреса клиентов и прочее);
  • Изменение данных. Сейчас многие разработчики используют БД через ORM системы. Сами эти системы по умолчанию позволяют делать несколько запросов за 1 раз, синтаксис SQL также позволяет это делать. При наличии уязвимости все может обратиться не только к выборке данных, но и к их изменению (вплоть до удаления таблиц, изменения структуры базы данных и пр.).
    В этой же ситуации возможно повышение привилегий пользователя. Меняете поля в тех или иных таблицах (например, в базе users поставить is_admins=true) и тем самым поднимаете свои права до админа;
  • DoS. В некоторых случаях инъекция может привести к отказу в обслуживании. Формируется несколько тяжелых запросов к БД, запускается в несколько потоков и ваш сервис на какое-то время может перестать работать;
  • Чтение системных файлов — еще одна беда, которую может принести SQL инъекция. Возникновение этого риска зависит от того, какую систему БД вы используете, а также от того, какой пользователь с ней работает (привилегированный или нет);
  • RCE (Remote Code Execution) — это исполнение кода. Напрямую зависит от типа БД, которая используется (раньше такое было возможно по умолчанию, с дефолтными настройками БД, в MSSQL).

Ниже приведена таблица уязвимых мест в SQL запросе. Запоминать ее, конечно же, не нужно. Кроме этого, это не все возможные варианты, а просто примеры. Просто обратите внимание на то, что красным выделены те места, где может возникнуть инъекция в SQL запрос, если туда придут необработанные данные. Опытный атакующий может найти способ это эксплуатировать. Будьте осторожны и внимательны.


SSRF (Server Side Request Forgery)


Дословный перевод — подделка запросов на стороне сервера. То есть атака, которая позволяет манипулировать данными, которые вы отсылаете приложению, заставляя сделать запрос не туда, куда изначально планировала бизнес-логика.
Работа SSRF демонстрируется на изображении ниже:

Есть атакующий, есть ваш сервер, который закрыт Firewall, но при этом есть функционал, который позволяет делать запросы от имени сервера дальше.
Если этот функционал не защищен должным образом и/или не корректно, как это обычно и бывает:), обрабатывает входящие данные, атакующий может обратиться к Memcached, Redis или получить доступ к любым внутренним ресурсам жертвы.

Для более наглядного примера рассмотрим стенд, который используется в компании SEMrush для внутреннего обучения сотрудников.
Здесь важно обратить внимание на значение "URL аватара":

Здесь обращаем внимание на 2 момента:
  • сам URL аватара;
  • и возможность загрузить его с помощью файла.

Обратите внимание, поле "URL аватара" — текстовое поле для ввода, а значит мы можем манипулировать этим значением. Попробуем поставить на аватар, пожалуй, самую известную картинку в интернете — робота Google со страницы ошибки 404.
Делай раз:

Делай два — жми "Сохранить". Получаем робота вместо моей фотографии:

Тут стоит обратить внимание на то, что значение "URL аватара" поменялось, на какой-то локальный путь — видимо, приложение запросило картинку, сохранило её на сервер и подставило новое значение.

Двигаемся дальше. В поле "URL аватар" вводим значение file:///etc/passwd. Такая конструкция позволяет обращаться к файловой структуре. В некоторых библиотеках, которые используют для работы с HTTP, по умолчанию включена работа с файловой структурой, и получать данные с серверов, на которых они запустились:

Что же произойдет после нажатия кнопки "Сохранить"?..
Во-первых, картинка стала "битой", во-вторых, поменялся путь к файлу.

Если мы попытаемся запросить эту картинку в браузере, нам ничего не покажут (файл "битый"). Но мы-то не первый день в информационной безопасности, мы знаем что надо делать:) Путем нехитрых манипуляций получаем содержание файла на своем компьютере:

Таким образом, с помощью этой уязвимости я, как атакующий, могу получить все исходные коды вашего сервиса и другие данные, доступные для чтения пользователю, от которого работает веб-сервис.
Разберем опасности SSRF:
  • Сканирование портов. Для внешней сети ваш сервис — это одна точка входа и 2 порта (http и https). Сканируя порты изнутри вашей инфраструктуры, атакующий может обнаружить открытые;
  • Обход host-based аутентификации. В чем суть? Вполне возможно, что внутри вашей структуры существуют сервисы, которые доступны только определённым ресурсам (читай: белый список IP). Так вот, если ваш уязвимый сервер находится в white-листе, вы получаете доступ к тем сервисам, которые для него доступны, и, как следствие, можете ими манипулировать;
  • В продолжение развития вышеупомянутой атаки, вы можете продолжать эксплуатировать уязвимые программы, запущенные в интранете или на локальном сервере. Довольно часто происходят ситуации, когда внутренняя инфраструктура, недоступная извне, слабо мониторится (не всегда обновляются версии/security патчи и пр.). Это все также может привести к атакам и краже данных;
  • Чтение локальных данных. Показал это выше на примере. Ваши конфиги можно прочитать и получить доступы, токены и пароли.


Где искать SSRF?


Это не настолько стандартная уязвимость. Она может встречаться в разных, часто в самых неожиданных местах. В данной ситуации прием “тут смотри, а вот сюда можешь даже не смотреть” не работает.
Признаки возможной SSRF:
  • Webhook-и. Если они настроены плохо, если неправильно настроен Firewall на тех серверах, откуда Webhook-и делают запросы, можно получить уязвимость;
  • Конвертация HTML. Попробуйте вставлять <iframe>, <img>, <base>, <script> или CSS конструкцию url, указывающую на внутренний сервис;
  • Загрузка удаленных файлов. Помните пример с аватаром? Когда у пользователя есть возможность загрузить данные по URL на сервер, это влечет за собой большие проблемы. Попробуйте отправить URL c портом и посмотрите, какой контент загрузится.


Как искать SSRF?


  • Поднять сервер и запустить listener:
    user$ nc -1 -n -vv -p 8080 -k

    Таким образом вы будете видеть все запросы, которые приходят на ваш сервер на порт 8080. С одной стороны, это незанятый порт вашими веб-серверами, а с другой стороны, это порт, который часто не фильтруется Firewall. Считается, что он используется для http протокола и запрещать его вроде как необязательно;
  • В исследуемом приложении найти параметр, в который можно передавать путь для запроса данных с нашего хоста (к нашему listener’у);
  • Изучить вывод listner’а или полученный обратно ответ.


XXE (XML External Entity)


Начну рассказ как всегда с примера, чтобы было нагляднее:
В вышеупомянутом сервисе SEMrush есть такой инструмент, который занимается анализом контента. Пользователь вбивает URL своего сайта или сайта-конкурента и перед тем, как его проанализировать, сервис этот самый контент скачивает. Смотрите как это происходит на видео:



Для скачивания сервис обращается к заданному сайту и краулер скачивает файл sitemap.xml. А это уже тот самый XML, о котором мы и ведем речь в этом блоке.
В видеоролике мы можем наблюдать, как атакующий сайта добавил в sitemap.xml определение внешней сущности XXE, которая указывает на "file:///etc/hosts". На Linux системах это файл, в котором описывается, какой IP соответствует хостам, если для них нет DNS записей.
Далее атакующий указывает в тэге <loc> раскрытие этой переменной. Парсер XML после этого, обработав весь XML в купе, в переменную location (выделено на видео красным цветом) вставит то значение, которое было в "file:///etc/hosts".
Атакующий инициирует запуск нашего парсера, идет в логи, и вот тут появляется строка, выделенная на видео белым цветом. Это содержимое файла "file:///etc/hosts", полученное в GET-запросе в логах подконтрольного ему сервера.
Что дальше? Атакующий убедится, что был прав. Поменяет название файла на "file:///etc/fstab", еще раз запустит парсер и получит статистику по запущенным процессам.

И напоследок: "file:///etc/hostname", запуск парсера, заходим в логи и получаем hostname машины, на которой находимся.
Это реальная бага, обнаруженная реальным человеком, не относящимся к нашей компании. Пришлось посыпать голову пеплом и платить деньги:)

Еще один пример XXE:

Предположим, что у нас есть некий endpoint, он так и называется — example.com/xxe.
Отправляем в него XML структуру → в XML объявляем сущность ХХЕ → сущность ХХЕ обращается к системному файлу /etc/passwd и раскрывается дальше в теле ответа → получаем в ответ содержимое этого файла.
Стоит заметить, что это встречается не так часто, как хотелось бы.

Почему это работает?


XML документы — это структурированный формат данных, который, кроме всего прочего, позволяет описать те типы данных, которые могут в нем содержаться, с помощью специального тега DOCTYPE.
Data Type Definition (DTD) — определение типов данных внутри этого XML документа. Есть три варианта того, как это можно сделать:
  • Если документ поддерживает DTD. На примере ниже представлен некий XML, в котором есть структура заказов, есть элемент product и элемент count (предположительно: инвентаризационный номер продукта и количество позиций в заказе). Order является родителем для этих двух элементов:
  • Внешние DTD на локальном сервере.
    Делаем то же самое, что и в первом варианте, но все определения выносим в отдельный файл, который находится на локальном сервере:

  • Внешние DTD на стороннем сервере:

Если вы внимательный читатель, то уже наверняка соотнесли тот факт, что возможность делать такие запросы у вас на сервисе и запрашивать внешние схемы DTD — уже сама по себе уязвимость, о которой мы говорили выше, а именно уязвимость SSRF.
Частое явление: разработчики исправляют XXE уязвимость, но при этом забывают запретить обработку внешних DTD и получают SSRF. Смертельных последствий из этого не последует, но забывать об этом все же не стоит.

Что такое сущности (Entities) в XML?


Entities в XML. Что это? Это возможность определить некие значения и загнать их в переменные. В сущностях есть три разных типа:

Predefined — предопределенные. Аналогичны HTML-коду, дают возможность использовать те символы, которые являются частью синтаксиса языка, как текстовую структуру. Здесь они приведены для примера, чтобы вы поняли, что это такое. Да, в большинстве атак они не используются, но могут понадобиться в некоторых исключительных случаях.
General и Parameter. Это одно и то же, только меняется синтаксис их объявления и то, как их можно вызывать после объявления

Где искать XXE?


Несколько вариантов:
  • Обработка XML в любом проявлении:
    • SVG;
    • sitemap;
  • Конвертация HTML в другие форматы;
  • Обработка docx, xlsx и подобных форматов.


Как их искать?



На картинке изображен всего лишь пример от которого нужно стартовать. Он не является универсальным ключом. Его нужно оптимизировать под те форматы, которые вы используете в исследуемом сервисе.

Первое, что мы делаем: объявляем некую сущность Z, которая обращается к подконтрольному для атакующего хосту, раскрываем ее внутри тела документа XML.
Здесь возможен и второй вариант — как раз сущность Parameter. Отличается от первого объявления (знаком %). И для того, чтобы обратиться к этой сущности, тело документа уже не нужно. Мы можем обратиться к ней напрямую в DOCTYPE структуре и раскрыть эту сущность:

Третий вариант развития событий — посмотреть, включена или выключена возможность запрашивать DOCTYPE c внешних сервисов:

Далее смотрим вывод подконтрольного нам сервера. Если мы видим обращение к URL /check с тех или иных IP-адресов, значит, с большой долей вероятности, уязвимость прошла, и дальше нам просто нужно разбираться, как получить более интересные нам данные.

В чем же состоит опасность XXE? Напишу кратко и по пунктам:
  • Чтение локальных файлов;
  • Доступ к локальным ресурсам;
  • Сканирование портов/хостов;
  • Plain-text wrappers. Это возможность обращаться к вашим сервисам, которые работают по plain-text протоколу;
  • Remote Code Execution (не часто). Он выключен по умолчанию;
  • DoS. За счет того, что сущности можно конкатенировать, есть возможность легко получить экспоненциальный рост объема памяти, занимаемой этими параметрами. Как результат — атака Billion laughs attack. Иными словами, вы просто перегружаете память атакуемого сервера.

В заключение скажу, что все это (статья, да и любые полученные вами знания) не имеют смысла без практического применения. Поэтому попрошу вас о сущей мелочи: задумайтесь о приложении, которое вы писали/тестировали вчера и попробуйте его проверить на уязвимости. Есть ли там формы ввода или обработка XML? А защищено ли это приложение? Добавлена ли фильтрация и отключены ли DTD?
Откройте мануал SQLmap и выясните, как с помощью него проверить ваше приложение. Если он ничего не найдет, возьмите другую тулзу и изучите её, а затем протестируйте свое приложение на другие уязвимости. Как я сказал в начале, в статье разобраны примеры лишь нескольких уязвимостей, но тысячи их.
Я не верю, что можно писать абсолютно безопасный код. Уязвимости всегда есть, просто вы их еще не нашли.
Теги:
Хабы:
Всего голосов 26: ↑25 и ↓1 +24
Просмотры 20K
Комментарии Комментарии 8

Информация

Дата основания
2008
Местоположение
США
Сайт
careers.semrush.com
Численность
1 001–5 000 человек
Дата регистрации