Как я взломал Гитхаб еще раз

от автора

Это история о том как я соединил 5 Low-severity багов в один большой баг, с помощью которого можно было читать/писать в приватные репы на Гитхабе (опять).

Несколько дней назад гитхаб запустил баунти программу. За 4 часа я смастерил такой URL после посещения которого я получал доступ к вашему гитхаб аккаунту и репозиториям. Хотите узнать как?

Баг 1. Обход валидации redirect_uri с /../
Это просто, можно отослать /path1/../path2 чтобы перезаписать предыдущий путь (path traversal).

Баг 2. Нет валидации redirect_uri при получении токена.
Первый баг сам по себе ничего не стоит. В OAuth2 встроена защита, что для каждого выпущеного кода есть соответствующий редирект_ури, и при обмене кода на токен необходимо дать тот же ури что был использован вначале. Попросту говоря если вернулся код на site/callback то и для получения токена надо отослать site/callback.

Как ни странно гитхаб реализовали проверку не правильно. Можно было выпустить код для /path1/../path2 и потом использовать его на /path1. То есть утекший через рефереры код оставался валидным даже для настоящего колбэка. С помощью этих двух багов можно было бы сливать коды на сайтах с функцией логина через Гитхаб. Похожий баг был в vk.com.

Баг 3. Картинки на гисте.
image
Я начал смотреть официальные клиенты гитхаба — Education, Pages, Speakerdeck, Gist. Первые два не пользовались OAuth по сути, третий не входил в bounty программу, а вот гист очень даже подходил. Он был «пре одобренным» клиентом, то есть по умолчанию установлен у всех пользователей.
Но нельзя просто вставить так как Camo-прокси гитхаба заменит это на локальный урл, и реферер не утечет на ваш сервер. Чтобы обойти эту защиту я использовал довольно новый трюк

///host.com парсится как путь всеми серверными библиотеками включая руби, но браузеры же парсят это как хост и загружают host.com вместо github.com///host.com

Наш урл-эксплоит выглядит сейчас так:

https://github.com/login/oauth/authorize?client_id=7e0a3cd836d3e544dbd9&redirect_uri=https%3A%2F%2Fgist.github.com%2Fauth%2Fgithub%2Fcallback/../../../homakov/8820324&response_type=code
image
Как только юзер загружает это адрес гитхаб автоматически редиректит на гист:
Location: gist.github.com/auth/github/callback/../../../homakov/8820324?code=CODE

Браузер загружает gist.github.com/homakov/8820324?code=CODE

И тут при запросе на нашу картинку он сливает реферер.

Как только мы получаем CODE жертвы мы можем открыть gist.github.com/auth/github/callback?code=CODE — вуаля. Мы залогинены как жертва на гисте и имеем доступ к его приватным гистам.

Баг 4. Токен хранится в куках
image
Это антипаттерн OAuth, крайне не рекомендуется хранить/показывать токен браузеру, гист же хранит его в рельс сессии. Которая как мы знаем просто base64 закодированная и подписанная кука.

Но токен имеет scope = gists и кроме гистов я ничего не могу прочесть.
Damn it, the token’s scope is just «gists», apparently…

Баг 5. Автоматическое одобрение любого scope для официальных клиентов.
Последний штрих. Так как гист официальный клиент гитхаба то вы не видите диалога «Одобрить это» и гитхаб делает это за вас автоматически. А значит я могу просто послать

github.com/login/oauth/authorize?client_id=7e0a3cd836d3e544dbd9&redirect_uri=https%3A%2F%2Fgist.github.com%2Fauth%2Fgithub%2Fcallback/../../../homakov/8820324&response_type=code&scope=repo,gists,user,delete_repo,notifications

Затем использовать слитый КОД для логина в аккаунт жертвы, прочитаю куку, возьму оттуда github_token и могу совершать API вызовы совершенно незаметно для пользователя — ведь токен принадлежит Гисту! Стелс-мод такой.

Награда составила $4000.
image

ссылка на оригинал статьи http://habrahabr.ru/post/211845/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *