Основы анализа безопасности веб-проектов

Совсем недавно прошел на платформе Stepik курс "Анализ безопасности веб-проектов", от mail.ru. Этот пост представляет собой что-то вроде конспекта курса, который писался по мере прохождения, для того, чтобы проще было систематизировать информацию и обращаться к ней спустя какое-то время. Помимо содержимого курса, старался дополнять материал ссылками на показавшиеся интересными и полезными статьи/ресурсы для более глубокого знакомства с темой.

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

В курсе освещаются (поверхностно, но достаточно, для общего понимания принципов и возможности углубиться самостоятельно) такие уязвимости и направления атаки, как локальное включение данных, инъекция команд, SQL-инъекции, CSRF, XSS и другие.

Перед тем, как перейти к основной части конспекта - хотелось бы оговорить две вещи:

  1. чтение данного поста не заменит прохождение самого курса, т.к. в нем есть весьма и весьма интересные задачи.
  2. если вы - автор/правообладатель курса и вы против публикации такого рода конспекта - напишите сюда.

Сбор информации

Для любой системы есть некая точка входа. Такой точкой может быть url-адрес, ip-адрес компьютера и т.п. Изначально мы должны постараться максимально расширить поверхность атаки, т.е. если точка входа - некое доменное имя - стоит узнать об имеющихся поддоменах, других доменах, принадлежащих той же организации и т.п. И если у первоначальной точки входа не было уязвимостей, возможно их удастся найти в других точках, входящих в поверхность атаки.

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

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

В пассивном анализе рассматриваются:

  1. Использование данных, получаемых через систему доменных имен (DNS, WhoIs)
  2. Поисковые системы
  3. Код клиентской части
  4. Содержимое robots.txt
  5. Используемые компоненты
  6. Социальные сети

Все это может дать некоторую информацию о цели

В ходе активного анализа рассматриваются:

  1. Подбор DNS-записей
  2. Подбор файловых путей
  3. Подбор пользователей
  4. Сканирование портов

DNS и Zonetransfer

Каждый компьютер, подключенный к сети обладает неким IP-адресом.  Для того, чтобы при обращении клиента к серверу не пришлось указывать ip-адрес, существует система доменных имен. При обращении клиента к доменному имени сначала идет обращение к DNS-серверу, получение ответа от него, содержащего IP-адрес целевого сервера, затем идет обращение по полученному IP-адресу.

Для формирования запросов к DNS-серверу есть несколько полезных утилит:

nslookup [-q=ns|mx|afxr|txt] [name] [server]
          -q - тип запроса
          name - имя, которое хотим отрезолвить
          server - DNS-сервер, через который хотим отправить запрос, необязательный параметр, 
по умолчанию будут использованы указанные в настройках клиентской машины сервера

Также можно использовать другие утилиты:

dig [@server] [name] [type]
host [name] [server]

Для получения информации о других доменных именах, связанных с целевой системой (и включения их в поверхность атаки) можно получить список поддоменов данной доменной зоны. Такая задача называется zonetransfer. В большинстве случаев zonetransfer запрещают, но далеко не всегда.

Запрос может быть выполнен следующим образом (используется проект zonetransfer.me, созданный как раз для демонстрации этой возможности):

nslookup -q=ns zonetransfer.me  - выдергиваем "авторитетные" dns-сервера для этой зоны

dig zonetransfer.me @dnsserver axfr  - в качестве dnsserver указываем сервер, полученный на первом шаге. 

Также можно использовать следующие команды под windows:

В командной строке (cmd):

nslookup
set type=ns (указываем, чтохотим увидеть только записи типа ns - DNS-сервера, поддерживающие зону)
zonetransfer.me <Enter>  (получаем список DNS-серверов данной зоны)
server <имя первого DNS-сервера> (указываем, что теперь любые запросы программа отсылает ему)
ls -d zonetransfer.me (получаем вывод всего, что содержится в домене zonetransfer.me)

Как третий вариант - можно использовать веб-сервисы, например: http://www.digwebinterface.com/

WhoIs

Whois - предназначен для получения информации об определенном доменном имени.

Стандартная практика использования следующая:

nslookup <domain.com> - резолвим домен, получая IP-адрес
whois <ip из шага 1> - получаем сеть, к которой принадлежит этот ip-адрес, выявленные адреса можно включать в поверхность атаки

Если выполнить:

whois domain.com

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

Поисковые движки

Содержат массу полезной информации. У поисковых движков есть свой язык запросов, который можно использовать.

inurl: - позволяет задать паттерн, который должен встречаться в url
site: - позволяет искать все, относящееся к конкретному сайту
filetype: - позволяет определять типы документов по расширению (например можно искать все pdf на сайте)
cache: - в качестве параметр применяются url, поисковая машина вернет закешированную копию

Robots.txt

Содержит информацию о каталогах, которые должны/не должны быть индексированы поисковыми системами.

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

HTML-код

Может содержать массу интересной информации. В целом стоит обращать внимание на следующие моменты:

  • комментарии - могут содержать массу интересной информации, например закомментированный код серверной части системы
  • версии распространенных продуктов - позволяют понять "на чем" работает целевая система
  • параметры - GET и POST-параметры, которые не используются по каким-либо причинам
  • файлы и пути - расположение относительно корневой веб-директории

Сканирование портов

Цель - понять что еще находится на целевом сервере, помимо интересущей нас системы.

Для сканирования портов используем стандартную утилиту nmap:

nmap -sS -T4 -n <target>

 -sS      - посылать только syn и считать порт открытым если получен syn_ack 
 -n       - не делать DNS-резолв, влияет на скорость работы
 -T4      - тайминг между запросами, от этого зависит скорость сканирования
 -vvv     - вывод информации о найденных портах по ходу сканирования а не после его окончания
 -p       - сканировать все 65000 портов, а не только самые популярные
 --reason - отображает причину, почему было принято решение о состоянии порта

По ссылке также есть довольно много примеров использования команды с разным набором параметров.

Точки входа в систему

Веб - приложение может принимать данные через:

  • GET / POST методы
  • Cookies
  • Headers
  • Hosts
  • Data sources

Все эти входные данные могут быть модифицированы пользователем, при разработке это нужно всегда осознавать.

HTTP - протокол открытый, т.е. данные передаются без кодирования, любой запрос может быть без особых проблем воспроизведен вручную. 

В ходе анализа как правило воспроизводится следующий цикл:

Для каждого параметра можно проверить состояние системы в трех ситуациях: когда есть данные, когда нет данных и ошибочное состояние (например, параметр неверного типа).

Интересные Header-ы

HTTP 1.1 отличает от HTTP 1.0 наличие header-а "Host". Это было введено для того, чтобы была возможность хостить несколько веб-серверов на одном физическом IP-адресе. Заголовок Host как и все остальные формируется клиентом.

Cookie - передаются в заголовку для сохранения состояния между сессиями.

Для того, чтобы определять IP-адрес пользователя, находящегося за прокси-сервером, был придуман служебный заголовок, который прокси-сервер дописывает: X-Forwarded-For. Некоторые разработчики надеются таким образом распознать реальный адрес клиента и отдают значению этого заголовка приоритет в обработке. Делают тем самым хуже себе, т.к. заголовок легко подделывается.

GET / POST запросы, их перехват и создание в консоли

Для анализа (и подмены "на лету") GET / POST запросов к серверу можно использовать т.н. перехватывающие прокси-сервера. Наиболее распространенные программы такого типа: OWASP ZAP,  Burp SuiteFiddler.

Для выполнения запросов можно подсоединиться к целевому веб-серверу, например так:

telnet ya.ru 80
GET / HTTP/1.1
Host: ya.ru

Для организации HTTPS-соединения можно сделать так:

openssl s_client -connect e.mail.ru:443
GET / HTTP/1.1
Host: e.mail.ru

В качестве более-удобных инструментов для общения с веб-сервером из консоли можно использовать wget (русскоязычная справка)  и curl (русскоязычная справка).

Версия curl для windows: http://curl.haxx.se/download.html

Версия wget для windows: https://eternallybored.org/misc/wget/

wget -O - --header "headername:value" http://target.com
curl -H "headername:value" http://target.com

Неожиданно, но, используя curl через GET-метод также можно передавать тело запроса (не средствами браузера). Например, так:

curl -X GET -H "Content-Type: application/json" -d '{"the": "body"}' 'http://localhost/test/get.php'

Подробное обсуждение здесь.

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

Уязвимости веб-приложений

Раскрытие служебных данных

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

Возможные данные:

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

Причины раскрытия данных:

  • ошибки приложения
  • ошибки конфигурации
  • системы контроля версий
  • html-код
  • "мусорные" файлы

Локальное включение файлов (LFI)

Локальное включение данных довольно часто используется веб-системами , представляет собой передачу через параметры имен локально существующих файлов и их  отображение пользователю.

Например, так:

http://target.com/getpage.php?page=contacts.txt

Код такого рода часто используется для навигации по страницам сайта.

Зная структуру каталогов веб-сервера можно "попросить" его отобразить содержимое других файлов, например, содержащих пароли (/etc/password), примерно так:

http://target.com/getpage.php?page=../../../../../../etc/passwd

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

http://target.com/getpage.php?page=../getpage.php

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

http://target.com/getpage.php?page=contacts

в коде будет добавлено расширение и отображено содержимое файла contacts.txt, то можно использовать null-byte - символ, обозначающий конец строки, чтобы обрезать расширение.

http://target.com/getpage.php?page=../../../../../../etc/passwd%00

Инъекция команд

Инъекция команд - это уязвимость, позволяющая выполнить непредусмотренную разработчиком (или даже любую системную) команду на сервере. Может быть выполнена, если в системе делается вызов какой-либо команды на базе параметров, пришедших от пользователя.

Пример:

http://hosttool.com/tools.php?host=1.2.3.4;pwd

Точка с запятой в данном случае будет разделителем и выполнится команда вида:

ping 1.2.3.4; pwd

В результате мы увидим не только результат команды ping, но и текущий каталог в системе.

http://hosttool.com/tools.php?host=1.2.3.4|pwd

Используя вертикальную черту, можно передавать stdout одной команды на stdin следующей команды, организуя "цепочку".

SQL инъекция

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

Примером может быть запрос такого типа:

http://target.com/login.php?user=alex' OR 1=1

Основные подходы:

  •  сворачивание условия WHERE к истиностному результату при любых значениях параметров (' OR 1=1).
  • присоединение к запросу результатов другого запроса (' UNION select ...)
  • закомментирование части запроса (' --)

Клиентские атаки

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

Same-origin policy - это механизм для защиты данных и методов, пришедших из разных источников.

"Одинаковость" источника определяется по трем признакам: протокол, домен, порт.

Одинаковыми считаются:

http://example.com/

http://example.com/folder/

Разными считаются:

 

http://example.com/

https://example.com/

http://test.example.com/

http://example.com:8080/

http://otherexample.com/

Задача клиентских атак как раз сводится к тому, чтобы каким-либо образом обойти Same-origin policy.

CSRF (cross-site request forgery)

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

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

Например, включив в код сайта-злоумышленника следующую строку, в случае, если пользователь авторизован на target.com, он может сам того не зная оставлять комментарии со спамом:

<img src="http://target.com/post_comment.php?text="spam"/>

 Переделка GET запроса на POST-запрос на target.com не поможет, тогда злоумышленник добавит код вида:

<form action ='http://target.com/form.php'>
<input type=hidden name='id' value=1>
</form>
<script>submitForm()</script>

Для защиты следует использовать CSRF-токены - механизм "подписывания" форм по алгоритму, неизвестному злоумышленнику .При создании защиты от csrf распространенная ошибка - генерация предсказуемых security-токенов. Токены должны всегда создаваться на основе недоступной злоумышленнику информации (зашифровать имя пользователя в md5 - плохая идея!).

XSS (cross-site scripting)

Одна из наиболее часто используемых атак веб-приложений. Основывается на факте, что злоумышленник может вставлять свой код в ответ от веб-сервера пользователю. Основная задача атаки - обойти Same Origin Policy и получить доступ к данным и функционалу клиентской части веб-приложения в рамках пользовательской сессии и с правами ее пользователя.

Существует несколько основных подходов к осуществлению XSS - атак.

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

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

www.target.com/script.php?lang=en<script>alert(1)</script>

Чтобы пользователю не был виден активный элемент - ссылка может быть закодирована механизмом кодирования узлов (goo.gl и т.п.), шифровка параметров в base64 и т.п. Такие ссылки уже вызовут меньше подозрений у пользователя.

Stored XSS - способ реализации атаки, когда код размещается на ресурсе (например, пост с неотфильтрованным js-кодом в гостевой книге), после чего каждый пользователь, зашедший на страницу невольно выполняет этот код.

DOM-based XSS - не требует никаких обращений на сервер со стороны пользователя. Все предпосылки для создания XSS находится в самом браузере. Основывается на том, что в контексте самого браузера есть код, обрабатывающий параметры и содержащий ошибку. К примеру, если участок JS- кода имеет доступ к параметру url и на его основе формирует некий html-код на странице.

Стоит проверить наличие в коде страницы таких конструкций, как:

document.write()
document.writeln()
eval()
.innerHTML

Еще один важный момент - если на странице есть flash (.swf),  то все, что приходит от swf также подлежит строгой валидации, о чем часто забывают

Основной способ защиты - правильная обработка всех входных и выходных данных. Множество векторов атаки описано здесь: http://html5sec.org/, стоит об этом помнить. Много полезного про XSS и то, как правильно строить защиту от него также описано в годной статье на хабре.

Инъекция заголовков (header injection)

В рамках HTTP-протокола заголовки разделяются друг от друга символом перевода каретки (%0d%0a). Если на сайте есть метод, позволяющий сгенерировать заголовок, содержащий символ перевода каретки, после этих символов можно поставить новый header.

Например, если есть некая страница: http://target.com?jump=<user input> при переходе на нее, генерирующая в ответе заголовок

...
Location: <user input>

то передав запрос вида:
http://target.com?jump=hell%0d%0aSet-Cookie: gotohell%3d1 получим в ответе:

...
Location: hell
Set-Cookie: gotohell = 1
...

Таким образом можно будет внедряя заголовки / куки осуществлять XSS-атаку в любом месте страницы.

Фиксация сессии (Session Fixation)

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

Злоумышленник в таком сценарии создает сессию (просто зайдя на сайт и получив sessionid). Далее он передает в рамках какого-то запроса передает сессионный идентификатор пользователю. Пользователь заходит по этой ссылке, вводит свой логин и пароль, сессия при этом остается той же самой. Теперь злоумышленник, используя тот же sessionid имеет права доступа, как у пользователя.

На практике сессии обычно хранятся в cookies-переменных. Таким образом злоумышленнику надо найти  уязвимость, которая позволит пользователю добавить некое cookies-значение, например описанную выше header injection. Как вариант можно попробовать передать значение сессии через GET / POST параметр в надежде, что код на стороне сервера не анализирует источник, а работает с неким глобальным массивом, содержащим GET, POST, COOKIE параметры.

Пост-эксплуатация

Пост-эксплуатация - это то, что можно сделать с целевой системой после того, как удалось найти уязвимость и выполнить какой-то участок кода на целевой системе.

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

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

Злоумышленник может получать информацию о скомпрометированной системе, анализируя:

  • конфигурацию системы (логин и пароль к БД в исходных кодах)
  • конфигурацию веб-сервера (например httpd.conf, .htaccess)
  • исходные коды приложения (ищем уязвимости, анализируя логику приложения)
  • доступы к окружению (находясь внутри сети может быть проще попасть на соседние сервера)
  • базы данных (и аутентификационная информация,к другим системам, хранящаяся в них)

Получение паролей из хеша

Чаще всего пароли хранят в виде хешей. Но есть способы получить пароль, имея его хеш.

Один из самых известных онлайн-брутфорсеров паролей: John the Ripper.

Может быть использован, например, так:

john <passwd file>
john --wordlist=<dictionary pass> <passwd file>
john --format=<formatname> passfile    (список форматов: john --list=formats)

Организация перманентного доступа

Самый простой способ - создать своего пользователя (желательно замаскировав его под системного).

Другой вариант - бинарные бекдоры, которые кладутся на систему и организуется их периодическое выпролнение (через cron или при каждом вызове любой частой команды, например ls).

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

Самый жесткий вариант - патч ядра операционной системы, включение бекдора туда.

Полезные ссылки

Классификация угроз от Web App Security Consorcium

Cheatsheet по угрозам безопасности HTML и не только

SQL Injeciton от А до Я в pdf от Positive Technologies

База раскрытых уязвимостей Exploit DB

Поисковик по уязвимостям vulners.com ( и еще есть статья о нем на хабре)

Лекции от того же автора на YouTube (во многом похожи, но есть часть тем, не раскрытых в курсе, например раздел про CMS)

Обзор инструментов для вскрытия хеша (статья на хабре)