You are on page 1of 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
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.
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
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/.
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.
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 Connectors 3 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.
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
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}
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


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
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
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”:


 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.
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.
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.
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.
*
* 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;
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)) {
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");
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.
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
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


# 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

You might also like