HOME | Comente!


Introdução

O JBoss AS é um servidor de aplicações compatível com a especificação Java EE que sempre teve como foco principal, a facilidade de uso. Isto talvez tenha sido um dos principais motivos pelos quais os seus desenvolvedores o deixaram aberto e, desta maneira, suscetível a diversas formas de ataque. Entretanto, ele tem sido modificado em versões mais recentes que eliminam várias vulnerabilidades. Este artigo tem como objetivo principal apresentar como podem ocorrer algumas formas de invasões através deste servidor e, como tomar as precauções básicas para minimizar os ataques bem sucedidos.

JBoss é o nome dado para um conjunto de produtos construídos e gerenciados pela comunidade JBoss. Este conjunto é composto do servidor de aplicações (JBoss AS) e de mais uma grande variedade de produtos. Neste artigo, para simplificar, estaremos nos referenciando ao JBoss AS simplesmente pelo nome JBoss.

A aplicação jmx-console

Quando o JBoss é iniciado, seu núcleo principal (até a versão 4.x, o Microkernel JMX) está acessível para fornecer operações de gerenciamento dos serviços providos por este servidor: os implantadores de aplicações, o servidor de nomes, de logs, o gerenciador de segurança, datasources, transações, persistência, pools de threads, etc. O mikrokernel provê um registrador de componentes de gerenciamento, um serviço que permite correlacionar estes componentes e emitir notificações entre eles, além do mais importante: torna visível os atributos e as operações gerenciáveis que estes componentes possuem, através de diferentes protocolos, entre eles, HTTP e RMI.

Em execução, os componentes de gerenciamento do JBoss podem ser acessados via HTTP através da aplicação jmx-console, e via RMI através de qualquer aplicação Java, sendo que dentre elas, está disponível (no diretório $JBOSS_HOME/bin) o utilitário twiddle.sh.

O JBoss até a versão 4.0 se ligava automaticamente a todas as interfaces de rede (fazia o bind, num jargão mais técnico). Recentemente, seus desenvolvedores substituíram esta característica por uma considerada mais segura: agora, por padrão, o JBoss ao ser iniciado só faz ligação na interface de loopback (127.0.0.1), tornando necessário que o administrador, ao configurar o acesso ao servidor, informe em qual IP o JBoss fará a ligação, através do parâmetro -b. Se o administrador desejar que o JBoss se ligue a todos os IPs, em uma máquina com várias interfaces, ele deve iniciá-lo como no exemplo a seguir:

$ run.sh -b 0.0.0.0

Para acessar o jmx-console você deve entrar numa URL como esta: http://servidor:8080/jmx-console. Às vezes, o JBoss poderá ser configurado para escutar o protocolo HTTP através da porta 80 inserindo-se um proxy que suporte balanceamento de carga através de módulos do Apache como o mod_proxy ou o mod_jk e, neste caso, você terá acesso a ele, sem necessitar especificar a porta. Outra forma de fazer o JBoss atender requisições através da porta 80, em servidores Linux, é configurando o iptables. Também é possível, mas inaceitável em termos de segurança, ajustar as portas escutadas pelo JBoss via ServiceBindingManager ou modificar o arquivo server.xml (do Tomcat embutido) e executá-lo como root para escutar a porta 80. NÃO FAÇA ISTO! ADOTE OUTRA SOLUÇÃO!. Além do jmx-console, outra aplicação web de gerenciamento disponível é o web-console, também acessível por uma URL como http://servidor:8080/web-console.

Em até bem poucas versões atrás o JBoss tinha, por padrão, estas aplicações acessíveis sem a solicitação de nenhuma senha. E grande parte dos problemas atuais de segurança no JBoss estão relacionados a este fato. Muitos administradores inexperientes simplesmente disponibilizam aplicações em produção, sem se atentar a isto.

Você pode fazer algumas buscas no Google por servidores JBoss que estejam com estas aplicações acessíveis na Internet. Clique aqui e aqui para ter um exemplo.

Para proteger o seu servidor do acesso indevido a estas aplicações (jmx-console e web-console), você pode executar os passos descritos neste wiki. As informações contidas nele também descrevem como fazer a configuração do acesso através de HTTPS, tornando seguro o tráfego de informações entre o browser e o servidor. Vale lembrar, que só a proteção do acesso via HTTP não é suficiente já que, havendo a possibilidade de acesso via RMI, também há como se executar qualquer operação de gerenciamento disponibilizada via HTTP. Logo, é fundamental proteger também esta forma de acesso. Você pode ver como fazer isto seguindo os passos desta página.

Nosso objetivo agora é fazer um teste de invasão: iremos implantar uma aplicação no JBoss que nos dará a liberdade para executar comandos na máquina em que o este servidor está sendo executado. Para isto, seguiremos os seguintes passos:

  1. Criaremos uma aplicação web que nos possibilitará executar comandos na máquina em que está o JBoss;
  2. Publicaremos este aplicação em algum servidor web;
  3. Acessaremos a aplicação administrativa do JBoss (jmx-console) e executaremos procedimentos que farão a implantação da aplicação criada no passo 1;
  4. Verificaremos se a aplicação foi realmente implantada;
  5. Executaremos a aplicação;

Criando uma aplicação web maliciosa

A aplicação disponibilizada com este artigo pode ser compilada com o auxílio do Ant. Para simplificar, você também não precisa deste passo pois, ela já está compilada e empacotada para a implantação no JBoss nas versões 3 e 4. Eu realizei o teste deste war nas versões 3.2.8 e 4.2.3 do JBoss. A aplicação pode ser compilada com a versão 1.4 do JDK ou superior e seu objetivo é possibilitar que você emita quaisquer comandos que serão executados pela máquina que está rodando o JBoss. Se o JBoss estiver sendo executado pelo usuário root ou por um usuário com poderes administrativos, dá pra notar o quanto este servidor fica ainda mais vulnerável. Sendo assim, adote uma regra: NÃO RODE O JBOSS COMO root OU COMO QUALQUER USUÁRIO COM PODERES ADMINISTRATIVOS. Caso esta regra não seja observada, os limites de execução de comandos desta aplicação vão desde um simples ls até um rm -rf /.

O ponto principal da aplicação é a execução de qualquer processo na máquina através do seguinte trecho de código (arquivo Executor.java):

Process p = Runtime.getRuntime().exec(cmdarray);
StreamGobbler errGobbler = new StreamGobbler(p.getErrorStream(), resultado);
StreamGobbler outGoogler = new StreamGobbler(p.getInputStream(), resultado);
errGobbler.start();
outGoogler.start();
p.waitFor();

Este trecho é responsável por criar um processo no servidor e executá-lo, passando como parâmetros um array que informa o nome do processo a ser executado e seus argumentos. Após feito isto, o programa cria duas threads que consomem a saída padrão e de erro deste processo e redirecionam estas para um buffer (resultado). Em seguida, o programa aguarda o término da execução do processo.

O processo criado através deste trecho de código pode ser qualquer um que execute no sistema operacional que está rodando o JBoss. Isto então permite a mais variada gama de execuções e, pelo fato do JBoss estar rodando em uma máquina virtual Java e ser independente de plataforma, temos condições de, com esta mesma aplicação, executar programas no Windows, no Linux, no MacOS, ou em qualquer que seja o sistema operacional que estiver executando esta máquina virtual.

Observe o perigo: se o JBoss não estiver sendo executado com um gerenciador de segurança habilitado, os desastres podem ser enormes! Podemos dizer que um gerenciador de segurança é um mecanismo padrão oferecido pelo Java para limitar os poderes da aplicação sobre o sistema operacional.

Agora avançaremos para o próximo passo: a disponibilização da aplicação em um servidor Web para que ela possa ser implantada.

Publicando a aplicação em um servidor web

O JBoss pode implantar aplicações que estão em seu próprio sistema de arquivos ou que estão disponibilizadas em um servidor remoto, através do protocolo HTTP, com ou sem o suporte a WebDAV. Nosso objetivo agora, é pegar a aplicação construída através do passo anterior e disponibilizá-la em um servidor Web para que o JBoss possa realizar a implantação da mesma.

Como você está lendo este artigo a partir de um servidor Web, não é necessário nem mesmo algum esforço para implantar a aplicação em algum outro servidor, não acha? Você pode simplesmente, fazer o servidor JBoss da vítima escolhida apontar para a aplicação disponibibilizada neste link.

Implantando a aplicação no servidor JBoss da vítima

Existem várias formas de se implantar uma aplicação no JBoss. Com toda certeza, a mais comum e conhecida pelos usuários deste servidor é copiar o pacote (.jar, .war, .ear, .sar, ...) para um diretório de implantação como $JBOSS_HOME/server/default/deploy. Desta forma, através do mecanismo de hot deployment que vem habilitado por padrão no JBoss, a aplicação será implantada automaticamente, sem a necessidade de reinicialização do servidor.

Hot deployment é uma característica bastante interessante mas que deve, quase sempre, estar desabilitada em produção. O motivo disto é que não ficamos levando aplicações para este ambiente com a mesma freqüência que no ambiente de desenvolvimento, por exemplo. Desabilitando o hot deployment no ambiente de produção, poupamos recursos e elevamos o grau de segurança: o servidor não precisa de uma thread monitorando mudanças no sistema de arquivos e, não haverá implantações indesejadas realizadas por uma cópia que, por engano, foi feita para o diretório de implantação (deploy, por padrão).

Você pode acompanhar uma discussão interessante sobre hot deployment neste link to TheServerSide.com. Além disto, esta página do Wiki do JBoss trás mais informações sobre como configurar o serviço DeploymentScanner, responsável por habilitar ou desabilitar esta característica.

Um pacote também pode ser implantado no servidor com sua estrutura descompactada no diretório deploy. Neste caso, fica mais fácil alterar uma classe ou, no caso de aplicações Web, qualquer página JSP e solicitar a reimplantação simplesmente fazendo-se um touch nos arquivos principais (web.xml, ejb-jar.xml, jboss-service.xml, ...). Mais uma vez, embora esta seja uma prática comum no ambiente de desenvolvimento, este tipo de implantação deve ser evitada no servidor pois, em termos de performance, é melhor implantar aplicações Web com páginas JSP já pré-compiladas e, como se desabilita o hot deployment em produção, não faz sentido fazer a implantação de pacotes explodidos além de não se ficar alterando frequentemente os arquivos de deployment. Talvez uma justificativa para a implantação de pacotes explodidos fosse a necessidade da aplicação escrever dados em algum local abaixo de sua estrutura de arquivos. Mas, uma solução melhor para este problema poderia ser o uso de uma propriedade (configurada pelo administrador do JBoss) que derterminasse aonde a aplicação deveria escrever estes dados.

Além da cópia do pacote para o diretório deploy, podemos também efetuar uma implantação utilizando os serviços oferecidos pelo componente (MBean) MainDeployer. Este componente, acessível pelo jmx-console, disponibiliza o método deploy que recebe como parâmetro uma URL. Esta será a forma que utilizaremos para efetuar o deploy da nossa aplicação maliciosa. Sendo assim, para efetuar a implantação da aplicação, será necessário acessar este MBean e executar a operação deploy que receberá como parâmetro esta URL.

Se a aplicação não tiver sido implantada com sucesso você verá uma tela de erro. Talvez isto possa ter ocorrido pelo fato do servidor não ter acesso direto a Internet (por estar atrás de um proxy, por exemplo). Neste caso, você não terá como implantar a aplicação pois o servidor precisa buscá-la a partir de uma URL válida e, como ele não tem acesso a Internet, somente urls locais da rede do servidor serão válidas. Mas, caso não ocorra erro, para checar se a aplicação foi implantada com sucesso, o MBean MainDeployer também deverá ser executado. O método listDeployedModules deve conter em seu resultado uma referência ao pacote cmd.war.

Se isto tiver ocorrido com sucesso, você pode acessar o servidor da vítima, através de uma URL como esta: http://servidor-da-vitima:porta/cmd.

Executando comandos no servidor da vítima

Eu vou lhe dar uma dica inocente... Se você estiver numa máquina Linux, rode comandos inofensivos como:

O restante fica a cargo de sua imaginação... ;-)

Eu também desenvolvi para a aplicação cmd uma pequena classe (ComandoEncerrar.java) que possibilita você parar o servidor JBoss da vítima e que serve como um modelo para você poder criar seus próprios comandos. Mas, lembre-se que se o gerenciador de segurança estiver do JBoss estiver habilitado, talvez este e outros diversos comandos não sejam possíveis.

Como você pode perceber, é realmente um desatre para a segurança de seu servidor JBoss, deixar o jmx-console desprotegido.

Conclusão

Proteja o acesso ao seu JBoss! Investigue no mínimo se você já colocou uma senha de acesso para as aplicações jmx-console e web-console, ou se já as removeu (ou pelo menos renomeou), no ambiente de produção. Isto não irá garantir que você esteja seguro sob diversos outros aspectos, mas já é o primeiro passo.

Links extras


HOME | Comente!

Fonte deste documento (index.t2t), versão TXT (index.txt)