Compreendendo a vulnerabilidade de Shellshock

Quase uma semana atrás, um novo ( antigo ) tipo de comando do sistema operacional Injection foi relatado. O CWE (Common Weakness Enumeration) descreve esse tipo de vulnerabilidade como:

> (...) The software constructs all or part of an OS command using externally-influenced
> input from an upstream component, but it does not neutralize or incorrectly neutralizes
> special elements that could modify the intended OS command when it is sent to a downstream
> component.

A vulnerabilidade Shellshock , também conhecida como CVE-2014-6271 , permite que os invasores injetem seu próprio código no Bash usando variáveis ​​de ambiente especialmente criadas , e foi divulgada com a seguinte descrição:

> Bash supports exporting not just shell variables, but also shell
> functions to other bash instances, via the process environment to
> (indirect) child processes. Current bash versions use an environment
> variable named by the function name, and a function definition
> starting with “() {” in the variable value to propagate function
> definitions through the environment. The vulnerability occurs because
> bash does not stop after processing the function definition; it
> continues to parse and execute shell commands following the function
> definition.
> For example, an environment variable setting of
>
> VAR=() { ignored; }; /bin/id
>
> will execute /bin/id when the environment is imported into the bash
> process. (The process is in a slightly undefined state at this point.
> The PATH variable may not have been set up yet, and bash could crash
> after executing /bin/id, but the damage has already happened at this
> point.)
>
> The fact that an environment variable with an arbitrary name can be
> used as a carrier for a malicious function definition containing
> trailing commands makes this vulnerability particularly severe; it
> enables network-based exploitation.

Ainda mais assustador, o banco de dados de vulnerabilidade do NIST classificou essa vulnerabilidade como “10 em 10” em termos de gravidade . Neste ponto, há pessoas afirmando que os ataques Shellshock já podem chegar a 1 bilhão e os honeypots estão capturando várias cargas de exploração . Coisas bem desagradáveis, hein?

Eu pensei assim. Portanto, decidi que valeria a pena escrever um guia abrangente sobre o assunto. Há muitas coisas sobre as quais gostaria de falar, então dividi este guia em dois. Nesta primeira parte, eu explico:

1. Bash functions and environment variables.
2. What's the Shellshock vulnerability.
3. Suggestions of how to protect your system.

Na segunda parte, analiso mais profundamente esta vulnerabilidade, explicando:

4. More details about CVE-2014-6271 and the four others CVEs that were created after it.
5. The systems that are vulnerable, with some proof of concept code.
6. Details of how the patches were created.

Pronto?


Compreendendo o Bash Shell

Para entender essa vulnerabilidade, precisamos entender como o Bash lida com funções e variáveis ​​de ambiente.

O shell GNU Bourne Again (BASH) é um shell Unix e interpretador de linguagem de comando . Foi lançado em 1989 por Brian Fox para o Projeto GNU como um substituto de software livre para o shell Bourne , que nasceu em 1977.

$ man bash

BASH
(1) General Commands Manual BASH(1)

NAME

bash
- GNU Bourne-Again SHell

SYNOPSIS

bash
[options] [file]

COPYRIGHT

Bash is Copyright (C) 1989-2011 by the Free Software Foundation, Inc.

DESCRIPTION

Bash is an sh-compatible command language interpreter that executes com
mands read from the standard input or from a file
. Bash also incorporates
useful features from the
Korn and C shells (ksh and csh).
(...)

Claro, existem outros shells de comando por aí . No entanto, Bash é o shell padrão para a maioria dos sistemas Linux (e sistemas baseados em Linux), incluindo qualquer baseado em Debian e Red Hat & Fedora.

Funções no Bash

O interessante vem do fato de que Bash também é uma linguagem de script, com a capacidade de definir funções. Isso é muito útil quando você está escrevendo scripts. Por exemplo :hello.sh

#!/bin/bash
function hello {
echo
Hello!
}
hello

que pode ser chamado de:

$ chmod a+x hello.sh
$
./hello.sh
Hello!

Uma função pode ser compactada em uma única linha. Você só precisa escolher um nome e colocar um ()depois dele. Tudo o que estiver dentro {}pertencerá ao escopo de sua função.

Por exemplo, podemos criar uma função bashiscoolque usa echo para exibir mensagens na saída padrão:

$ bashiscool() { echo "Bash is actually Fun"; }
$ bashiscool

Bash is actually Fun

Processos Filhos e o export Comando

Podemos tornar as coisas ainda mais interessantes. A instrução pode ser usada para executar uma nova instância do Bash, como um subprocesso, para executar novos comandos. O problema é que o processo filho não herda as funções ou variáveis ​​que definimos no pai:bash -c

$ bash -c bashiscool # spawn nested shell
bash
: bashiscool: command not found

Portanto, antes de executar uma nova instância do Bash, precisamos exportar as variáveis ​​de ambiente para o filho. É por isso que precisamos do exportcomando. No exemplo abaixo, o sinalizador significa ler as combinações de teclas do nome do arquivo :-f

$ export -f bashiscool
$ bash
-c bashiscool # spawn nested shell
Bash is actually Fun

Em outras palavras, primeiro o exportcomando cria uma variável de ambiente regular contendo a definição da função. Em seguida, o segundo shell lê o ambiente. Se ele vir uma variável que se parece com uma função, ele avalia esta função!

Um exemplo simples de uma variável de ambiente

Vamos ver como as variáveis ​​de ambiente funcionam examinando alguns comandos internos do Bash. Por exemplo, um muito popular,, grepé usado para pesquisar padrões em arquivos (ou a entrada padrão).

Executar grepem um arquivo que contém a palavra ‘diversão’ retornará a linha onde esta palavra está. Executar grepcom uma bandeira retornará as linhas não correspondentes, ou seja , as linhas onde a palavra ‘diversão’ não aparece:-v

$ echo 'bash can be super fun' > file.txt
$ echo
'bash can be dangerous' >> file.txt
$ cat file
.txt
bash can be super fun

bash can be dangerous

$ grep fun file
.txt
bash can be super fun

$ grep
-v fun file.txt
bash can be dangerous

O grepcomando usa uma variável de ambiente chamada GREP_OPTIONS para definir as opções padrão. Essa variável geralmente é definida como:

$ echo $GREP_OPTIONS
--color=auto

Para atualizar ou criar uma nova variável de ambiente, não é suficiente usar a sintaxe Bash , mas em vez disso, precisamos chamar o interno :GREP_OPTIONS='-v' export

$ GREP_OPTIONS='-v'
$ grep fun file
.txt
bash can be super fun

$ export GREP_OPTIONS
='-v'
$ grep fun file
.txt
bash can be dangerous

O env comando

Outro Bash embutido, o env imprime as variáveis ​​de ambiente. Mas também pode ser usado para executar um único comando com uma variável exportada (ou variáveis) fornecida a esse comando. Nesse caso, envinicia um novo processo, depois modifica o ambiente e, a seguir, chama o comando que foi fornecido como argumento (o envprocesso é substituído pelo processo de comando).

Na prática, para usar env para executar comandos, nós:

1. set the environment variable value with env,
2. spawn a new shell using bash -c,
3. pass the command/function we want to run (for example, grep fun file.txt).

Por exemplo:

$ env GREP_OPTIONS='-v' | grep fun file.txt    # this does not work, we need another shell
bash can be super fun

$ env GREP_OPTIONS
='-v' bash -c 'grep fun file.txt' # here we go
bash can be dangerous

Enfrentando a vulnerabilidade de Shellshock

E se passarmos alguma função para a definição da variável?

$ env GREP_OPTIONS='() { :;};' bash -c 'grep fun file.txt'
grep
: {: No such file or directory
grep
: :;};: No such file or directory
grep
: fun: No such file or directory
file
.txt:bash can be super fun
file
.txt:bash can be dangerous

Visto que as coisas que adicionamos são estranhas quando analisadas para o comando grep, ele não as compreenderá.

Agora, e se adicionarmos algumas coisas após a função?

$ env GREP_OPTIONS='() { :;}; echo NOOOOOOOOOOOOOOO!' bash -c 'grep fun file.txt'
NOOOOOOOOOOOOOOO
!
grep
: {: No such file or directory
grep
: :: No such file or directory
grep
: }: No such file or directory
grep
: fun: No such file or directory

Você notou que foi executado normalmente? Este é o bug Shellshock!echo NOOOOOOOOOOOOOOO!

Isso funciona porque quando o novo shell vê uma variável de ambiente começando com (), ele obtém o nome da variável e executa a seguinte string. Isso inclui a execução de qualquer coisa após a função, ou seja , a avaliação não para quando o fim da definição da função é alcançado!

Lembre-se de que echonão é a única coisa que podemos fazer. As possibilidades são ilimitadas! Por exemplo, podemos emitir qualquer comando:/bin

$ env GREP_OPTIONS='() { :;}; /bin/ls' bash -c 'grep fun file.txt'
anaconda certificates file
.txt IPython
(...)

UAU.

Pior, não precisamos usar uma variável de ambiente do sistema nem mesmo chamar um comando real:

$ env test='() { :;}; echo STILL NOOOOOOOO!!!!' bash -c :
STILL NOOOOOOOO
!!!!

No exemplo acima, envexecuta um comando com um determinado conjunto de variáveis ​​(teste) para alguma função (neste caso é apenas um :, um comando Bash definido como não fazer nada). O ponto-e-vírgula sinaliza o fim da definição da função. Novamente, o bug está no fato de que nada impede a análise do que está depois do ponto-e-vírgula!

Agora é fácil ver se o seu sistema está vulnerável, tudo que você precisa fazer é executar:

$ env x='() { :;}; echo The system is vulnerable!' bash -c :

Que simples.


Como Proteger Seu Sistema

Embora um patch para CVE-2014-6271 tenha sido lançado logo após o bug ser divulgado, ele estava incompleto e novos problemas foram rastreados como CVE-2014-7169 , CVE-2014-7186 , CVE-2014-7187 , CVE-2014-6277 e CVE-2014-6278 . Vários patches foram lançados desde então, inclusive no fim de semana. A luta ainda não acabou e recomendo as seguintes medidas:

  • Atualize seu sistema! E continue atualizando … Muitas distribuições Linux lançaram novas versões do software Bash, portanto, siga as instruções de sua distribuição. Na maioria dos casos, um simples yum updateou ou semelhantes irá fazê-lo. Se você tiver vários servidores, o script abaixo pode ser útil:apt-get update
#!/bin/bash
servers
=(
120.120.120.120
10.10.10.10
22.22.22.22
)
for server in ${servers[@]}
do
ssh $server
'yum -y update bash'
done
  • As solicitações HTTP para scripts CGI foram identificadas como o principal vetor de ataque (mostrarei mais detalhes na parte II). Portanto, desative todos os scripts CGI que chamem o shell (no entanto, isso não atenua totalmente a vulnerabilidade). Para verificar se o seu sistema está vulnerável, você pode usar este scanner online . Considere o mod_security se ainda não o estiver usando.

  • Fique de olho em todas as suas contas em busca de sinais de atividade incomum. Considere alterar senhas importantes.

  • Como as solicitações HTTP usadas por exploits Shellshock são bastante exclusivas, monitore os logs com palavras-chave como ou . Alguns lugares comuns para http registros são: , ou .
    grep '() {' access_logcat access_log |grep "{ :;};"cPanel: /usr/local/apache/domlogs/Debian/Apache: /var/log/apache2/CentOS: /var/log/httpd/

  • Em caso de ataque, publique as informações do invasor! Você pode usar awk e uniq para obter seu IP, por exemplo:

$ cat log_file |grep "{ :;};" | awk '{print $1}'|uniq
  • Atualize o firmware em seu roteador ou em qualquer outro dispositivo habilitado para web, assim que estiverem disponíveis. Lembre-se de baixar apenas patches de sites confiáveis ​​(apenas HTTPS, por favor!), Pois os golpistas provavelmente tentarão tirar proveito dos relatórios Shellshock.

  • Se você tiver uma assinatura de hospedagem gerenciada, verifique o status da sua empresa. Por exemplo: Acquia , Heroku , Mediatemple e Rackspace .

  • Atualize seus contêineres Docker e instâncias AWS.

  • Se você estiver executando sistemas de produção que não precisam de funções exportadas, dê uma olhada neste wrapper que se recusa a executar o bash se o valor de qualquer variável de ambiente começar com um pai esquerdo.