flawopen.com/Teardowns/CVE-2024-32002

CVE-2024-32002: Git Submodule Symlink RCE

Critical 9.8 CWE-78 / CWE-59 Git < 2.45.1
Languages: en pt-br es fr de ru zh-cn ja hi ko id
ELI5 — Обманчивая табличка в офисе

Представьте курьера, доставляющего посылку в «Кабинет 101». Злоумышленник вешает на дверь табличку: «Кабинет 101 перенесен в сейф руководства». Не проверяя подлинность указателя, курьер идет по стрелке и оставляет посылку прямо в сейфе. В Git курьером был процесс клонирования подмодулей, табличкой — символическая ссылка, а сейфом — скрытая папка .git/hooks/, скрипты из которой автоматически запускаются операционной системой.

Target: Git core CLI
Vector: git clone --recursive <url>
Impact: Remote Code Execution (RCE)
Platform: macOS & Windows (Case-Insensitive Filesystems)

Критический диф в исходном коде Git

В builtin/submodule--helper.c и dir.c Git создавал рабочую директорию подмодуля, не проверяя, является ли какой-либо из промежуточных каталогов симлинком.

builtin/submodule--helper.c (Vulnerable)Vulnerable
// Git clone created submodule directory blindly
static int clone_submodule(const struct module_clone_data *clone_data)
{
    struct strbuf sb = STRBUF_INIT;

    // BUG: clone_data->path could traverse an existing symlink
    strbuf_addf(&sb, "%s", clone_data->path);
    safe_create_leading_directories(sb.buf);
    return do_clone(clone_data);
}
builtin/submodule--helper.c (Fixed)Patched
// Fixed: Refuse to clone into or through symlinked path components
static int clone_submodule(const struct module_clone_data *clone_data)
{
    struct strbuf sb = STRBUF_INIT;

    // FIX: Validate that no parent component is a symlink
    if (path_has_symlinks(clone_data->path))
        die(_("fatal: submodule path '%s' contains a symlink"),
            clone_data->path);

    strbuf_addf(&sb, "%s", clone_data->path);
    return do_clone(clone_data);
}

Схема атаки в 3 шага

Уроки безопасности для разработчиков

Explore more vulnerability mechanisms & language matrices: Command Injection Matrix →