Esta resposta é um derivado de um artigo original da original na Revista Fedora . Matthew Miller, licenciado sob a licença Creative Commons Attribution-Share Alike 4.0 .
Deixe-me explicar:
env x='() { :;}; echo OOPS' bash -c :
Isso imprimirá "OOPS" em um sistema vulnerável, mas sairá silenciosamente se o bash tiver sido corrigido.
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
Isso imprimirá "OOPS" em um sistema vulnerável, mas imprime “this is a test”
se o bash tiver sido corrigido.
E você provavelmente já ouviu falar que tem algo a ver com variáveis de ambiente. Mas, por que o código nas variáveis de ambiente é executado? Bem, não é para ser - mas, por causa de um recurso que sou tentado a chamar um pouco inteligente demais para o seu próprio bem, há espaço para uma falha. Bash é o que você vê como um prompt de terminal, mas também é uma linguagem de script e tem a capacidade de definir funções. Você faz isso assim:
$ Ubuntu() { echo "Ubuntu is awesome."; }
e então você tem um novo comando. Lembre-se de que o echo
aqui não é executado ainda; é apenas salvo como o que acontecerá quando executarmos nosso novo comando. Isso será importante em um minuto!
$ Ubuntu
Ubuntu is awesome.
Útil! Mas, digamos, por algum motivo, precisamos executar uma nova instância do bash, como um subprocesso, e queremos executar meu novo comando incrível sob esse ponto. A instrução bash -c somecommand
faz exatamente isso: executa o comando especificado em um novo shell:
$ bash -c Ubuntu
bash: Ubuntu: command not found
Ooh. Triste. A criança não herdou a definição da função. Mas, inerente ao ambiente - uma coleção de pares de valores-chave que foram exportados do shell. (Este é um conceito todo "nuther"; se você não estiver familiarizado com isso, confie em mim agora.) E, ao que parece, o bash também pode exportar funções. Então:
$ export -f Ubuntu
$ bash -c Ubuntu
Ubuntu is awesome.
O que é bom e bom - exceto que o mecanismo pelo qual isso é realizado é sorta desertor . Basicamente, como não há magia Linux / Unix para fazer funções em variáveis de ambiente, a função de exportação apenas cria uma variável de ambiente regular contendo a definição da função. Então, quando o segundo shell lê o ambiente de “entrada” e encontra uma variável com conteúdo semelhante a uma função, ela é avaliada.
Em teoria, isso é perfeitamente seguro , porque, lembre-se, a definição de uma função não é realmente executada . Exceto - e é por isso que estamos aqui - houve um erro no código em que a avaliação não foi interrompida quando o fim da definição da função foi atingido. Ele simplesmente continua.
Isso nunca aconteceria quando a função armazenada em uma variável de ambiente fosse feita legitimamente, com export -f
. Mas por que ser legítimo? Um invasor pode inventar qualquer variável de ambiente antiga, e se parecer com uma função, novos shells de bash vão pensar que é!
Então, no nosso primeiro exemplo:
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
O comando env
executa um comando com um determinado conjunto de variáveis. Nesse caso, estamos definindo x
como algo que parece uma função. A função é apenas um único :
, que na verdade é um comando simples que é definido como não fazer nada. Mas, depois do semi-colon
que sinaliza o fim da definição da função, há um comando echo
. Isso não deveria estar lá, mas não há nada que nos impeça de fazer isso.
Então, o comando dado para rodar com este novo ambiente é um novo bash shell, novamente com um comando " echo this is a test
" ou "do nothing :
", após o qual ele será finalizado, completamente inofensivo.
Mas - opa! Quando esse novo shell é inicializado e lê o ambiente, ele chega à variável x
e, como se parece com uma função, ela é avaliada. A definição da função é inofensivamente carregada - e então nossa carga maliciosa é acionada também. Então, se você executar o código acima em um sistema vulnerável, você receberá “OOPS”
de volta para você. Ou, um invasor poderia fazer muito pior do que apenas imprimir coisas.