hardening tomcat

23
Faculdade Santa Maria Departamento de Computação Especialização em Segurança de Redes e Sistemas Hardening do Tomcat em Servidores Linux Bernardo Sales Teixeira da Silva Agosto 2009

Upload: bernardo-sales

Post on 30-Jun-2015

503 views

Category:

Documents


12 download

TRANSCRIPT

Page 1: Hardening Tomcat

Faculdade Santa Maria

Departamento de Computação

Especialização em Segurança de Redes e Sistemas

Hardening do Tomcat em Servidores Linux

Bernardo Sales Teixeira da Silva

Agosto 2009

Page 2: Hardening Tomcat

Resumo

Esse documento foi feito com o objetivo de demonstrar o processo de hardening de um

servidor linux executando o tomcat. Serão mostradas e explicadas desde a instalação do

Tomcat as configurações necessárias para que o sistema execute com a melhor performance e

em um nível de segurança aceitável sem comprometer suas funcionalidades.

Page 3: Hardening Tomcat

Sumário

1. INTRODUÇÃO ______________________________________________________________________________ 4

2. BAIXANDO E INSTALANDO O TOMCAT _________________________________________________ 5

3. CONFIGURAÇÕES DE SEGURANÇA DO TOMCAT _______________________________________ 6

3.1. CONNECTORS ____________________________________________________________________________ 6

3.2. EXECUTANDO O TOMCAT COM UMA CONTA NÃO PRIVILEGIADA ________________ 8

3.3. APLICAÇÕES DA INSTALAÇÃO PADRÃO DO TOMCAT _____________________________ 10

3.4. SECURITY MANAGER __________________________________________________________________ 11

3.5. EXECUTANDO O TOMCAT EM UMA JAULA CHROOT _______________________________ 11

4. CONCLUSÃO _______________________________________________________________________________ 23

5. REFERÊNCIAS _____________________________________________________________________________ 23

Page 4: Hardening Tomcat

1. Introdução

Os sistemas web são complexos desde a sua concepção pois envolvem inicialmente uma série

de outros aplicativos para poderem funcionar e extender funcionalidades. Tudo isso aumenta a

superfície de exposição dos servidores de aplicações web, o que acaba sendo um assunto a ser levado

muito a sério do ponto de vista de segurança, pois quanto mais complexa se torna uma aplicação, a

mesma tende a ter mais pontos vulneráveis. O OWASP1 Top 10 project é um projeto que visa divulgar as

10 principais vulnerabilidades exploradas nas aplicações web e junto a isso fornece documentações com

procedimentos e recomendações para evita-las. Um dos itens dessa lista refere-se ao escopo desse

documento que é a configuração inadequada do servidor de web e de aplicações. No nosso caso

específico iremos abordar a configuração do Tomcat, que é um servidor de aplicações web escritas em

Java.

Será utilizado o sistema operacional Linux para os procedimentos descritos nesse documento

sendo a distribuição escolhida o Debian 5.01 Lenny. Como a instalação do linux não é o foco desse

documento não iremos abordar esse procedimento, estamos assumindo que o sistema operacional já

está instalado. Para mais informações sobre esse tópico visite http://d-

i.alioth.debian.org/manual/en.i386/index.html. Nesse link é abordado com detalhes todo o processo de

instalação do Debian.

1 Open Web Application Security Project é uma comunidade aberta e livre que possui integrantes por todo o

mundo com o propósito de criar documentações, metodologias dentre outras ferramentas focadas na segurança de aplicações web. Para mais informações visite http://www.owasp.org/.

Page 5: Hardening Tomcat

2. Baixando e Instalando o Tomcat

Antes de tudo precisamos de uma JVM2 instalada e com as veriáveis de ambiente

configuradas. Baixamos e instalamos a partir dos repositórios non-free do Debian o pacote sun-

java6-jdk. Fazemos isso com o apt-get:

#apt-get install –y sun-java6-jdk

Definimos as variáveis de ambiente JAVA_HOME e JRE_HOME, dessa forma colocamos no

arquivo ~/.bash_profile essas definições:

export JAVA_HOME=/usr/lib/jvm/java-6-sun

export JRE_HOME=${JAVA_HOME}/jre

Também incluímos na varíavel de ambiente PATH o caminho para os binários do java(

colocamos também no arquivo .bash_profile logo depois das linhas acima):

export PATH=${PATH}:${JAVA_HOME}/bin:${JRE_HOME}:/bin

Baixamos o tomcat com o wget:

$wget http://linorg.usp.br/apache/tomcat/tomcat-6/v6.0.20/bin/apache-tomcat-6.0.20.tar.gz

No momento em que esse documento foi escrito a versão mais recente disponível do tomcat

era a 6.0.20. Depois de baixado, descompactamos com a ferramenta tar, mudamos para o

diretório criado depois da extração e executamos o script startup.sh:

$tar –xvzf apache-tomcat-6.0.20.tar.gz

$cd apache-tomcat-6.0.20

$sh startup.sh

Se tudo estiver correto, poderemos acessar a página de teste do Tomcat na porta 8080 do

nosso servidor. Essa é a instalação default do Tomcat da forma mais simples possível, não

instalamos o apache junto com o mesmo visto que o foco desse documento é apenas tratar das

configurações de segurança do tomcat, no entanto é possível configurar o tomcat para ser

executado junto com o apache, para informações nesse tópico visite

http://www.vivaolinux.com.br/artigo/Integracao-Apache-=%3E-Tomcat/. Existem muitas outras

referências sobre esse assunto disponíveis no google.

2 Java Virtual Machine, a máquina virtual Java que utilizamos está na versão 1.6.0 build 12.

Page 6: Hardening Tomcat

Figura 1 - A Instalação do Tomcat foi concluída com sucesso.

3. Configurações de segurança do Tomcat

Iremos demonstrar algumas configurações nessa seção com o objetivo de deixar o nosso

tomcat mais seguro. Desse ponto em diante iremos considerar que o diretório raíz da instalação

do Tomcat está em /opt/apache-tomcat-6.0.20.

3.1. Connectors

O tomcat utiliza objetos chamados Connectors3 para se comunicar com o mundo

externo. A página de teste que acessamos na porta 8080 é disponibilizada por um Connector do

Tomcat. Esses conectores podem receber alguns parâmetros que configuram seu

comportamento como o timeout ou o limite máximo de conexões. Inicialmente o Tomcat já

vem com dois Connectors habilitados sendo que um é o que fornece a página exibida na figura 3 Um Connector representa um ponto de conexão(porta TCP) através do qual requisições são recebidas e respostas

são enviadas.

Page 7: Hardening Tomcat

1 e o outro escuta na porta 8009, que serve para integrar o Tomcat com outro servidor web

como o Apache ou o IIS da Microsoft. Caso no nosso sistema não exista nenhum Apache para

utilizar esse serviço, podemos desabilitar esse connector sem problemas, pois ficar com essa

porta aberta sem necessidade, significa facilitar a vida de um possível atacante que pode ficar

enviando pacotes naquela porta procurando uma vulnerabilidade escondida no tomcat, e isso

talvez nunca seria percebido visto que não iria necessariamente alterar o comportamente dos

outros Connectors. Via de regra desabilitamos tudo o que não utilizamos no nosso servidor.

Podemos bloquear o acesso a Connectors não utilizados comentando a configuração dos

mesmos. Outra porta que fica aberta do tomcat é a 8005 também utilizada para integração com

o Apache e serve para desligar o servidor. Essa porta também definitivamente não deve ficar

exposta. Uma maneira alternativa aos arquivos de configuração do Tomcat é fazer esse

bloqueio com o iptables(inicialmente a política de INPUT do iptables já deve ter como ação

padrão DROP, salvo casos excepcionais):

#!/bin/sh # comando iptables, medida basica de seguranca IPTABLES=/sbin/iptables # algumas variaveis locais SHUTDOWN=8005 AJP=8009 # limpeza da base de regras $IPTABLES -F $IPTABLES -t nat -F $IPTABLES -t mangle -F # Apaga quaiquer cadeias criadas $IPTABLES -X $IPTABLES -t nat -X $IPTABLES -t mangle -X # Zera contadores $IPTABLES -Z $IPTABLES -t nat -Z $IPTABLES -t mangle -Z # bloqueia qualquer acesso as portas 8009 e 8005 $IPTABLES -A INPUT -s 0/0 -p tcp --dport ${SHUTDOWN} -j DROP

$IPTABLES -A INPUT -s 0/0 -p tcp --dport ${AJP} -j DROP

Page 8: Hardening Tomcat

3.2. Executando o Tomcat com uma conta não privilegiada

Outro ponto importante é a conta sob a qual o tomcat irá executar. Serviços que

executam como root possuem total controle sobre a máquina, sendo assim bugs como buffer

overflows ou qualquer outro que permita a injeção de comandos maliciosos terão seus efeitos

destruidores com a máxima eficácia, podendo o atacante inclusive teoricamente limpar os

rastros do seu ataque no servidor. Minimizamos os danos de um ataque desse tipo, removendo

os privilégios exagerados sob o qual o tomcat executa. Para isso criaremos um usuário

específico sem privilégios de root para executar e administrar o tomcat. Se precisarmos abrir

com o tomcat alguma porta abaixo de 1024, nesse caso poderiamos utilizar o iptables para nos

ajudar nisso, visto que precisamos de poderes de root para fazer isso. Segue um script dfe

exemplo em bash que configura o iptables para redirecionar a solicitação para a porta 8080 do

tomcat.

#!/bin/sh # script para redirecionar o trafego da porta default do tomcat 8080 para a porta 80 # comando iptables, medida basica de seguranca IPTABLES=/sbin/iptables # algumas variaveis locais LOCALETH=eth0 TOMCAT=8080 HTTP=80 # limpeza da base de regras $IPTABLES -F $IPTABLES -t nat -F $IPTABLES -t mangle -F # Apaga quaiquer cadeias criadas $IPTABLES -X $IPTABLES -t nat -X $IPTABLES -t mangle -X # Zera contadores $IPTABLES -Z $IPTABLES -t nat -Z $IPTABLES -t mangle -Z # redirecao de porta $IPTABLES -A PREROUTING -t nat -i eth0 -p tcp --dport ${HTTP} -j REDIRECT --to-port ${TOMCAT}

Page 9: Hardening Tomcat

Salvamos esse script em /opt/tomcat_scripts/tomcat_iptables.sh. Já para configurarmos o startup do serviço como outro usuário, criamos o usuário “default” para executar o tomcat. E criamos o seguinte script para inicialização do tomcat em /opt/tomcat_scripts/. #!/bin/sh # variaveis locais export TOMCAT_HOME=/opt/apache-tomcat-6.0.20 export TOMCAT_START=${TOMCAT_HOME}/bin/startup.sh export TOMCAT_STOP=${TOMCAT_HOME}/bin/shutdown.sh export FIREWALL_STARTSCRIPT=/opt/tomcat_scripts/tomcat_iptables.sh export TOMCAT_USER=default export SU=/bin/su export USAGE="tomcat.sh {start|stop}" export ECHO=/bin/echo #inicial o tomcat e aplica regras de firewall(“start”), senão para o tomcat(“stop”) case "$1" in start) ${SU} - ${TOMCAT_USER} -c ${TOMCAT_START} ${FIREWALL_STARTSCRIPT} ;; stop) ${SU} - ${TOMCAT_USER} -c ${TOMCAT_STOP} ;; *) ${ECHO} ${USAGE} ;; esac exit 0

Esse script basicamente aceita os parâmetros “start” ou “stop” para iniciar ou desligar o tomcat respectivamente. Salvamos esse script como tomcat.sh. Colocamos o link simbólico no diretório /etc/rc2.d/: #ln –s /opt/tomcat_scripts/tomcat.sh S21tomcat

Depois criamos outro link simbólico no diretório /etc/rc0.d para que o serviço seja desligado quando o servidor for desligado também: #ln –s /opt/tomcat_scripts/tomcat.sh K79tomcat

Page 10: Hardening Tomcat

3.3. Aplicações da instalação padrão do Tomcat

O Tomcat já vem com algumas aplicações instaladas por padrão, quando visitamos o

diretório /manager/html podemos ver quais aplicações estão rodando, através de uma

aplicação que também vêm configurada por default no tomcat chamada Manager. Em casos de

ambientes de produção devemos desabilitar as aplicações que não serão utilizadas. Para tal

basta removermos os diretórios das aplicações desnecessárias da pasta webapps dentro da

pasta do tomcat. Na verdade se possível devemos remover todas as aplicações default que vem

como tomcat, isso deixará o servidor mais seguro, no entanto se realmente for necessário

deixar a manager, a mesma não é acessível por default. Para configurar o acesso a essa

aplicação devemos definir um usuário e senha no arquivo tomcat-users.xml e incluir o usuário

na role manager. O arquivo tomcat-users.xml fica no diretório conf/.

Figura 2 - Definimos o usuário "default" na role "manager", é claro que em um ambiente de produção não podemos definir um usuário e senha tão previsíveis

Page 11: Hardening Tomcat

3.4. Security Manager

Um dos recursos de segurança do Java2 é a possibilidade de configurar políticas de

segurança criando restrições no código que é executado utilizando Security Managers. Isso nos

permite ter um controle bastante refinado no que a aplicação poderá fazer como, parar

máquina virtual Java, acessar arquivos em disco ou abrir conexões de rede para outros

endpoints por exemplo. Isso traz muitos benefícios para tornar nosso Tomcat mais robusto,

uma vez que podemos restringir o acesso ao sistema de arquivos local, não permitir o

desligamento da JMV ou acesso a outros recursos externos ao servidor a partir de qualquer

aplicação por exemplo, já estamos deixando o Tomcat muito mais seguro e mesmo que as

aplicações que executam nele sejam o elo fraco da corrente, sabemos que elas não tem muito

poder para fazer tanto mal assim, pelo menos não na infraestrutura do servidor. O arquivo de

configurações da política de segurança do Tomcat é o catalina.policy que fica no diretório

conf/. A configuração padrão já nos fornece um nível de segurança razoável e para iniciar o

tomcat com o security manager adicionamos no nosso script tomcat.sh o parâmetro de

inicialização –security no comando que invoca o tomcat. Isso fará a JVM carregar as

configurações definidas no arquivo catalina.policy. Aplicando o Security Manager

modificaremos apenas a linha que inicializamos o tomcat no nosso script tomcat.sh:

${SU} - ${TOMCAT_USER} -c “${TOMCAT_START} – security”

Grifamos de vermelho o trecho que alteramos. Agora quando o tomcat for inicializado ele deve

indicar que está utilizando o Security Manager conforme a figura abaixo:

Figura 3 - Iniciando o Tomcat com o Security Manager

3.5. Executando o Tomcat em uma jaula chroot

Chroot significa modificar o diretório raíz de algum processo para um diretório que

escolhermos, no caso do Tomcat isso significa que podemos criar um diretório raíz e assim

“isolar” o Tomcat do resto do nosso servidor, garantindo assim um pouco mais de segurança

aos outros diretórios do mesmo. Para executar o Tomcat em um contexto de diretório raíz

modificado teremos que configurar primeiro a jvm para funcionar nesse contexto chroot, o que

Page 12: Hardening Tomcat

envolve basicamente criar uma árvore de diretórios que se pareça com o “/” original de modo

que a JVM e o Tomcat “pensem” que estão executando no SO normalmente sem ter seu

diretório raíz modificado.

O aplicativo utilizado para realizar essa tarefa é o chroot. Ele já instalado por padrão no

Debian 5.01. O comando chroot é simples de executar, de uma maneira bem simplificada:

#chroot <caminho para novo root> <comando para executar> <argumento(s)...>

Isso fará o aplicativo executado “pensar” que o diretório raíz é o que nós indicamos no primeiro

argumento para chroot. Isso no nosso caso implica em levar para o nosso diretório raíz

modificado todas as bibliotecas de depências do tomcat e da máquina virtual Java, mais as

dependências das próprias bibliotecas e montar suas estruturas idênticas as originais para que

os nossos aplicativos executem de forma transparente na nossa jaula chroot. Isso pode ser um

tanto trabalhoso mas sem sombra de dúvida já nos fornece mais uma camada de segurança,

pois caso um atacante consiga executar algum código arbitrário através do Tomcat, o mesmo

estará restrito a jaula que montamos, não podendo ir para outros diretórios do servidor. No

entanto não devemos confiar totalmente nessa jaula, pois como na vida real, nem toda prisão é

impossível de fugir, o atacante pode se conectar a outros processos vulneráveis depois de

entrar pelo tomcat, ou através de outras vulnerabilidades conseguir acesso ao nosso sistema

fora da jaula chroot ainda. De qualquer forma, devemos tentar fazer todos os procedimentos

possíveis de hardenização do nosso servidor. Não iremos colocar todos os comandos

executados para configurar o Tomcat na jaula chroot, apenas iremos colocar os comandos mais

importantes, apesar de descrever toda a configuração.

Para conseguir executar o Tomcat em uma jaula chroot devemos ser root, pois o kernel

não deixará outro usuário a não ser o root utilizar a chamada de sistema chroot(), e além disso

instalar o tomcat a partir dos binários oficiais, uma instalação através de algum gerenciador de

pacotes, pode criar os arquivos do Tomcat espalhados pelo verdadeiro “/”, tornando nossa

configuração mais complicada. Esse procedimento deve ser feito como root e não

necessáriamente irão ser os mesmos arquivos em todos os sistemas, mas basicamente a teoria

para o chroot funcionar é a mesma.

Começaremos definindo um diretório que será o nosso “/”(root)

modificado(recomendamos criar o diretório chroot dentro do /opt, mas isso é apenas uma

preferência, pode ser em outro lugar, depende da conveniência), depois disso dentro dele

criamos os diretórios bin, dev, etc, lib, opt, proc, tmp, usr(se o seu sistema for de 64bits

também deve criar o diretório lib64 e copiar as depêndencias adequadas).

Copiamos alguns arquivos do diretório /etc para o nosso etc “engaiolado”:

Page 13: Hardening Tomcat

hosts, nsswitch.conf, resolv.conf. Utilizamos eles para que o tomcat consiga resolver

nomes, assegure que nenhuma configuração desnecessária esteja nesses arquivos;

o diretório java-6-sun, que contém arquivos de configuração da JVM;

Fazemos todas as cópias de arquivos são feitas com a opção –a. Que serve para manter todas

as características do arquivo original quando possível. Assumindo que o nosso diretório chroot

esteja em /opt/chroot: #cp –a /etc/hosts /opt/chroot/etc/hosts

Ou #cd /opt/chroot/etc

#cp –a /etc/hosts .

Também devemos manter todas as permissões desses diretórios idênticas aos originais!

Precisamos mover todos os binários da JVM para que o Tomcat funcione corretamente,

para isso copiamos o diretório de instalação da JVM para dentro do nosso raíz e montamos a

mesma estrutura de diretórios original. Depois iremos resolver as dependências de bibliotecas

para a JVM. Para descobrir as dependências utilizamos o aplicativo ldd(figura 4).

O ldd nos diz quais são e onde estão as libs de dependência do argumento de entrada.

Podemos passar inclusive outras libs que o ldd irá exibir a mesma saída. Verifique se entre os

arquivos indicamos pelo ldd não existem links simbólicos, caso existam devemos copiar todos

os binários originais nesse caso para reproduzir o ambiente original de execução. Verifique

abaixo nas figuras 5 e 6 outras bibliotecas que colocamos no diretório /opt/chroot/lib e

também outro subdiretório desse mesmo diretório que também copiamos para nossa

estrutura.

Page 14: Hardening Tomcat

Figura 4 - Utilizando o ldd para resolver dependências.

Figura 5 - Saída do comando ls no nosso diretório chroot /lib. Verifique que os links simbólicos que apontam para um caminho relativo estão resolvidos.

Page 15: Hardening Tomcat

Figura 6 - Listagem do diretório /opt/chroot/lib/i686/cmov.

Copiamos na listagem da figura 6 algumas outras dependências para o bash, pois precisaremos dele no nosso chroot assim como outros aplicativos como o touch e o uname, que são executados pelo script de inicialização do tomcat(catalina.sh). Também incluímos outras bibliotecas para resolução de nomes. Essas bibliotecas descobrimos observando as saídas de erro dos programas executados a partir do nosso diretório chroot e utilizando o ldd. Caso ainda tenha dificuldades, o strace é uma ferramenta que rastreia chamadas de kernel sendo assim ele gera muito mais saída do que realmente acontece “por baixo dos panos” no momento do carregamento das bibliotecas compartilhadas e tudo mais o que o aplicativo faz:

#strace chroot /opt/chroot /usr/lib/jvm/java-6-sun/bin/java &> output.txt

Observe que redirecionamos a saída do strace para um arquivo texto, pois o mesmo pode gerar

muita coisa mesmo, e dessa forma podemos analisar com mais calma o que aconteceu.

Criaremos os dispositivos necessários para a execução dos aplicativos que executamos

na chroot, para isso copiamos o script /dev/MAKEDEV para /opt/chroot/dev e depois criamos

os dispositivos com o MAKEDEV4:

#cd /opt/chroot/dev

#./MAKEDEV –d

#./MAKEDEV null

Os comandos executados acima irão criar vários dispositivos.

O diretório /proc também deve ser montado para que a JVM funcione corretamente:

#mount –t proc proc /opt/chroot/proc

Instalamos o bash de modo que possamos executar scripts e depurar problemas dentro da

“gaiola chroot”. Para fazer isso basta copiar o binário /bin/bash para /opt/chroot/bin e

também criar o link sh dentro da pasta bin apontando para o bash. Não se esqueça das

4 O MAKEDEV é um script utilizado para criar dispositivos. Para mais informações visite as páginas de manual do

MAKEDEV.

Page 16: Hardening Tomcat

bibliotecas compartilhadas, caso não consiga executar o bash, deve ser porque o ambiente não

está igual ao original, faça como descrevemos acima para resolver as dependências quebradas.

A partir desse ponto já devemos ser capazes de executar a máquina virtual java dentro

do contexto chroot(figura 7) e assim também já devemos tentar executar o tomcat(figura 8)!

Figura 7 - JVM sendo executada dentro da gaiola chroot

Figura 8 - Executando o Tomcat em um contexto chroot.

Depois de toda essa configuração ainda temos um pequeno problema, o Tomcat está

novamente executando como root, o que definitivamente não queremos, pois inclusive já

demonstramos como fazer o Tomcat executar como outro usuário que não seja root. Essa

limitação se deve ao chroot, que deve ser executado como root. No entanto o chroot do

FreeBSD nos permite passar como argumento de linha de comando um usuário que irá executar

o aplicativo na gaiola chroot. Baixamos o código fonte do chroot do FreeBSD e a única coisa que

iremos fazer será uma pequena modificação para porta-lo para o Linux para depois finalmente

compilar e ter um chroot que permite passar um usuário não root como parâmetro para

executar comandos em chroot. Baixamos o arquivo chroot.c no seguinte link

http://svn.freebsd.org/viewvc/base/stable/8/usr.sbin/chroot/chroot.c?revision=196045&view=

markup. Segue o código fonte com a parte que modificamos grifada em negrito.

/*

* Copyright (c) 1988, 1993

* The Regents of the University of California. All rights reserved.

*

* Redistribution and use in source and binary forms, with or without

* modification, are permitted provided that the following conditions

* are met:

* 1. Redistributions of source code must retain the above copyright

* notice, this list of conditions and the following disclaimer.

* 2. Redistributions in binary form must reproduce the above copyright

* notice, this list of conditions and the following disclaimer in the

* documentation and/or other materials provided with the distribution.

* 4. Neither the name of the University nor the names of its contributors

* may be used to endorse or promote products derived from this software

* without specific prior written permission.

Page 17: Hardening Tomcat

*

* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND

* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE

* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS

* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY

* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF

* SUCH DAMAGE.

*/

#if 0

#ifndef lint

static const char copyright[] =

"@(#) Copyright (c) 1988, 1993\n\

The Regents of the University of California. All rights reserved.\n";

#endif /* not lint */

#ifndef lint

static char sccsid[] = "@(#)chroot.c 8.1 (Berkeley) 6/9/93";

#endif /* not lint */

#endif

#include <sys/cdefs.h>

/*__FBSDID("$FreeBSD$"); // apenas comentamos isso */

#include <sys/types.h>

#include <ctype.h>

#include <err.h>

#include <grp.h>

#include <limits.h>

#include <paths.h>

#include <pwd.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

static void usage(void);

char *user; /* user to switch to before running program */

char *group; /* group to switch to ... */

char *grouplist; /* group list to switch to ... */

int

main(argc, argv)

int argc;

char *argv[];

{

struct group *gp;

struct passwd *pw;

char *endp, *p;

const char *shell;

gid_t gid, *gidlist;

Page 18: Hardening Tomcat

uid_t uid;

int ch, gids;

long ngroups_max;

gid = 0;

uid = 0;

while ((ch = getopt(argc, argv, "G:g:u:")) != -1) {

switch(ch) {

case 'u':

user = optarg;

if (*user == '\0')

usage();

break;

case 'g':

group = optarg;

if (*group == '\0')

usage();

break;

case 'G':

grouplist = optarg;

if (*grouplist == '\0')

usage();

break;

case '?':

default:

usage();

}

}

argc -= optind;

argv += optind;

if (argc < 1)

usage();

if (group != NULL) {

if (isdigit((unsigned char)*group)) {

gid = (gid_t)strtoul(group, &endp, 0);

if (*endp != '\0')

goto getgroup;

} else {

getgroup:

if ((gp = getgrnam(group)) != NULL)

gid = gp->gr_gid;

else

errx(1, "no such group `%s'", group);

}

}

ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1;

if ((gidlist = malloc(sizeof(gid_t) * ngroups_max)) == NULL)

err(1, "malloc");

for (gids = 0;

(p = strsep(&grouplist, ",")) != NULL && gids < ngroups_max; ) {

if (*p == '\0')

continue;

if (isdigit((unsigned char)*p)) {

Page 19: Hardening Tomcat

gidlist[gids] = (gid_t)strtoul(p, &endp, 0);

if (*endp != '\0')

goto getglist;

} else {

getglist:

if ((gp = getgrnam(p)) != NULL)

gidlist[gids] = gp->gr_gid;

else

errx(1, "no such group `%s'", p);

}

gids++;

}

if (p != NULL && gids == ngroups_max)

errx(1, "too many supplementary groups provided");

if (user != NULL) {

if (isdigit((unsigned char)*user)) {

uid = (uid_t)strtoul(user, &endp, 0);

if (*endp != '\0')

goto getuser;

} else {

getuser:

if ((pw = getpwnam(user)) != NULL)

uid = pw->pw_uid;

else

errx(1, "no such user `%s'", user);

}

}

if (chdir(argv[0]) == -1 || chroot(".") == -1)

err(1, "%s", argv[0]);

/* Nessa parte é que o chroot muda o uid/gid do processo */

if (gids && setgroups(gids, gidlist) == -1)

err(1, "setgroups");

if (group && setgid(gid) == -1)

err(1, "setgid");

if (user && setuid(uid) == -1)

err(1, "setuid");

if (argv[1]) {

execvp(argv[1], &argv[1]);

err(1, "%s", argv[1]);

}

if (!(shell = getenv("SHELL")))

shell = _PATH_BSHELL;

execlp(shell, shell, "-i", (char *)NULL);

err(1, "%s", shell);

/* NOTREACHED */

}

static void

usage()

{

(void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "

"[-u user] newroot [command]\n");

Page 20: Hardening Tomcat

exit(1);

}

Como podemos observar acima comentamos apenas uma linha no código para conseguir a

funcionalidade que precisavamos no chroot. Na verdade o que ocorre é que a chamada de

sistema chroot(char*) precisa ser executada como root, então o que ocorre no código acima é

que depois de modificar o diretório corrente para o argumento de linha de comando passado, é

feita a chamada a chroot, ainda com o sid de root, e então depois é(são) chamada(s) a(s)

função(ões) setsid()/setgid()/setgroups() que mudam o usuário/grupo que executa o

programa. Depois disso é executado o argumento passado pela linha de comando que

representa o programa a ser executado no contexto chroot.

Renomeamos o arquivo para modchroot.c, e compilamos o código(devemos lembrar

que para compilar programas precisamos dos compiladores e das bibliotecas de

desenvolvimento, caso não tenha os pacotes necessários faça como o usuário root apt-get

install –y build-essential): $mv chroot.c modchroot.c

$gcc modchroot.c –o modchroot

Deixamos o executável gerado na pasta home do usuário root /root. E sempre que precisarmos

podemos chamar o modchroot toda vez pelo caminho absoluto, ou colocar o mesmo em um

diretório como /sbin. Isso ai fica a escolha de cada um. Agora para iniciar o Tomcat no contexto

chroot, e com permissões de outro usuário(assumindo que o modchroot esteja em

/root/modchroot e que esse “outro usuário” se chame default): #/root/modchroot -u default –g default /opt/chroot /opt/apache-tomcat-6.0.20/bin/startup.sh –

security

Teremos que fazer algumas alterações nos nossos scripts de startup, para que iniciem o

tomcat no contexto chroot, criem as variáveis de ambiente da JVM e adicionaremos algumas

linhas no nosso scripts de firewall do tomcat para fechar algumas portas que não devem ficar

abertas externamente(a não ser que seja realmente necessário).

Iremos remover o shell padrão do nosso usuário do Tomcat(default) e também invalidar

a senha do mesmo, para tornar ainda mais difícil a vida de um invasor que por algum acaso

consiga obter o controle do Tomcat. Para isso vamos no arquivo passwd, localizamos a linha do

nosso usuário, que no nosso caso é o default, e substituímos /bin/bash por /bin/false. Isso fará

que assim que o usuário default fizer o login, volte para o prompt de login novamente. E para

invalidar de uma forma bem direta, editamos o arquivo /etc/shadow, localizamos a linha do

nosso usuário e colocamos uma !(exclamação) antes do inicio da senha do mesmo, que fica

logo após o default: na linha do arquivo. Vide figura abaixo.

Page 21: Hardening Tomcat

Figure 9 - Invalidando a senha do usuário default

Seguem as versões final dos scripts de inicialização e de firewall do Tomcat.

Arquivo tomcat.sh:

#!/bin/sh

# script de inicializacao do tomcat ###################

# variaveis locais ####################################

export MODCHROOT=/root/modchroot

export CHROOTDIR=/opt/chroot

export TOMCAT_HOME=/opt/apache-tomcat-6.0.20

export TOMCAT_START=${TOMCAT_HOME}/bin/startup.sh

export TOMCAT_STOP=${TOMCAT_HOME}/bin/shutdown.sh

export FIREWALL_STARTSCRIPT=/opt/tomcat_scripts/tomcat_iptables.sh

export TOMCAT_USER=default

export TOMCAT_GROUP=${TOMCAT_USER} # nome do usuario = nome do grupo

export SU=/bin/su

export USAGE="${0} {start|stop}"

export ECHO=/bin/echo

########################################################

# variaveis de ambiente da JVM #########################

export JAVA_HOME=/usr/lib/jvm/java-6-sun

export JRE_HOME=${JAVA_HOME}/jre

########################################################

# prepara o diretorio chroot

# monta o /proc na jaula chroot

mount -t proc proc ${CHROOTDIR}/proc/ &> /dev/null

case "$1" in

start)

# ${SU} - ${TOMCAT_USER} -c "${TOMCAT_START} -security"

${MODCHROOT} -u ${TOMCAT_USER} -g ${TOMCAT_GROUP} -- ${CHROOTDIR} ${TOMCAT_START} -security

${FIREWALL_STARTSCRIPT}

;;

stop)

#${SU} - ${TOMCAT_USER} -c ${TOMCAT_STOP}

${MODCHROOT} -u ${TOMCAT_USER} -g ${TOMCAT_GROUP} ${CHROOTDIR} ${TOMCAT_STOP}

# desmonta o /proc do chroot

umount ${CHROOTDIR}/proc &> /dev/null

;;

*)

${ECHO} ${USAGE}

;;

esac

Page 22: Hardening Tomcat

exit 0

Arquivo tomcat_iptables.sh:

#!/bin/sh

# script para redirecionar o trafego da porta default do tomcat 8080 para a porta 80

# tambem bloqueia algumas portas do tomcat para enderecos externos

# comando iptables, medida basica de seguranca

IPTABLES=/sbin/iptables

# algumas variaveis locais

LOCALETH=eth0

TOMCAT=8080

HTTP=80

SHUTDOWN=8005

AJP=8009

######################################################

# essa parte de limpeza de regras nao necessariamente

# precisa executar colocamos isso nesse script porque

# apenas executamos ESTE script de firewall no nosso

# exemplo, mas caso ja possua outros scripts

# executando no servidor adequar a necessidade

######################################################

# limpeza da base de regras

$IPTABLES -F

$IPTABLES -t nat -F

$IPTABLES -t mangle -F

# Apaga quaiquer cadeias criadas

$IPTABLES -X

$IPTABLES -t nat -X

$IPTABLES -t mangle -X

# Zera contadores

$IPTABLES -Z

$IPTABLES -t nat -Z

$IPTABLES -t mangle -Z

##########################################

####### INICIO DAS REGRAS PARA O TOMCAT ##########

# redirecao de porta

$IPTABLES -A PREROUTING -t nat -i eth0 -p tcp --dport ${HTTP} -j REDIRECT --to-port ${TOMCAT}

# bloqueia qualquer acesso as portas 8009 e 8005

Page 23: Hardening Tomcat

# acesso apenas liberado para localhost

$IPTABLES -A INPUT -s ! 127.0.0.1 -p tcp --dport ${SHUTDOWN} -j DROP

$IPTABLES -A INPUT -s ! 127.0.0.1 -p tcp --dport ${AJP} -j DROP

######### FIM DO SCRIPT ###################

4. Conclusão

Com tudo isso já devemos ter uma instalação funcional do Tomcat, e o mais importante

de tudo, bem protegido. Existem outros recursos que não comentamos aqui como por exemplo

um filtro de requisições para requests HTTP, SSL, assim como outras configurações que não nos

aprofundamos completamente como adequações no Security Manager, no entanto esperamos

que o objetivo de introduzir o leitor nas configurações de segurança do Tomcat tenha sido

atingido e o aprofundamento do conteúdo iniciado aqui pode ser encontrado na documentação

oficial do Tomcat, e em vários outros sites pela web(o Google ficará bastante feliz em ajudar

nessa pesquisa). As referências utilizadas para a construção desse documento devem servir

como um ponto de partida.

5. Referências

http://www.theserverside.com/tt/articles/content/TomcatSecurity/TomcatSecurity.pdf

http://linux-sxs.org/internet_serving/book1.html

https://www.owasp.org/images/8/89/OWASP_Top_10_2007_for_JEE.pdf

http://www.owasp.org/index.php/Top_10_2007

http://oreilly.com/catalog/tomcat/chapter/ch06.pdf

http://svn.freebsd.org/viewvc/base/stable/8/usr.sbin/chroot/chroot.c?revision=196045&view=markup

Britain, Jason – O’Reilly Tomcat the Definitive Guide 2nd Edition ISBN-13: 978-0596-10106-0

http://tomcat.apache.org/tomcat-6.0-doc/index.html