Security Reverse Engineering vk.com

    Данный пост — небольшой отчет о процессе реверсивного проектирования и анализа работы самой популярной соц. сети в СНГ — vk.com. В основном анализ проводился со стороны безопасности (хотя сама соц. сеть весьма привлекательна как high-load проект, безусловно). Для себя вынес некоторые интересные решения и просто получил удовольствие. Пост получился, возможно, немного сумбурный, так углублялся просто в интересные мне моменты.

    Содержание


    Обзор

    Архитектура

    • php 5.2/5.3
    • Периоды нагрузки (отключения автоподгрузки ленты)
    • Врапперы в сообщениях
    • Разный код для мобильной и полной версий

    Security

    • Фичи
      • Авторизация
      • Anti-CSRF токены
      • Запрет iframe
      • Отключенный POST на контент-серверах
    • Фиче-баги
      • Узнать возраст через поиск
    • Баги
      • XSS
      • Загрузка документов без имени
      • Подгрузка по ajax фото из закрытых альбомов (?)
      • Не везде anti csrf

    Разное



    Обзор


    Прежде всего стоит прочесть парочку хоть и старых, но интересных статей:

    После включения firebug'a и посмотрев сайт просто со стороны веб-разработчика, сразу становится видно, что внутри некоторый бардак (к нему мы еще вернемся в конце статьи), отсутствие диспатчеров (возможно, для снижения нагрузки), разбросанные стили и js файлы и многое другое. А в целом — незамысловатое веб-приложение, использующее в нагруженных местах nodejs, а для остального «стандартные» (я бы даже сказал «заезженные») технологии разработки (исключая их нераскрытую бд. Настройку балансировщиков так же откидываю).

    Архитектура

    • php 5.2/5.3
      По ходу работы с приложением, в зависимости от того, на какой бэкенд мы попадаем, мы натыкаемся на разные версии php (5.2/5.3). Т.е. это скорее всего говорит о том, что версия php меняется скорее из-за фикса различных багов в самом интерпретаторе, чем из-за нововведений в php 5.3. Кстати, установлен suhosin
    • Периоды нагрузки (отключения автоподгрузки ленты)
      Скорее всего написан некоторый монитор, который смотрит за нагрузкой и динамично балансирует конфиги скриптов. Например, ближе к вечеру отключается автоподгрузка ленты, которая при нескольких млнов юзеров может значительно снизить нагрузку.
    • Врапперы в сообщениях
      Фича добавления разного контента в сообщениях сделана довольно примитивно, но может это и верно. При добавлении видео отправка сообщения выглядит подобным образом:
      act=a_send&al=1&chas=XXXXXXXXXXXXXX&from=box&media=video%3A-22558194_163667075&message=&title=&to_ids=6254003
      Т.е. просто указывается тип аттача (video, audio, map etc...) и внутренняя ссылка на него. Я долго копался с этим моментом, пытаясь что-нибудь туда подсунуть — не вышло.
    • Разный код для мобильной и полной версий
      Это, возможно, очевидно, но не есть гуд. Скорее всего из-за низкой абстракции кода, которая не позволяет просто взять метод и вызвать его на другом (например мобильном) интерфейсе. Тому есть подтверждения, например разные переводы (статус «не женат/не замужем» в полной версии переведен на английский как «Single», а в мобильной — «Not married». Писал на это тикет). Но это только шаблоны, есть и другие моменты, которые косвенно указывают на различный код (возможно код просто урезанно-дублированный)


    Security

    Прежде чем начать этот раздел я сделаю отсыл на пост Евгения Касперского, хотя некоторые моменты уже неактуальны — e-kaspersky.livejournal.com/70000.html
    • Фичи
      • Авторизация
        Это просто первым пунктом. Авторизация проходит по следующей схеме — action формы ведет по https на login.vk.com, там выставляет куку для себя (https://login.vk.com) и для vk.com (remixsid). Если с кукой на «рабочем» домене что-то не то (изменена, не совпал последний IP и т.п), автоматически происходит редирект на login.vk.com. И если пароль действительно вводился на этом браузере, там будет persistent-кука (которая выставилась при вводе оригинального пароля), по которой произойдет автоматический вход. Если же нет (к примеру, куки увели и зашли с другого ip) то на аккаунт не пустит. Кстати, когда нашел XSS с этим погорячился. По факту увод куков не дает ничего (конечно, если это не XSS на login.vk.com). Так же ведется запись последних активных сессий — 6 штук, который считаются «живыми»
      • Anti-CSRF токены
        Считаю (думаю, не только я) наилучшей защитой от CSRF именно этот метод. Но как они его красиво реализовали… Первый момент стандартен, на любое действие генерируется уникальный код для юзера, который невозможно предугадать. Но здесь же особенность токенов состоит в том, что они зависят от параметров действия. В данном случае у нас есть — from_id, to_id, action_id и иногда еще некоторые параметры. От всех них берется хэш (скорее всего какая-то своя быстрая 72-битная хэш-функция), скорее всего добавляется соль (статичная?) (хотя, в последнее время явным образом from_id не передается) и добавляется в форму. Т.е. на каждое действие с разными параметрами — разный токен.
      • Запрет iframe
        Собственно, сабж. Сайт нельзя отобразить в iframe, что правильно. Запретить отображение сайта в iframe можно различными способами
      • Отключенный POST на контент-серверах
        В силу разных причин это верно ограничивать сервер доступными методами. На всех контент серверах отключен POST
    • Фиче-баги
      • Узнать возраст через поиск
        Маленький трюк. Если у человека заполнен возраст, но выставлено не отображать его — то его можно узнать, если найти человека через поиск и начать подбирать возраст (фильтром). Наверное, гипер-бородатая фиче-бага.
    • Баги
      • XSS
        Наверное, все началось с того, что я захотел найти XSS, лично для себя. Она была найдена в основном модуле сайта — поиск. Вектор был таким:
        vk.com/search?c%5Bage_from%5D=alert(String.fromCharCode(88, 83, 83, 32, 101, 120, 97, 109, 112, 108, 101, 33))&c%5Bname%5D=1&c%5Bsection%5D=people


        Скрин алерта


        Исходный код

        Число для поиска возраста в чистом виде подставлялось в js-функцию параметром. Единственное ограничение, которое я здесь «словил» — это невозможность использования кавычек (они преобразовывались), что легко обходится строковыми функциями. Поправили буквально за день-два. «Баунти» программы у них нет. В ответ было мол — поправили, проверьте и всё. P.S. Сниффер успешно внедрился, но это ничего не дало, из-за первого пункта про систему авторизации.
      • Загрузка документов без имени
        Эту багу и следующую так и не хватило времени доисследовать. Но что-то и так уже статья постоянно откладывалась, так что как есть. При загрузке документов он смотрит на расширение файла и или принимает файл, или нет (ессно, я пытался загрузить htaccess и переназначить роли файлов по расширению). Возникла бага с файлом .model Скрипт его пропустил, но он всегда «404»
      • Подгрузка по ajax фото из закрытых альбомов (?)
        Создав ajax-запрос на нужный документ мы можем получить полное изображение фотографии (думаю, замечали в новостной ленте), которая закрыта настройками приватности лично для вас. Возможно, тут стоит покопать
      • Не везде anti CSRF токены
        Это действительно так. Но найденные мной места были некритичными.


    Разное
    • Не удаляются файлы, даже после удаления
      Многих пользователей так или иначе это заботит. Если прочитать статьи в начале, то можно узнать, что есть две версии по этому поводу — фрагментация данных на жестких дисках и проблема контроля целостности данных. Второй момент действительно сложен. Ту же картинку можно удалить, а она, возможно, где-то используется. Анализировать всю базу на пример использования документа весьма не просто. Но это ладно, хотлинки. А вот документы доступны только по обращению через скрипт, но и даже документы, после удаления, остаются доступными, хотя можно было бы добавить проверку. Ответ тех.саппорта был таким: «документ будет доступен по ссылке, даже если его удалить.» и всё.
    • по дефолту не включен https
      Возвращаясь к письму Касперского — прямо сейчас советую принудительно поменять свои закладки с http на https, если этого еще не сделано. Сейчас mitm настолько прост, что хватит любого android-смартфона с рутом. Устанавливается droidsheep и нажав всего пару кнопок уже получится проснифать куки вк (и не только) и автоматически с ними зайти на сайт


    Мусор


    И «по-мелочам». Базу начинают чистить. Например лимит сообщений с юзером в переписке большой, но уже подчищается. Различные другие наработки оставил мусором в блокноте.

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

    Подробнее
    Реклама
    Комментарии 54
    • +1
      Интересно насчет .DS_store, в метаданных может быть интересная информация, но в интернете ничего путного про расшифровку не нахожу
      • +5
        Хотя, простой cat справляется

        vk.com/mts_test.htm
        vk.com/debian-preseed.cfg
        vk.com/auto_login.html

        И еще куча подобного
        • 0
          а есть копия пресида-то? интересно как вконтактик сетапится :)
        • +7
          Если кому-то интересно, в .DS_Store можно найти упоминания следующих файлов:

          Вот они все
          index.html
          index.php
          infected-list.html
          infested_ip_list.html
          info.txt
          ip.html
          login.html
          login_result.html
          mobile
          mp3
          mts_test.htm
          niftyCorners.css
          niftycube.js
          nortonsw_38f4f030-e545-0.html
          oauth
          pereezd.gif
          press
          proxy
          queue
          source
          subdomain
          swf
          test.html
          test.jpg
          toolbar
          u00001
          uploader
          w3c
          admin.cs
          admin.html
          api
          auto_login.htm
          base.css
          blank.html
          crossdomain.xml
          crossdomain_userapi.xml
          css
          debian-preseed.cfg
          debian-preseed.cfg-old
          debian-preseed64.cfg
          favicon.ico
          images
          images

          Проверил некоторые — действительно можно найти в корневом разделе (http://vk.com/test.txt).
          • +1
            Интересно, сколько людей сейчас пошло добавлять .DS_Store в .gitignore.
            • +2
              Ну вообще это просто правило хорошего тона среди разработчиков, использующих OS X.
              • +1
                Откройте для себя ~/.gitignore_global. Исключительно удобно и просто.

                Включить gitignore_global: touch ~/.gitignore_global && config --global core.excludesfile ~/.gitignore_global
            • +1
              Не совсем понял насчет мусора. В каком смысле подчищается лимит?
              • 0
                Тоже не понял вашего вопроса.
                Это несвязанные пункты.
                Подчищается история сообщений. Т.е. не все сообщения сохраняются в переписке.
                • 0
                  А заметили какую-то закономерность в подчистке истории сообщений? Неужели реальные, неспамные сообщения удаляют? Как-то похоже, что экономят на спичках.
                  • 0
                    Не знаю, не знаю.
                    Думаю речь идет о млрдах ключей. Так что далеко не спички.
                    Особо не исследовал этот вопрос, можно посмотреть.
                    Просто решил отмотать по максимуму переписку с одним из контактов — сообщения, которые были отправлены более 2х назад уже недоступны.
                    • 0
                      Попробовал поискать — доступны сообщения за декабрь 2008.
                      При чем, это действительно первые сообщения, отправленные человеку.
                    • 0
                      Вот сегодня читал старую переписку свою года 2008 части сообщений тупо нет, так что да подтверждаю база чистится причём сообщения пропали рандомно, то с моей стороны то со стороны собеседника.
                      • 0
                        Похоже что старые сообщение просто исключаются из бэкапа/дублирования, и в случае падения сервера происходит автоматическая «чистка».
                    • +2
                      Мои сообщения удаляют? То есть буквально, я открою историю, и за какой-нибудь 2009 год у меня может не оказаться сообщений?
                  • +1
                    То, что фото и документы доступны по прямой ссылке после удаления — это огромная проблема.
                    • +1
                      А где же рассказ про баг с репостом предложенных новостей?
                      Ну тогда я расскажу.
                      • +7
                        Время для редактирования закончилось…
                        Идём в сообщество/паблик/etc
                        Нажимаем предложить новость.
                        Заливаем картинку, например, демотиватор.
                        Отправляем предложенную новость.
                        Перезагружаем страницу сообщества, снова «Предложить новость»
                        Видим предложенную новость.
                        Кликаем на время отправки.
                        Лайкаем залитый демотиватор и делимся с друзьями.
                        Оп. У нас на стене есть демотиватор от имени сообщества.
                    • +1
                      Сейчас VK стал уже более-менее адекватным по отношению к безопасности и приватности данных, а вот пару лет назад с помощью нехитрой связки m.vk.com + VK API + user api можно было выдрать на порядок больше информации, чем человек (как он полагал) позволил узнать с сайта
                      • +6
                        Был даже легализованный вариант — durov.com
                      • 0
                        Неужто так и не нашли, как залить анимированную гифку?
                        • 0
                          Я только залил png'шку с php кодом внутри :)
                          Сейчас, вроде, любое изображение 100% пересохраняется, что не дает загрузить подобное изображение, нет?
                          • 0
                            Ну вроде как да.
                            Тем не менее анимогифки время от времени всплывают.
                            Может, надо заливать картинки через API, в качестве аватарки или ещё как-нибудь?

                            • 0
                              Честно говоря не ставил перед собой подобной задачи, постараюсь посмотреть.
                              Но все те гифки, которые были загружены до этого, сейчас удалены. И новых я не видел.
                              Предыдущий баг был жив всего несколько часов и год-два назад, насколько я знаю.
                              • 0
                                Всё просто… Через документы заливают.
                                • 0
                                  И они живой анимацией прямо на странице проигрываются? :) Что-то не видел)
                                  Сейчас, конечно, проверю
                                  • 0
                                    прикреплённый аттачем документ открывается в отдельной вкладке.
                                    а в ленту вставляется превьюха, которая, естественно, генерится.
                                    • 0
                                      может, можно как-то перенести документ в категорию фоток?
                                      • 0
                                        Я сейчас попробовал на моменте отправки сообщения с изображением подсунуть гифку из документов вместо обычной фотки — не выйдет (не вышло), формат отправляемых данных разный.
                                        • 0
                                          вот так не проходит:
                                          {
                                          act:post
                                          al:1
                                          attach1: ид_документа
                                          attach1_type:photo
                                          }

                                          ?
                                          • 0
                                            Раньше можно было залить gif-ку переименовав ее, а сейчас все, закрыли данную возможность. Интересно, чем опасен в плане безопасности анимированный gif (ну кроме раздражения пользователей фактом анимации)
                                            • +2
                                              Думаю, ограничение существует как раз таки из эстетических соображений.
                              • +2
                                >> Узнать возраст через поиск

                                Вот зачем рассказали, прикроют же (: (сам пользовался иногда)
                                • 0
                                  POST к статике по умолчанию закрыт nginx'ом, так что это не заслуга вконтакте ;)
                                  • 0
                                    А чем, кстати, плох POST к статике?
                                    • 0
                                      возможно тем, что веб-серверу нужно вычитать от клиента тело запроса, которое потом все-равно придется выбросить.
                                  • 0
                                    BeLove, «две очень похожих статьи» в начале раздела Обзор являются одной и той же статьей. Первая версия на Insight IT была оригиналом, а вторая является её адаптацией для печати на бумаге в журнале Хакер.
                                    • +1
                                      1. Anti-CSRF токены
                                      «Но как они его красиво реализовали» это сарказм? токен никак не должен зависить от параметров которые легко может узнать сам хакер — фром айди и ту айди… токен простой рандом хеш, без выпендрежа

                                      2. Собственно, сабж. Сайт нельзя отобразить в iframe, что правильно. Запретить отображение сайта в iframe можно различными способами
                                      что правда? x-frame-options не передается и vk.com и m.vk.com преспокойно фреймится и кликджекится homakov.blogspot.hk/2012/06/saferweb-with-new-features-come-new.html

                                      3. Поправили буквально за день-два. «Баунти» программы у них нет. В ответ было мол — поправили, проверьте и всё. P.S. Сниффер успешно внедрился, но это ничего не дало, из-за первого пункта про систему авторизации
                                      такой XSS это просто *здеццц. насчет баунти — я тоже находил серьезный баг в oauth, за куда меньший баг фб мне 2к дали habrahabr.ru/post/150756/

                                      вк огромная свалка не компилированного не минифицированого vanilla js кода. гребаный стыд
                                      статья хорошая +1
                                      • 0
                                        токен никак не должен зависить от параметров которые легко может узнать сам хакер — фром айди и ту айди… токен простой рандом хеш, без выпендрежа

                                        Рандом хэш ведь придется запоминать на стороне сервера?
                                        С их вариантом на сервере ничего запоминать не надо и можно получив токен проверить его на валидность, а что хакер знает параметры не страшно (их же и так из параметров формы можно взять), если он не узнает соль.
                                        • 0
                                          signed cookie, ничего запоминать не надо. идеальное решение, сделано в рельсах например
                                          • 0
                                            И еще у рандомного хэша минус, что форму с ним нельзя закэшировать и при выводе формы надо каждый раз тратить ресурсы на его рассчет, а их токен можно. По идее их токен это просто подпись формы, не вижу тут минусов, хакер может ее узнать только войдя в аккаунт жертвы.
                                            • 0
                                              ненужно ничего каждый раз гененрировать. 1 раз генерация при первом заходе на ресурс, сохраняется в сессии, сессия хранится прямо в куки подписана(прочесть и изменить ее нельзя)
                                              при каждом запросе сессия шлется вместе ст океном на сервер и токен из запроса сверяется с токеном из сессии. кешировать все можно. даже для устаревших токенов если вы удалили сессию я делал патч для jquery_ujs для синхронизации
                                              • 0
                                                И в чем тогда скрытый смысл рандомности токена, если он не меняется всю сессию?
                                                Получается то же самое, что и у них – токен для формы будет неизменным (сессия может длиться и неделями и месяцами).
                                                Никак не пойму где вы видите уязвимость в их варианте, с которой справится рандомный токен.
                                                • 0
                                                  зачем ему меняться? если нет XSS то из куки его не вытащить а если есть то это другой уровень проблемы
                                                  я изначально сказал что решение НЕ красивое. Зачем писать gen_hash(form_id + to_id etc + salt) когда можно просто 1 раз сгенерить random строку. защита от CSRF и роуты написана не профессионалом и это очевидно — как заметил ТС не везде есть защита и более того GET иногда используется для state changing действий
                                                  • 0
                                                    > я изначально сказал что решение НЕ красивое. Зачем писать gen_hash(form_id + to_id etc + salt) когда можно просто 1 раз сгенерить random строку.

                                                    Дело вкуса, мне их вариант нравится больше, чем рандомный токен.
                                                    Они своим токеном подписывают параметры формы и значит можно проверить, что параметры формы не менялись, чего рандомный токен не даст. Наверное это помогает бороться со спамботами.
                                        • 0
                                          Про анти-CSRF токены я сказал без сарказма. Пару аргументов:
                                          1) Использовать сессии — хранить лишние данные для млнов юзеров или не хранить? Выбор — не хранить
                                          2) Куки — вообще, смотря как реализовать. Вообще, это плохой стиль, писать ненужную инфу для юзера ему в куку. И в зависимости от реализации может возникнуть проблема при работе с множеством вкладок заканчивая совершенно другими
                                          3) Ну и третий, самый главный. Подобные токены полностью решают проблему Parameter Tampering. Подмена параметров невозможна, каждое действие подписано.
                                          • +1
                                            1) зачем хранить? signed cookie
                                            2) это не не нужная инфа и не плохой стиль. это stateless стиль, зачем нагружать сервер когда клиент может взять на себя то что подписано
                                            3) да, такая же идея всплыла у яхуды катза после mass assi… кароче не для всех сервисов это нормально. как будете ajax запросы подписывать, когда неизвестно какие параметры придут?
                                        • –1
                                          Ха! интересно что можно выловить, используя уязвимостьPHP к неизвестным HTTP методам, и соответсвенно обходу .htaccess. HTExploit надо из дома натравить.
                                          • 0
                                            Я чуть что чуть более чем ничего.
                                            Было бы странно, если бы сервера VK работали на апаче с mod_php

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.