3 September 2013

Изучаем deep packet inspection у RETN

IT InfrastructureNetwork technologies
Новость: Магистральный провайдер RETN, не смотря на то, что он магистральный, осуществляет фильтрацию трафика посредством DPI. Поскольку оператор он магистральный, и, в частности, занимается доставкой зарубежного трафика, то на выходе мы имеем цензуру для многих провайдеров, в том числе и тех, кто чхать хотел на всякие «запретные списки», но имеют RETN в аплинках.

DPI — совокупное название технологий, при которых оборудование «залезает» во внутрь трафика, то есть реагирует не только на заголовки пакетов разного уровня, но и на содержимое.

Во избежание помех тест проводился из нескольких городов и с нескольких провайдеров, что позволило исключить фактор локальных провайдерских фильтраций (второй, косвенный тест основывался на использовании TTL-сканирования, который всегда указывал на район RETN'а).

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

За основу возьмём широко известный журнал Стервозинки (широко известен он только тем, что был заблокирован, заблокирован за какуют-то нелепицу, причём заблокирован давно, и из бана выползать не собирается).

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

Посмотрим на бытовые симптомы проблемы:

wget -d --tries 1 stervozzinka.dreamwidth.og/15580.html

Рядом на консоли запускаем tcpdump host stervozzinka.dreamwidth.og

17:17:14.376828 IP local.49510 > dreamwidth.og.http: Flags [P.], seq 1:136, ack 1, win 115, options [nop,nop,TS val 11199749 ecr 1627034663], length 135
17:17:17.924801 IP local.49510 > dreamwidth.og.http: Flags [P.], seq 1:136, ack 1, win 115, options [nop,nop,TS val 11200636 ecr 1627034663], length 135
17:17:18.068805 IP local.49509 > dreamwidth.og.http: Flags [P.], seq 1:136, ack 2, win 115, options [nop,nop,TS val 11200672 ecr 1627029045], length 135


Одинаковый seq — признак перепосыла сегмента. Но понять, где блокируют (на получении ответа или на отправке запроса) мы не можем. Но точно видим, что таки блокируют, ибо просто так TCP-сегменты не перепосылают.

Переключимся со своевольного wget'а на что-то попроще, чтобы точно контролировать отправляемое:

echo -e "GET /15580.html HTTP/1.1\nHost: stervozzinka.dreamwidth.og\n"|nc stervozzinka.dreamwidth.og 80
Это нас никак не продвинет, однако даст некоторую свободу экспериментировать с заголовками. Указанный запрос так же блокируется.

А вот для вариаций (которые нарушение RFC, но varnish'ем со стороны dreamwidth обрабатываются нормально) мы можем увидеть некоторые особенности:

  • GET /15580.html HTTP/1.1\nHost: stervozzinka.dreamwidth.og\n" (два пробела после GET) — пускает
  • GET /15580.html HTTP/1.1\nHost: stervozzinka.dreamwidth.og\n (два пробела перед HTTP/1.1 — не пускает
  • get /15580.html HTTP/1.1\nHost: stervozzinka.dreamwidth.og\n (get маленькими буквами) — пускает
  • GET /15580.html HTTP/1.1\nIgnore:me\nHost: stervozzinka.dreamwidth.og\n (лишний заголовок между GET и HOST) — не пускает


Предварительный вывод — скучный и примитивный exact matching. Если так, то как оно понимает, что из содержимого пакета заголовок, а что нет?

Так что…

echo -e "GET /15580.html\n\nHost: stervozzinka.dreamwidth.og\n"|nc stervozzinka.dreamwidth.og 80 — не пускает.

Для тех, кто не понял — я поставил два перевод строки после GET, то есть Host уже относится к телу, а не к заголовку. А ещё я убрал HTTP/1.1, то есть это plain HTTP 1.0, у которого не бывает заголовка Host, то есть мы запросили /15580.html с сервера без указания на hostname.

Заметим, запрос без hostname работает: GET /15580.html \n\n

Другими словами, мы видим, что DPI проверяет что-то совсем несусветное — наличие Host в BODY. В результате дропаются запросы, к блокируемому сайту не имеющие никакого отношения.

Усложним эксперимент:
echo -e «POST /\n\nА ты знаешь, что они банят по содержимому? Например: GET /15580.html \n\nHost: stervozzinka.dreamwidth.og\n"|nc stervozzinka.dreamwidth.og 80

Ой, ой, ой. Нам забанили отправку POST'а с невинным содержанием. Этот POST не дошёл до сервера. Не может быть?

Давайте проверим, и отправим пост более культурными методами:

curl -d "GET /15580.html \n\nHost: stervozzinka.dreamwidth.og\n" dreamwidth.og

Наше предположение — фильт требует наличия обоих строчек в одном пакете и не проверяет его валидность:

curl --connect-timeout 10 -d "GET /15580.html\n`seq 1 10000`\nHost: stervozzinka.dreamwidth.og\n" 69.174.244.50

Проходит. Это означает, что пакете должны быть оба заголовка. (да-да, если мы напишем такой запрос на сервер, у которого Host: в заголовке пойдёт другим пакетом, то, возможно, мы сможем пробить цензуру.

Ещё одна проверка: проверяют ли люди номер порта?
echo -e "GET /\nHost: stervozzinka.dreamwidth.og\n"|nc dreamwidth.og 443
(пустой ответ)

echo -e "GET /15580.html\nHost: stervozzinka.dreamwidth.og\n"|nc dreamwidth.og 443
(таймаут)

Нет. Трафик на 443ий порт фильтруют с тем же успехом (пропускают обычный, дропают „запрещённый“).

Ещё одна проверка: фильтруют ли по IP? Находим соседний (из того ж сегмента) открытый IP, отвечающий на 80ом порту. Пускают.

Итог



Условия для дропа пакета:
  • На любом порту TCP (UDP не проверялось)
  • С любыми флагами
  • По фактическому наличию в пакете (в любом порядке) строк
    • GET /15580.html
    • Host: stervozzinka.dreamwidth.og
  • Совпадению src_IP с указанным в списке для запрета


Таким образом, это больше напоминает packet filter с поиском сигнатур без регэкспов в проходящих пакетах, а вовсе не не настоящий DPI.
Tags:цензураDPIзакон об интернетеогораживаниевеликий русский файрволгосударственная дуратоталитаризмRETN
Hubs: IT Infrastructure Network technologies
+80
40.8k 128
Comments 57
Top of the last 24 hours