Разработка веб-приложений похожа на задачку про два стула, где реализовать функционал, не допустив при этом уязвимость, крайне непросто. Особенно сильно это проявляется при сжатых сроках. Независимо от того, какой язык используется, насколько хорошо написан код, какие задействованы фреймворки — недостатки будут появиться даже в проверенном и легаси коде, важно уметь их оперативно выявлять, устранять и не придерживаться правила: «лучше XSS в проде, чем RCE в деве».

Веб-разработка развивается очень быстро, постоянно появляются новые технологии, а с ними и новые угрозы безопасности. Поэтому мы разработали отдельную программу практической подготовки WebSecOps, рассчитанную на тех, кто хочет прокачать навыки в области веб-безопасности.

Вы, наверняка, слышали про Zero Security: A и Корпоративные лаборатории, а также про пентест-площадки Test lab, отмеченные, как одни из лучших в российском сегменте. Имея большой опыт проведения обучения, являясь разработчиками собственного продукта — Nemesida WAF, ежедневно сталкиваясь с тысячами атак, мы хотим поделиться своим опытом:

  • как выявлять и валидировать уязвимости;
  • как отличить реальную атаку от False Positive;
  • как реагировать на сложные атаки и правильно использовать WAF для их блокирования;
  • какие существуют техники обхода WAF и как им противостоять.

Чем будем заниматься во время обучения?

  • познакомимся с обновленной методологией тестирования на проникновение и OWASP TOP 10 2021;
  • рассмотрим популярные уязвимости веб-приложений: SQL, NoSQL, RCE, CSRF, SSTI и т.д., а также научимся их искать и эксплуатировать;
  • посмотрим, как WAF помогает защититься от хакерских атак, изучим методы выявления атак (сигнатурный / ML), их достоинства и недостатки;
  • изучим методы обхода WAF;
  • и самое важное — закрепим полученные знания на практике.

Курс построен по принципу 20% теория и 80% практика. Это совершенно не означает, что материала будет мало, но в той или иной мере «гуглить» все равно придется. Наша задача не натренировать до автоматизма эксплуатацию SQLi в параметре ID, мы хотим передать знания, научить анализировать ситуацию, искать решение и добиваться поставленной цели в максимально реальных условиях.

Разберем пример практических заданий:

По условиям задания нам доступны 2 сервера с веб-приложением wso.example.lab и wso2.example.lab.

Материал носит информационный характер. Не нарушайте законодательство.

wso.example.lab

При анализе веб-приложения обнаруживаем только название домена example.lab, больше ничего потенциально интересного обнаружить не удалось. Просканируем сервер с помощью Nmap и посмотрим, какие порты открыты на нем.

#nmap wso.example.lab

Из представленного списка нас интересует порт 53, который обычно используется сервисом DNS. При помощи команды:

#dig type=ns wso.example.lab

узнаем, что DNS-сервер имеет IP-адрес 192.168.61.27, который так же является IP-адресом веб-приложения. С помощью инструмента subbrute производим перебор поддоменов для example.lab, wso.example.lab и wso2.example.lab. Для wso2.example.lab обнаруживаем домен 4 уровня dev.wso2.example.lab.

#python3 subbrute.py wso2.example.lab

Поработаем с доменами wso2.example.lab и dev.wso2.example.lab. Веб-приложения, представленные на этих доменах, одинаковые, но домен 4 уровня dev. намекает, что он предназначен для разработчиков. Для работы с веб-приложением необходимо пройти аутентификацию, но у нас имеется только логин и функция восстановление пароля. Просканировав сайт с помощью инструмента Dirb находим интересную информацию:

#dirb http://wso2.example.lab

#dirb http://dev.wso2.example.lab

Директория .git потенциально говорит о возможности получения исходного кода проекта веб-приложения. Попробуем выполнить это с помощью утилиты git-dumper:

#python3 git-dumper http://dev.wso2.example.lab/.git/ git/

Теперь мы можем посмотреть исходный код веб-приложения, где находим файл login.php с функциями restore_password и send_token.

login.php

При восстановлении пароля должна формироваться ссылка вида https://wso2.example.lab/?operation=fpassword&token=. Необходимый токен генерируется путем хеширования с помощью MD5 email-адреса и времени в определенном формате. Так как email-адрес у нас есть, то попробуем подставить эти значения:

Восстанавливаем пароль и входим

На странице мы можем сортировать записи. Проверим параметры на наличие SQL-инъекций. Для этого воспользуемся инструментом SQLMap:

#sqlmap -r /root/request --dbs --level 3

После дампа таблиц получаем токен для задания. Теперь обращаемся к wso3.example.lab. Ссылка для перехода на этот сервер без дополнительной авторизации находится на странице wso2.example.lab. После перехода оказываемся в тикетной системе.

wso3.example.lab

Но так как мы переходили на страницу с сайта, исходные коды которого мы получили ранее, то сначала посмотрим как эта ссылка формируется. Для начала просматриваем файл шаблона, который формирует страницу, где видим обращение к функции auth_string:

Ищем эту функцию и анализируем ее код

Из анализа исходного кода понимаем, что при генерации ссылки учитывается user_group (тип пользователя). Типов всего 2, мы об этом узнали в процессе дампа таблиц:

Значение для параметра auth_string формируется в виде закодированного JSON. Но для подделки значения нам необходимо узнать sol, который никак не описан в исходном коде.

На основе исходных файлов составляем скрипт для декодирования и запускаем


Видим, что повторяется строка egikmjepojgio.

Для выполнения кодирования вносим изменения в скрипт и запускаем

Получившееся значение подставляем в ссылку и получаем доступ с правами модератора.

wso3.example.lab

Проверяем наличие шаблонизатора, для этого в поле для поиска вводим {{4*4}}. Выполнение математической операции говорит об использовании шаблонизатора Twig и наличии уязвимости SSTI. После изучения документации шаблонизатора используем команды для получения информации, например:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

На основе информации из тикетов делаем вывод, что на сайте для чего-то используется salt (соль), но поиск по ключевому слову не дал результатов. Возможно, нужная переменная определена где-то в другом месте. Проведя поиск по ключевым словам находим упоминание msalt в файле config.php

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat config.php | grep msalt")}}

Полученную строку объединяем с логином администратора и дважды применяем хеширование с помощью MD5:

Полученную строку применяем в качестве значения для cookie и обновляем страницу для получения токена.

Обязательно ли разработчику думать о безопасности, когда есть современные фреймворки? И как гласит старинная поговорка: «Семь раз прочти, один раз запишись на WebSecOps». До встречи!