Protegendo-se de vírus com procmail
por Elgio Schlemer
15 de agosto de 2001
(versão 1.3)

Muitos vírus são disseminados anexando-se em arquivos executáveis e enviando-se a toda a lista de contatos do usuário. Um destes vírus, o Sircam, causou bastante estrago na Internet Brasileira recentemente.

Passado o susto inicial, procuro organizar neste documento as idéias que circularam nos canais de segurança sobre técnicas de bloqueio deste vírus através de regras de procmail.

1. O que é o procmail?

Procmail é um agente de entrega LOCAL que se encarrega de postar a mensagem localmente, ou seja, gravá-la efetivamente na caixa postal do usuário. Não é uma alternativa ao sendmail , exim ou qmail, pois estes servem para enviar mensagens entre máquinas distintas usando SMTP (Simple Mail Transfer Protocol). No Linux, tipicamente, o sendmail faz uso do procmail para entregas locais de mensagens. Isto pode ser verificado no seu arquivo de configuração /etc/sendmail.cf. Procure pelo FLAG "Mlocal", que deve estar parecido com:


	Mlocal,         P=/usr/bin/procmail, ...

Uma outra possibilidade, frequentemente encontrada em sistemas SunOS utilizam o /bin/mail como padrão e alguns antivirus que agem direto no envio de mensagens podem instalar-se neste ponto. Um destes antivirus é o Amavis, que justamente se instala no lugar do procmail. Mesmo o amavis, que passa um antivirus de verdade em anexos, faz uso do procmail no final da busca.

O envio de uma mensagem pela Internet é feito da seguinte forma: o sendmail (ou outro agente SMTP) recebe uma mensagem via SMTP da internet ou da rede interna. Se esta mensagem for para um destinatário externo, o sendmail se comunica com o sendmail do servidor responsável por este domínio via SMTP (sem querer aqui mencionar os outros protocolos existentes). Mas se a mensagem for para um usuário LOCAL, ou seja, cuja caixa postal fisicamente se encontra no servidor, o sendmail delega a tarefa de entregar esta mensagem a um agente local, como o procmail. Esta tarefa podia ser simplesmente copiar a mensagem para a conta do usuário. Algo simples, como um:


	cat MSG >> /var/spool/mail/usuario

Mas pode não ser tão simples assim, pois a primeira coisa que se deve considerar é garantir que ninguém acesse a caixa postal enquanto ela estiver sendo atualizada. Isto e muito mais o procmail faz.

2. Regras do procmail.

O procmail é extremamente poderoso para configurar regras, possuindo muitas facilidades e possibilidades. Um bom começo é ler o que tem no manual de exemplos (man procmailex), que fornece vários exemplos, desde o simples redirecionamento de mensagens até coisas mais complexas, como tratar de forma diferente mensagens maiores que tantos Kbytes, responder automaticamente, evitar receber a mesma mensagem, etc...

Estas regras podem ser individuais para cada usuário ou podem ser GLOBAIS, sendo aplicada para TODOS os usuários. No caso de serem individuais, elas devem estar em um arquivo de nome .procmailrc no HOME do usuário e este home, evidentemente, deve estar montado no servidor de e-mail. Ainda no caso de regras individuais, deve-se observar que o arquivo deve ter permissão 600, senão não funciona e gera mensagem no syslog.

Observação: eu particularmente considero perigoso permitir que usuários criem seus .procmailrc, pois se alguém roubar a senha de um usuário, pode fazer um grande estrago no servidor de e-mails. Melhor é o servidor de e-mails não montar os homes dos usuários.

Veja um exemplo simples:


	# Linhas com '#' no inicio sao comentarios
	# Exemplo  de .procmailrc (exemplo 1)
	# Nao esquecer de fazer um chmod 600 ~/.procmailrc
	# Apenas salva em um arquivo especifio mensagens sobre linux
     	:0
              * ^Subject.*linux
	      linux.msg
             
	# fim

O pequeno exemplo acima salva no arquivo "linux.msg" todas as mensagens que tenham em qualquer posição no campo Subject do cabeçalho a palavra linux. Importante destacar que as mensagens que cairem na regra NÃO FICARÃO DISPONÍVEIS na caixa postal do usuário, devendo ser procuradas no arquivo. Observe que é possível fazer regras de filtragem (como o Netscape faz) ainda no servidor! Uma regra bastante útil, por exemplo, seria salvar em um arquivo mensagens grandes e manter na caixa postal do usuário as mensagens pequenas. Isto pode ser útil quanto o usuário estiver baixando as mensagens por linha discada.

Se o administrador do sistema quiser que uma regra se aplique a TODOS os usuários, ele deve colocá-las em /etc/procmailrc. Um cuidado maior deve ser tomado, pois estas regras serão aplicadas a TODOS!

Veja o exemplo 2 que evita o recebimento de mensagens duplicadas pelo usuário:


	# Exemplo 2: /etc/procmailrc
	# todos os usuarios executam estas regras
	
	:0 Whc: /var/spool/procmail/${LOGNAME}.lock
	|formail -D 8192 /var/spool/procmail/${LOGNAME}.cache

	:0 a
	/var/spool/procmail/${LOGNAME}.duplicados

	# fim

No exemplo 2, usou-se a variavel $USERNAME para obter o nome do usuário que estiver executando a regra. Outras variáveis existentes são mostradas em man procmailrc.

O exemplo usa um programa externo, formail, que vem junto com o pacote procmail para gerar uma lista de identificadroes de mensagens. Observe que a regra agora tem hc. 'h' quer dizer 'header', ou seja, é apenas o header da mensagem que será passada ao formail. 'c' quer dizer 'carbon copy', ou seja, uma copia da mensagem é que será passada ao formail. Portanto, a mensagem original continua existindo. O formail gera uma lista (com a sintaxe empregada) de identificadores de mensagens (campo Message-ID:), aquela que cada agente de e-mail gera, e salva no arquivo especificado se ainda não estiver lá. Se estiver, não grava. O tamanho desta lista é de 8Kbytes (8192 no parâmetro 'D'). Se já existia a assinatura, formail retorna um valor considerado VERDADEIRO. Se não existia, o valor retornado é considerado FALSO.

A segunda regra ":0 a" será aplicada sempre que uma regra anterior foi VERDADEIRA. Na prática, temos que se o formail retornou VERDADEIRO, porque já existia a assinatura no arquivo, a segunda regra envia a mensagem para o arquivo especificado, nao postando-a na caixa postal.

3. Usando regras para bloquear "virus"

A idéia não é exatamente bloquear o vírus sircam, mas sim bloquear mensagens com anexos suspeitos.

A característica principal do sircam e alguns outros vírus, é disfarçar a extenão do arquivo, fazendo a vítima pensar ser um anexo inofensivo.

A maioria dos usuários sabe que pode abrir sem problema um arquivo "txt", pois é texto puro. Então, o vírus envia um anexo de nome "urgente.TXT.exe" e a vítima pensa ser um "txt", mas é um executável.

Este foi o padrão usado para barrar o sircam. Arquivos com duas extensões, sendo a segunda executável. Um exemplo bem simples (não a solução completa) pode ser:


	# exemplo 3: em /etc/procmailrc
	# Nao use este exemplo!! Eh apenas ilustrativo.
	
	:0 B
    	* filename=.+\....\.(pif|com|exe|bat|lnk|scr|vbs)
	/dev/null
	# fim 

Agora o 'B' indica que deve processar o "Body", corpo da mensagem. Olhando como são colocados os anexos, encontramos o padrão:


	Content-Type: APPLICATION/octet-stream; name="urgente.TXT.exe"
	Content-Disposition: attachment; filename="urgente.TXT.exe"

Isto muda em alguns programas, podendo haver uma quebra de linha antes do campo name ou mesmo a inexistência das aspas.

No exemplo, optou-se por casar tudo que tenha tão somente "filemame...". (a sintaxe segue expressoões regulares, que não serão explicadas aqui). Quero que toda a mensagem que tenha um anexo suspeito, a saber, que seja composto de "nome"."extensao 1"."extensao perigosa" (sendo esta última pif, com, exe, bat, lnk, src e vbs) vá para /dev/null, ou seja, perca-se!

É claro que o exemplo acima está sujo, pois basta fazer uma mensagem que tenha no corpo desta a frase "filename=teste.txt.com" para cair na regra.

Felizmente o nosso sircam é bem comportado para gerar anexos. Ele tem um padrão que não muda. Então, a regra, mais especifica para o Sircam, pode ser:


	# exemplo 4: em /:etc/procmailrc
	# Nao use este exemplo!! Eh apenas ilustrativo.
	# Contribuicao de Rodrigo Barbosa
	
	:0 B
    	* ^Content-Type: application/mixed; name=.+\..+\.(pif|com|exe|bat|lnk|scr|vbs)"?$
	/dev/null
	# fim 

Observe que ela agora está mais específica, exigindo um começo e fim de linha e terminando com ou sem aspas.

É provável que a primeira (exemplo 3) cause falsos positivos, por apenas avaliar a ocorrência de "filename", porém ela pega qualquer anexo de qualquer virus que case com o padrão. É de se analizar com cautela qual é mais favorável.

Considero perigoso enviar mensagens de usuário para /dev/null. O mais prudente é salvá-las em um arquivo especifico. Isto pode ser obtido substituindo o /dev/null por um nome de arquivo. Este nome pode ter o login do usuário como componente:


	# exemplo 5: em /etc/procmailrc
	# Nao use este exemplo!! É apenas ilustrativo.
	
	:0 B
    	* filename=.+\....\.(pif|com|exe|bat|lnk|scr|vbs)
    	/var/spool/procmail/${LOGNAME}.virus
	# fim 

Ainda, mais interessante é poder retornar uma mensagem explicativa a quem enviou o virus, notificando-o de que a mensagem foi recusada. Isto pode ser feito usando o formail, para gerar uma mensagem de resposta. Esta é a solução completa , que é mostrada abaixo em duas edições, com comentários.


	##########################################################
	# Solução 1. Bloqueia qualquer anexo suspeito.
	#   - crie o diretorio $DIR;
	#   - crie o /etc/virus.msg com a msg de aviso.
	# coloque em /etc/procmailrc
	
	# Diretorio onde as msg bloqueadas serão guardadas
	DIR="/var/spool/procmail"

	# Protecao contra alguns virus
	:0 B
	    * filename=.+\....\.(pif|com|exe|bat|lnk|scr|vbs)
	{
	# Cria um copia carbono, que eh passada ao formail. 
	# O formail gera cabecalhos de reply, que concatenado 
	# com o /etc/virus.msg, gera uma mensagem que é passada
	# ao agente SMTP, no caso o sendmail.
	#
	# O parametro -i permite trocar o remetente. No caso, estou 
	# trocando para "antivirus". Senão a msg de retorno iria
	# com o endereco da vitima (digo, quase vitima...). 
	    :0 c
	    |(formail -r -i"From:antivirus" -A"X-Loop: antivirus";\
	    cat /etc/virus.msg)|$SENDMAIL -oi -t
	
	# Utilizando lockfile, para evitar que mais de um
	# processo mexa no arquivo ao mesmo tempo (recomendavel)

    	    :0: ${DIR}/${LOGNAME}.lock
	    ${DIR}/${LOGNAME}.virus
	}
	# fim
	##########################################################


	##########################################################
	# Solucao 2.
	# Filtering for Sircam virus
	# by morcego and Elgio Schlemer
	# For usage on /etc/procmailrc
	#
	:0 HB
	* ^Content-Type: application/mixed; name=.+\..+\.(com|lnk|pif|exe|bat)"?$
	{
	        :0 c
	        | (formail -r -i"From: antivirus" -A"X-Loop: antivirus";\
	        cat /etc/virus.msg)|$SENDMAIL -oi -t
	
        :0
        ${ORGMAIL}.sircam
	# fim
	##########################################################

4. Conclusão

a) O uso destas regras para bloquear anexos não são, evidentemente, uma solução definitiva. O ideal são programas que realmente verificam os enexos a procura de virus. Observe que a solução deixa passar anexos normais, como "teste.exe", por exemplo, ficando a segurança a mercê do bom senso do usuário: o de não executar.

b) Alguns administradores podem ser mais radicais, bloqueando todo e qualquer anexo, mas acho que usuários acostumados a trocar cartões animados por e-mail (executáveis) não vão gostar...

c) É importante que se diga que a privacidade das mensagens dos usuários não foi violada, pois as regras bloqueiam aquelas que são vírus e isto é feito sem a participação do administrador.

d) Entendendo como funciona as regras, pode-se fazer praticamente qualquer coisa. Um sugestão é inserir uma mensagem de aviso da administração logo no inicio do corpo de toda e qualquer mensagem que possua um anexo. Podia ser algo simples, como:

	********* AVISO DA ADMINISTRACAO *********
	A mensagem abaixo possui um anexo que pode
	conter vírus. Certifique-se de passar um
	antivírus antes de abrir o anexo
	******************************************
Assim, o anexo não é removido, mas o usuário tem logo no início uma advertência. (o que todo mundo já devia saber, mas...)


Como tudo neste maravilhoso mundo do Linux, as possibilidades estão limitadas apenas e tão somente pelo conhecimento e criatividade.

5. Referências:

a) Sobre o uso do procmail: um bom começo é ler os manuais do procmail. São três:

	man procmail
	man procmailrc
	man procmailex

b) Expressões Regulares:
Tutorial do Aurélio

c) Assuntos relacionados:
Bloqueando vírus com regras de Procmail.
Protegendo-se de anexos com Procmail - tutorial em português
Antispam por procmail

6. Notas sobre bugs

31/Jul/2001: Jefferson me relatou por e-mail que a solução do antivirus não enviava a resposta de retorno ao usuário que enviou o vírus, mesmo que a mensagem era bloqueada. Seus usuários tinham como característica o fato de não possuirem um shell válido.

O procmail usa o shell padrão do usuário quando precisa executar comandos externos, como o cat e o formail das regras. Este problema pode ser resolvido SETANDO dentro do /etc/procmailrc o shell a ser usado:



	##########################################################
	# Solução 1. 31/07/2001

	# Setando o shell a ser usado
	SHELL=/bin/sh
	
	# Diretorio onde as msg bloqueadas serão guardadas
	DIR="/var/spool/procmail"

	# Protecao contra alguns virus
	:0 B
	    * filename=.+\....\.(pif|com|exe|bat|lnk|scr|vbs)
	{
	    :0 c
	    |(formail -r -i"From:antivirus" -A"X-Loop: antivirus";\
	    cat /etc/virus.msg)|$SENDMAIL -oi -t
	
    	    :0: ${DIR}/${LOGNAME}.lock
	    ${DIR}/${LOGNAME}.virus
	}
	# fim
	##########################################################

12/Ago/2001: Não é uma correção de BUG, mas uma otimização. Inserção de uma regra anterior que filtra APENAS mensagens maiores que X bytes. Isto pode significar aumento de desempenho, pois uma grande variedade de mensagens, menores que o tamanho especificado, nao serão pesquisadas.



	##########################################################
	# Solução 1. 14/08/2001

	# Setando o shell a ser usado
	SHELL=/bin/sh
	
	# Diretorio onde as msg bloqueadas serão guardadas
	DIR="/var/spool/procmail"

	# Protecao contra alguns virus
	# Somente msgs maiores que 30000 bytes
	:0 B
	    * > 30000
	    * filename=.+\....\.(pif|com|exe|bat|lnk|scr|vbs)
	{
	    :0 c
	    |(formail -r -i"From:antivirus" -A"X-Loop: antivirus";\
	    cat /etc/virus.msg)|$SENDMAIL -oi -t
	
    	    :0: ${DIR}/${LOGNAME}.lock
	    ${DIR}/${LOGNAME}.virus
	}
	# fim
	##########################################################

7. Sobre o autor (eu :-D)

Trabalho como administrador de redes do instituto de informática da UFRGS (Universidade Federal do Rio Grande do Sul) e leciono as disciplinas de Arquitetura de Computadores, Linguagem de Programação II, Sistemas Distribuídos, Redes e Segurança de Sistemas na Universidade Luterana do Brasil, ULBRA.

Páginas Pessoais:

http://www.ulbra.tche.br/~elgios - Página na Ulbra, com material das minhas disciplinas.
http//www.inf.ufrgs.br/~elgios - Página na UFRGS, sobre minha vida acadêmica.
http://www.inf.ufrgs.br/~elgios/fotos - Página de fotos com informações não técnicas a meu respeito.