Выполнение произвольного кода в клиенте Git

git уязвимость

Думаю, вам не нужно рассказывать, что такое git, — он сегодня используется всеми от небольших компаний до гигантов индустрии. Найденная в нем уязвимость позволяет злоумышленнику атаковать пользователей, которые клонировали специально сформированный репозиторий. Об этой уязвимость в Git я и расскажу в сегодняшней статье.

Обнаруженные уязвимости получили идентификаторы CVE-2018-11233 и CVE-2018-11235. Они присутствуют в следующих версиях git:

  • все версии ниже 2.17.1;
  • все версии ниже 2.16.4;
  • все версии ниже 2.14.4;
  • все версии ниже 2.15.2;
  • все версии ниже 2.13.7
  • и другие, более ранние версии.

Большой интерес представляет баг CVE-2018-11235, который был обнаружен исследователем Этьеном Сталмансом (Etienne Stalmans). Эксплуатация именно этой уязвимости приводит к самым плохим последствиям — выполнению произвольного кода на машине жертвы. Проблема была найдена в рамках программы охоты за ошибками GitHub и затрагивает функции обработки имени подмодуля.

Дыра оказалась платформонезависимой и прекрасно существует во всех основных популярных операционных системах — Windows, macOS и Linux. Список уязвимых веток приложения обширен, к тому же под угрозой оказались и программы, в которые включена версия Git «из коробки». В основном это разные IDE, такие как Visual Studio и Xcode.

РЕКОМЕНДУЕМ: Лучшие клиенты Git GUI для Windows

Стенд

Думаю, описание установки git на свою машину будет лишней тратой экранного места. Выбирайте удобную вам платформу и скачивайте дистрибутив. Проследите только, чтобы номер версии входил в число уязвимых. Я ради разнообразия буду использовать git для Windows.

git уязвимость
Уязвимая к CVE-2018-11235 версия git

Что такое «подмодули»?

Во время разработки постоянно возникает необходимость задействовать в своем проекте еще какой-то проект. Например, дополнительную библиотеку, которая независимо используется в нескольких других проектах. Чтобы не плодить копии этой библиотеки и всегда иметь простую возможность обновить ее до последней версии, в git существует понятие подмодуля (submodule). Подмодули позволяют содержать один git-репозиторий как подкаталог другого. Это дает возможность клонировать еще один репозиторий внутрь проекта, при этом в него по-прежнему можно коммитить отдельно.

Посмотрим, как это сделать. Для начала создадим пустой репозиторий.

Допустим, теперь мы хотим использовать в этом проекте крутой словарь для дирбаста. Загрузим его в качестве подмодуля:

где fuzz — это название папки, куда будет помещен репозиторий. Теперь, если заглянуть в git status, мы увидим, что появился новый файл .gitmodules.

Этот конфигурационный файл задает соответствие локального пути внутри проекта с адресом репозитория.

git уязвимость
Добавление подмодуля в репозиторий

Обрати внимание на заголовок файла: в кавычках указывается название подмодуля, оно аналогично названию папки, в которую мы его клонировали. Разумеется, репозиторий может содержать сколько угодно подмодулей, для каждого будет создана отдельная запись в .gitmodules.

Сам файл находится под версионным контролем вместе с другими твоими файлами. Он отправляется при выполнении push и загружается при выполнении pull вместе с остальными файлами проекта.

Однако, кроме появления .gitmodules, в структуре проекта были сделаны и другие изменения. Как ты знаешь, в корне репозитория в папке .git хранятся служебные файлы. Там можно обнаружить директорию modules с подпапкой fuzz. А в ней уже хранится такой же служебный каталог .git, только от нашего подмодуля. В самой папке подмодуля находится файл .git, в котором указано, по какому пути искать служебную директорию.

git уязвимость
Добавление подмодуля в репозиторий

Пора закоммитить внесенные изменения.

Теперь попробуем клонировать наш свежесобранный репозиторий с подмодулем.

Заглядываем в папку fuzz и… не видим там ничего.

git уязвимость
Попытка клонирования репозитория с подмодулем

Дело в том, что для автоматической загрузки подмодулей во время клонирования нужно использовать ключ --recurse-submodules или просто --recursive.

Теперь все в порядке и можно переходить к деталям уязвимости.

Детали уязвимости

Сначала заглянем в коммит, который патчит уязвимость.

git уязвимость
Коммит с патчем уязвимости CVE-2018-11235

В файл submodule-config.c была добавлена функция check_submodule_name для проверки имени подмодуля.

submodule-config.c

Она вызывается во время работы скрипта git-submodule.sh, чтобы обработать название, переданное в виде аргументов командной строки.

git-submodule.sh

/builtin/submodule—helper.c

Также check_submodule_name вызывается в функции name_and_item_from_var, которая занимается обработкой имени подмодуля из конфигурационного файла.

submodule-config.c

Теперь вернемся к созданию подмодулей. Как ты помнишь, его название в секции [submodule] было таким же, как и название папки, где он хранится. Но это только до тех пор, пока мы вручную не укажем его название с помощью ключа --name.

Теперь заглянем в .gitmodules.

А теперь кое-что поинтереснее. Глянем листинг директории .git/modules.

git уязвимость
Листинг директории .git/modules после использования кастомного имени подмодуля

Путь, по которому располагаются файлы подмодуля, остался тем же, а вот служебная папка теперь имеет название, которое мы указали в параметре name.
Отталкиваясь от добавленных проверок в теле пропатченной функции check_submodule_name, рискнем предположить, что тут имеет место уязвимость path traversal. Проверим это умозаключение, указав в качестве названия подмодуля ../test.

git уязвимость
Path traversal в имени подмодуля

Да, уязвимость присутствует, и папка со служебными файлами подмодуля теперь находится не в поддиректории modules, а в .git нашего репозитория. Теперь, манипулируя параметром name, мы можем менять местоположение служебной папки подмодуля. Что же это нам может дать, кроме возможности перезаписать какие-то данные?

Хуки в git

Git предоставляет возможность запускать пользовательские скрипты при выполнении определенных важных действий с репозиторием. В инфраструктуре git это называется хуками (git hooks). Существует два вида хуков: на стороне клиента и на стороне сервера. Клиентские хуки инициируются такими операциями, как commit и merge, в то время как серверные обработчики выполняются при сетевых взаимодействиях, например получении запушенных коммитов.

Все хуки хранятся в поддиректории hooks каталога .git. Когда ты инициализируешь новый репозиторий с помощью git init, каталог с хуками содержит вязанку скриптов-примеров c расширением .sample. По сути, хуки — это простые шелл-скрипты со специальными названиями, соответствующими операциям. Например, pre-commit.

habrahabr git уязвимость
Примеры файлов с хуками

Так как хуки находятся непосредственно в служебной папке .git, то, разумеется, они никогда не включаются в репозиторий, не являются его частью и не передаются при клонировании с помощью git clone. Это логичная практика: если бы хуки были частью репозитория, то можно было бы просто создать репозиторий, после клонирования которого у клиента выполнялся бы произвольный код.

Подмодули — это обычные внешние репозитории, а значит, они тоже содержат хуки, которые по умолчанию располагаются в папке .git/modules/<имя_подмодуля>/hooks. Но ведь у нас есть path traversal!

Тернистый путь к RCE

C помощью найденной уязвимости мы можем служебную папку подмодуля превратить в часть репозитория, и она будет вместе с ним путешествовать во время работы и при последующем клонировании.

После выполнения такой команды в корне репозитория, помимо директории самого подмодуля, появляется его служебная папка. Теперь можно добавлять хуки в fuzz.git/hooks.

Выполнение произвольного кода в клиенте Git
Переносим служебную папку .git подмодуля в корень репозитория

Создадим хук post-checkout, который будет выполняться после команды checkout, в том числе и после клонирования репозитория.

Выполнение произвольного кода в клиенте Git
Коммитим кастомный хук в репозиторий

И этого для машин на Windows достаточно. Если теперь клонировать созданный репозиторий, мы увидим результат выполнения команды uname -a. Это работает как при клонировании с git clone subvh subtest --recursive, так и через git submodule update --init.

Выполнение произвольного кода в Git
Выполнение произвольного кода в версии git для Windows

А вот на системах с Linux такой фокус не пройдет. При попытке клонировать репозиторий на этапе загрузки подмодулей будет выдана ошибка: папка для служебных файлов подмодуля уже существует.

Выполнение произвольного кода в Git
Неудача при попытке эксплуатации git под Debian

К тому же во время клонирования вся директория будет перезаписана, и наш хук не отработает.

Выполнение произвольного кода в Git
Перезапись содержимого служебной директории подмодуля

Но Этьен нашел способ избежать этого. Байпас оказался простым, но не самым очевидным. Помог счастливый случай! Нужно лишь добавить еще один подмодуль, причем с таким названием, чтобы оно было первым при сортировке в алфавитном порядке. В нашем случае это может быть, например, ааа.

Подойдет любой подмодуль. Главное тут — название. Когда в папке .git/modules уже существует какой-нибудь подмодуль, git считает любой путь валидным при последующей инициализации других подмодулей, и перезапись директории не происходит. Это отличная новость, так как теперь наш хук прекрасно себя чувствует и выполняется.

Выполнение произвольного кода в Git
Успешная эксплуатация git на Linux

Выводы

Вот такая интересная, изящная и очень опасная уязвимость существовала во всеми любимом клиенте git. Еще одно доказательство того, что популярность продукта совсем не означает отсутствия в нем уязвимостей. Даже если исследователи засмотрели что-то до дыр, у тебя всегда есть шанс найти что-то новое и утереть им нос.

Кстати, на момент написания статьи GitHub запретил пушить репозитории, в которых есть модули, содержащие названия хуков. Заботятся о нашей безопасности!

Понравилась статья? Поделиться с друзьями:
Добавить комментарий