В проблеме "визуализации" собранного трафика необходимо решить две задачи:
- Классификация трафика
- "проигрывание" трафика заданного типа в соответствующем приложении
Анализ публикаций в Интернете
- wireshark + ncat http://aerokid240.blogspot.ru/2009/12/replaying-captured-web-traffic-using.html
- Fiddler AutoResponder (http://114r16.blogspot.ru/2012/08/replaying-session-with-fiddler.html)
- perl утилита http://patrick.net/sprocket/rwt.html
- обсуждение https://www.mail-archive.com/tcpreplay-users@lists.sourceforge.net/msg00658.html
- etherape - интересная штука для визуалиации трафика (http://en.wikipedia.org/wiki/EtherApe)
- web page replay - https://github.com/chromium/web-page-replay
- на основе MITM - http://mitmproxy.org/doc/
- Загадочная TCPopera (обрывочная информация, доклады и презентации на просторах гугла)
- NetScout (типа готовое решение) http://www.netscout.com/Pages/default.aspx
- Load/Replay с проксированием, используемые в основном для репродукции багов: Loadster (http://www.loadsterperformance.com/documentation/tutorial), Selenium (http://docs.seleniumhq.org/), solex (http://solex.sourceforge.net/), WaRR (https://code.google.com/p/warr/)
- В рамках задачи session replay (предполагается наличие специального ПО на сервере или клиенте): http://en.wikipedia.org/wiki/Session_replay
- XPlico http://www.xplico.org
http трафик
Сегодня HTTP - это стандарт де-факто в веб-программировании. Как следствие веб-трафик - это не только браузерный серфинг, но и, к примеру, мобильные приложения. По данным исследователей на 2013 год, мобильный трафик составляет около 10%. Будем считать, что задача отсеивания только браузерного трафика решена на этапе классификации.
Веб трафик представляет собой ряд HTTP запросов и ответов, происходящих в определенный промежуток времени. Как только пользователь открывает страницу браузера выполняется множество HTTP запросов. Каждый запрос относится к определенному веб-объекту, такому как видео, картинка, HTML файл, флеш файл, яваскрипт и проч. Можно выделить основной запрос пользователя, и целый ряд запросов, которые браузер выполнил самостоятельно. Основной запрос, как правило возвращает HTML или XML, который содержит ряд встроенных веб-объектов, каждый из которых оборачивается очередным HTTP вызовом. Цель номер один - определить в трафике основные запросы. Затем понять какие HTTP запросы были вызваны подгрузкой встроенных объектов.
Выделение основных запросов
Посмотрим на запросы, полученные в итоге простой последовательности
действий - открыть страницу ya.ru, ввести для поиска слово test и
перейти по ссылке на Википедию. Записанный трафик - файл
wikipedia_request.pcap
, выделенные HTTP заголовки сложены в
wikipedia_request.parsed
. Получилось 18 запросов.
Мы знаем, что основными запросами являются - ввод адреса ya.ru, submit в
форме поиска и клик по ссылке на Википедию. Если расчертить все HTTP
запросы в виде графа, в котором HTTP заголовоки являются вершинами, а ребро от
вершины A к вершине B существует тогда и только тогда, когда в вершине B
имеется поле Referer, значение которого совпадает со значением URL
вершины A (восстанавливается из Host и GET), то получится картинка,
представленная в wikipedia_request.png
. Четко видно три основных
источника, соответствующих основным запросам. Таким образом, подсчитывая
ссылки и учитывая время, прошедшее между запросами, можно с определенной
уверенностью восстанавливать активность пользователя. Затем, используя
графы ссылок, можно понять какие встроенные объекты были запрошены
браузером пользователя автоматически, отыскать их "следы" в HTML
странице, полученной в ответ на соответствующий основной запрос,
осуществить их перезапись, указав локальный источник и направить данный
HTML в браузер.
Проблемы
Существует целый океан проблем, с которым можно столкнуться, используя приведенную выше эвристику. Ниже будут приведены примеры граблей на которые очень легко наступить. В первом приближении не стоит зацикливаться на всех сложностях. Надо реализовать простейший вариант обработки, рабочий прототип, а затем решать проблемы по мере их поступления.
Параноики
Некоторые пользователи используют специальное ПО для ослабления "слежки" за ними со стороны ИТ-гигантов. Ярким примером является расширения для браузеров от EFF - "Privacy badger" (https://www.eff.org/privacybadger). Такое ПО вырезает из запросов ряд полей, в том числе "referer". К счастью таких пользователей мало.
Фантомные запросы
С первой мы столкнулись прямо в примере -
внимательный читатель отметит, что на изображении вершина
yandex.ru/yandsearch?text=test
помечена красным. Дело в том, что это
так называемая "фантомная" вершина - не существует пользовательского GET
запроса GET /yandsearch?text=test
к хосту yandex.ru. Таким образом у
11 ответов указан referer, не соответствующий пользовательскому запросу.
Поисковый запрос выглядел так:
GET /jclck/dtype=stred/pid=0/cid=2873/path=morda_ru.not_used.p0.nah_not_shown.keyboard/user_input=test/text=test/times=20.52.23.19.16.20/region=1/log=sgtype%3ABBBBBBBBBB/pos=4/ratio=4.4.4/since_first_change=3919/since_last_change=3504/session=1401026534664/*data=url%3Dhttp%3A%2F%2Fya.ru/ HTTP/1.1
Host: clck.yandex.ru
Referer: http://ya.ru/
Не ассоциировав фантомный запрос с реальным мы не смогли "подцепить" его
к ветке http://ya.ru
. Простого способа такой ассоциации не существует,
тем не менее, учитывая временную линию и приняв фантомный запрос за
основной - получаем довольно точную картину активности пользователя. К
сожалению во многих случаях на такое способен только квалифицированный
специалист.
Чрезвычайная сложность веб-приложений
Основной HTML и встроенные объекты в современных веб-приложениях очень тесно переплетены. Часто данные подаются в браузер отдельными JSON объектами, которые преобразуются активными скриптами (JavaScript, Flash, Java applet) к нужному виду.
Кеш браузера
Как правило пользовательский браузер кеширует огромное количество данных, таких как css, javascript, favicon, некоторые изображения. В результате для рендеринга очередного запроса ему достаточно получить данные из кеша, не обращаясь к удаленным серверам. В результате чего, анализируя трафик, мы не получим ряд очень важных для отображения элементов. В такой ситуации необходимо самим выполнить соответствующие запросы. К сожалению это может демаскировать оператора, поэтому решение о загрузке тех или иных данных из сети должен принимать он. Можно лишь стараться максимально упростить его выбор - что загружать, а что нет.
meta Refresh
Существует специальный тег meta с атрибутом http-equiv. Баузеры
преобразовывают значение этого атрибута, заданное с помощью
content, в формат заголовка ответа HTTP и обрабатывают их, как будто они
прибыли непосредственно от сервера. Таким образом в ситуации meta
http-equiv="Refresh"
, браузер получает правильный двухсотый ответ с
контентом, но тут же запрашивает другую страницу, которую и покажет
пользователю.
<meta http-equiv="Refresh" content="0;URL=forum/index.php">
Алгоритм построения пользовательского "трейса"
На вход подается pcap файл с трафиком за определенный период времени. Выделяются и нумеруются сессии запрос-ответ. Все тела ответов сохраняются за соответствующим номером. Все запросы выстраиваются в граф отношений на основе значений поля referer. Рассматриваем только фантомные вершины и вершины, ответом для которых был HTML (ответ на основной запрос пользователя просто обязан быть в формате HTML). Из этих вершин выделяем основные запросы по количеству запросов-referer и времени между запросами (оно должно быть не меньше определенно заданного заранее значения). Отметим, что реферером основного запроса (если он есть) может быть только основной запрос. Все оставшиеся запросы должны соответствовать какому-либо основному.
Отображение основного зарпоса со встроенными объектами
Следующей задачей является отображение отдельно взятого основного запроса вместе с его встроенными объектами так, как видел его пользователь. Задачу можно решить двумя способами.
Первый - открыть основную страницу в браузере, перехватить все сопутствующие запросы и ответить на них трафиком из анализируемого файла. Такой выше механизм реализован в приложении XPlico.. Интересно то, каким образом реализована данная функциональность. Так как приложение имеет web-интерфейс и запускается с HTTP-сервера, этот же сервер может выступать в качестве http-proxy. Пользователь, запуская браузер для приложения xplico указывает этот же адрес в качестве http-proxy. Таким образом, когда пользователь открывает сохраненную страницу, запросы браузера на загрузку встроенного содержимого направляются через xplico, что позволяет ему отвечать уже имеющимся в pcap трафиком.
Второй подход - заменить все встроенные объекты непосредственно в HTML
коде основной страницы. При решении этой задачи первое, что необходимо
сделать - создать отображение пар (запрос, ответ) из pcap файла на
ссылки, полученные из атрибута src
всех тегов и атрибута href
тега
link
. В результате разбора трафика для каждой пары (запрос, ответ)
создается контент-файл, в который записываются данные из ответа.
Подменив все ссылки на имена файлов, мы получим локальную копию
страницы.
Проблемы
- Разница в браузерах.
Пользователь может просматривать страницу в одном браузере, а оператор в другом. За счет блоков вида:
<!--[if gte ie 9]>
...
<!-->
браузер пользователя будет запрашивать блоки javascript и css,
характерные для него. В свою очередь браузер оператора не подхватит
эти куски, так как у него, возможно, срабо:тает другой if
блок,
требующий загрузки других объектов. К сожалению из-за
войны браузеров
веб-мастера все чаще используют такой подход.
Примером может служить популярный новостной портал lenta.ru. Восстановленный трафик, который был записан для Firefox-31.0, некорректно отображается в Chromium-30.
- Битый pcap.
Хорошо видно на примере семпла rbcru.pcap. При загрузке файла
http://s.rbk.ru/rbc_static/fp_v4/skin/not-so-default-pack.css?1398866344
libpcap пропустил несколько пакетов. В итоге полученный css хоть и
выглядел вполне нормальным, но не содержал описаний ключевых классов.
В результате чего страница у оператора отрендерится неверно. Для
того, чтобы получить орининал можно заменить 7.css на его полную
версию - not-so-default-pack.css.
- Фреймы.
Фреймы популярная технология, позволяющая иметь полноценный HTML документ в другом HTML документе. Представленный способ выборки пользовательских запросов будет считать фрейм таковым. В простейшем случае он встроится в страницу, полученную ранее. Достаточно лишь не считать пользовательскими документы, встроенные в другие. К сожалению мы сталкиваемся с необходимостью следить за порядком получения страниц, что может создать трудности при многопоточной обработке.
- Сложный java-script.
Как мы уже отмечали, современные web-приложения представляют собой сложные java-script приложение. браузер может подргужать из Интернета объекты, встраивая их в определенные части тела документа, в результате интерпретации каких-то функций java-script. Хорошим примером может служить заглавная страница fox.
Встраивание объектов
Необходимо, чтобы результат разбора pcap был одним файлом. Надо попытаться все встроенные объекты хранить прямо в пользовательском html. Существует несколько стандартизованных схем: RFC2397, RFC2392. Мы воспользуемся RFC2397 и заменим все соответствующие встоенным объектам URL. Данный способ является самым простым и достаточно эффективным, но при наличии "тяжелых" объектов браузер может некорректно отображать получившуюся страницу. К примеру, chromium на некоторых примерах при скроллинге стирает изображения:
Internet Explorer 8, распространяющийся в составе Windows 7 вообще не умеет работать по RFC2397, но уже Internet Explorer 11 справляется.
Встроенный документ может в свою очередь может содержать встроенные документы. Важно встраивать объекты в нужном порядке. К примеру, если С встроен в B, а B в свою очередь встроен в A, необходимо сначала C встроить в B и только потом B встроить в A. Для определения порядка встраивания необходимо сначала строить направленный граф отношений. Кроме того необходимо следить за тем, чтобы встроенные объекты не образовывали циклы. С другой стороны, наш граф имеет строго предопределенную структуру, что позволяет не углубляться в [задачу обхода ориентированного графа][grap_walk]. Мы точно знаем с какой вершины необходимо начать обход. Далее можем производить рекурсивное встраивание, лишь следя за отсутствием циклов.
Все проверенные браузеры Firefox 30.0, Chromium 35.0, Internet Explorer 11 нормально разбирают по крайней мере дважды вложенные документы. Для проверки можно попытаться открыть следующий документ:
<html>
<head>
<script type="application/javascript" src="data:application/javascript;base64,ZnVuY3Rpb24gZml4X2NvbnRlbnQoKQp7Cgl2YXIgbmFtZV9pbnB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjb250ZW50JykKCW5hbWVfaW5wdXQuaW5uZXJIVE1MID0gIjxpbWcgc3JjPSdkYXRhOmltYWdlL2dpZjtiYXNlNjQsUjBsR09EbGhNZ0FlQU1aY0FBQUFBQU1EQXdVRkJRWUdCZ2NIQndnSUNBb0tDZ3NMQ3c0T0RoQVFFQkVSRVJJU0VoTVRFeFVWRlJZV0Zod2NIQjRlSGg4Zkh5QWdJQ0VoSVNJaUlpUWtKQ2NuSnlnb0tDa3BLU29xS2l3c0xDNHVMakV4TVRJeU1qMDlQVUJBUUVSRVJFeE1URkZSVVZKU1VsTlRVMWxaV1ZwYVdseGNYRjVlWG1Sa1pHVmxaV2hvYUd4c2JHMXRiWGg0ZUlxS2lvNk9qcENRa0pLU2twaVltSm1abWFDZ29LV2xwYkt5c3JPenM3Mjl2YjYrdnNEQXdNSEJ3Y0xDd3NiR3hzakl5TXpNek03T3p0UFQwOVhWMWRmWDE5bloyZURnNE9MaTR1VGs1T1hsNWVibTV1Zm41K25wNmV2cjYrenM3TzN0N2U3dTd1L3Y3L0R3OFBIeDhmUHo4L1QwOVBYMTlmYjI5dmYzOS9uNStmdjcrLzM5L2YvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL3lINUJBRUtBSDhBTEFBQUFBQXlBQjRBQUFmK2dGeUNnNFNGaG9lSWlZcUxqSTJPajVDUmtwT1VsWmFYbUptYW01eWRucCtnbkFDakFBVVVMVStkQUl5cmdsaEVLaUNxcklWUEJvSkZKQXNJSWsyQ0FEWWNCQTRuVG9NMEVnSVZNNjFjelluTldFVXJzbHdiT2xkU0xDbS9HVGxVU1NZbGdqZ1NPMVE3RWMzUGlLU2tEMGVHVXcrL1FZTk1ESUllT0lNM3pRaTBCR1VaRWdLRklDTWpHb3dLOEdzTG9WWUtvZ3lDMHN4Q3dFRkxFZ2o2NEFLSkZpeXQyRUdVS0lnaUpIWks4bkU1UUVVUWo1Q0ZXdTBiaElQZG9tWURRM0Rqd2dHR0ZTQVlZRDRrTjZGSGxSNFQxckVpSllDQ0N5dUNnblFZQUVHRzBFSE5aa1JRRm1NQTFsQ0xmRndBcStpRUVDcy9OcndnbTZpR0JnTU9HR0E0WkV1M3J0MjdlUE95RFFRQU93PT0nLz4iCn0KCg=="></script>
</head>
<body onload="setTimeout(fix_content, 500)">
<div id="content"> tick, tick, tick </div>
</body>
</html>
Блок base64 в нем - это HTML-документ типа application/javascript следующего вида:
function fix_content()
{
var name_input = document.getElementById('content')
name_input.innerHTML = "<img src='data:image/gif;base64,R0lGODlhMgAeAMZcAAAAAAMDAwUFBQYGBgcHBwgICAoKCgsLCw4ODhAQEBERERISEhMTExUVFRYWFhwcHB4eHh8fHyAgICEhISIiIiQkJCcnJygoKCkpKSoqKiwsLC4uLjExMTIyMj09PUBAQERERExMTFFRUVJSUlNTU1lZWVpaWlxcXF5eXmRkZGVlZWhoaGxsbG1tbXh4eIqKio6OjpCQkJKSkpiYmJmZmaCgoKWlpbKysrOzs729vb6+vsDAwMHBwcLCwsbGxsjIyMzMzM7OztPT09XV1dfX19nZ2eDg4OLi4uTk5OXl5ebm5ufn5+np6evr6+zs7O3t7e7u7u/v7/Dw8PHx8fPz8/T09PX19fb29vf39/n5+fv7+/39/f///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEKAH8ALAAAAAAyAB4AAAf+gFyCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+gnACjAAUULU+dAIyrglhEKiCqrIVPBoJFJAsIIk2CADYcBA4nToM0EgIVM61czYnNWEUrslwbOldSLCm/GTlUSSYlgjgSO1Q7Ec3PiKSkD0eGUw+/QYNMDIIeOIM3zQi0BGUZEgKFICMjGowK8GsLoVYKogyC0sxCwEFLEgj64AKJFiyt2EGUKIgiJHZK8nE5QEUQj5CFWu0bhIPdomYDQ3DjwgGGFSAYYD4kN6FHlR4T1rEiJYCCCyuCgnQYAEGG0EHNZkRQFmMA1lCLfFwAq+iEECs/Nrwgm6iGBgMOGGA4ZEu3rt27ePOyDQQAOw=='/>"
}
В котором в свою очередь блок base64 представляет собой image/gif изображение:
Comments
comments powered by Disqus