Páginas

quarta-feira, 17 de julho de 2013

Hardening

Muitos administradores (muitos mesmo) ao instalarem um servidor acabam esquecendo (ou são pressionados a terminarem depressa) de uma parte importante do sistema operacional, que é a segurança. Nesse artigo eu pretendo mostrar algumas dicas, técnicas e ferramentas muito legais que visam proteger um firewall. Juntamente com o script de firewall corporativo que foi postado nesse blog, trarão muito mais segurança e minimizarão os riscos de ataques diretamente em seu firewall de borda.

A primeira dica é já para a instalação do SO, mais precisamente na parte de particionamento. Para facilitar a manipulação de partições eu costumo utilizar LVM, pois permite redimensionamentos posteriores, extends de disco, etc. A dica aqui é criar partições separadas para pontos de montagem estratégicos do sistema operacional. Dessa forma podemos definir opções de montagem para cada uma separadamente. Como exemplo, podemos definir que o /home, /tmp e /var não terão permissão de execução, isso quer dizer que nenhum programa malicioso (rootkit, backdoor, exploit) será executado nesses pontos de montagem (comuns nesses casos).

Um esquema bem legal de particionamento seria separar as partições da seguinte forma:

/
/boot
/home
/opt
/tmp
/usr
/var
/var/log

O /home em um firewall não deve conter arquivos pessoais, muito menos executáveis e por isso tiraremos a permissão de execução de binários nessa partição. O mesmo acontece em /tmp e em /var (lembrando que deveremos dar permissão de execução nessas duas partições para utilizarmos ferramentas como apt ou aptitude, mas veremos um script para isso mais adiante). O /opt em geral contém os pacotes que são baixados e instalados pelo próprio usuário, e é bom separarmos a partição para limitarmos o espaço que teremos para esse fim, além de retirarmos a permissão de execução de binários com SUID BIT. A partição /usr conterá os binários do sistema e sua separação aqui é mais para limitar o tamanho mesmo. A partição /var/log também não terá permissão de execução e será limitada para que os logs não venham ocasionalmente a preencher o espaço disponível em disco para o / que dispensa explicações. O /boot é necessário para armazenar o kernel e as informações do GRUB, etc. Essa não faz parte do LVM, é uma partição física formatada em EXT2.

Agora que já temos nosso esquema de particionamento, instalamos o SO e ao término, faremos as atualizações e configurações necessárias. Depois disso vamos modificar as permissões das partições editando o arquivo /etc/fstab (faça backup dele antes). Vamos tomar por exemplo a linha da partição /var:

/dev/mapper/servidor-var /var               ext4    defaults 0       2

Essa é a linha original do arquivo, com as permissões padrão do sistema. Vamos alterá-la para que fique assim:

/dev/mapper/servidor-var /var               ext4    defaults,nosuid,noexec 0       2

Dessa forma, tiramos a permissão de execução na partição e também a permissão de execução de arquivos com SUID BIT ligado. Devemos fazer isso nas partições /home, /tmp, /var, /var/log. Na partição /opt devemos tirar a permissão de execução de SUID BIT (opção "nosuid"). Ao terminar (faça em todas as partições descritas acima), reinicie o sistema para que as alterações tenham efeito ou remonte cada partição:

"mount -o remount /var"

Depois disso, execute um mount para conferir se as alterações foram aplicadas:

"mount"

Para que possamos fazer instalação de pacotes utilizando apt ou aptitude, devemos sempre remontar as partições /tmp e /var com permissão de execução e retirar as permissões após a instalação. Para facilitar, podemos fazer um script simples:

#!/bin/bash
case $1 in
start)
        mount -o remount,rw,noexec /var
        mount -o remount,rw,noexec /tmp
        echo "Partições SEM permissão de execução"
    ;;
stop)
        mount -o remount,rw,exec /var
        mount -o remount,rw,exec /tmp
        echo "Partições COM permissão de execução"
    ;;
*)
        echo "Modo de uso $0 {start|stop}"
        exit 0
    ;;
esac
exit 1

Crie a pasta /root/admin_scripts e coloque esse script lá. Dê permissão de execução chmod +x script.sh. Sempre que ele for executado com a opção "stop" ele dará permissão de execução nas partições, e com a opção "start" ele removerá a permissão de execução das partições.

Nosso próximo passo é remover a permissão de SUID BIT dos binários que não precisam dessa permissão. O que é SUID BIT? É a permissão de execução do dono do arquivo. Isso é, se o dono do arquivo for o root, ele vai ser executado como root e isso pode ser explorado para ganho de acesso administrativo ao sistema operacional. Apenas alguns arquivos tem a real necessidade de serem executados com SUID BIT, e o script abaixo retira as permissões dos demais:

#!/bin/bash
# Script para remover SUID BIT de binários Linux
# Desenvolvido por Rodrigo Garcia em 17/06/2013
FN_LISTASUID()
{
        find / -perm -4000 2> /dev/null | egrep -v "/passwd|/sudo|/su|/sudoedit" > suid.txt
        if [ $? = 0 ]
        then
                cat suid.txt
        else
                echo "Não há arquivos com SUID BIT ligado no sistema!!!"
                exit 0
        fi
}
FN_RMSUID()
{
        FN_LISTASUID
        echo -n "Deseja realmente remover o SUID BIT dos arquivos listados (S/n)?: "
        read RESPOSTA
        if [ -z $RESPOSTA ]
        then
                RESPOSTA=$(echo "s")
        fi
        case $RESPOSTA in
        s)
                while read line
                do
                        chmod -s $line
                done < "suid.txt"
                echo "SUID BIT removido com sucesso!!!"
                ;;
        n)
                exit
                ;;
        *)
                echo "Opcao Invalida!!!"
                exit
                ;;
        esac
}
FN_HLP()
{
        echo "Script para remover SUID BIT de Binários GNU/Linux"
        echo "Desenvolvido por Rodrigo Garcia em 17/06/2013"
        echo "Use $0 [opcao]"
        echo "-l --lista        Lista os binários com SUID BIT ligado;"
        echo "-r --remove       Lista os binários com SUID BIT ligado e remove a permissão;"
        echo "-h --help Mostra essa mensagem;"
}
case $1 in
-l)
        FN_LISTASUID
        exit
        ;;
--lista)
        FN_LISTASUID
        exit
        ;;
-r)
        FN_RMSUID
        ;;
--remove)
        FN_RMSUID
        ;;
-h)
        FN_HLP
        ;;
--help)
        FN_HLP
        ;;
*)
        echo "Use $0 [opcao] -h ou --help para mais informacoes"
        exit
        ;;
esac

Salve-o como /root/admin_scripts/rmsuid.sh e dê permissão de execução (chmod +x rmsuid.sh). Sua execução é bem simples, ./rmsuid.sh --lista ou (-l) busca no sistema os arquivos que não precisam de SUID BIT ligado, salva a lista em um arquivo texto e mostra na tela. A opção --remove (ou -r) mostra os arquivos e confirma a remoção de SUID BIT dos arquivos desnecessários, e pronto!

Agora vamos em busca dos pacotes desnecessários que estão instalados no sistema. Temos um script também que faz isso:

#!/bin/bash
dpkg -l | awk 'NR >= 6 { print $1 FS $2 }' > pacotes.txt

Esse script lista todos os pacotes do sistema e salva seu nome e sua versão no arquivo pacotes.txt para ser analisado, e então coerentemente o administrador removerá os pacotes (por exemplo, se o pacote "apache2" estiver instalado no firewall, é melhor removê-lo). Salve-o como /root/admin_scripts/pacotes.sh e dê permissão de execução.

Em seguida, precisamos manter acesso externo ao firewall para que possamos administrá-lo remotamente (sempre existirá essa necessidade). Mas não podemos deixar a porta 22 do SSH aberta direto, pois sofreremos muitas tentativas de invasão. Então vamos começar mudando a porta padrão do SSH por outra aleatória (recomendo acima da porta 1024). Para isso precisamos editar o arquivo /etc/ssh/sshd_config e alterar a linha:

Port 22

Para:

Port "porta qualquer acima da 1024"

Mas isso ainda não resolve o nosso problema, pois teremos sempre a porta de conexão do SSH que escolhermos aberta para a internet. A solução encontrada aqui é o uso da ferramenta "knockd" que trabalha com uma técnica chamada "port knocking" que consiste em uma conbinação de portas do firewall que o cliente tem que "bater" para que outra porta seja aberta, como um cofre que possui uma combinação pré definida. Vamos instalar o knockd:

/root/admin_scripts/noexec.sh stop

aptitude install knockd

/root/admin_scripts/noexec.sh start

Após a instalação, vamos configurar o serviço editando o arquivo /etc/knockd.conf nas seguintes linhas:

[openSSH]
        sequence    = escolher uma sequência aleatória de 3 portas (recomendo acima de 1024), ex: 1028,2056,4112
        seq_timeout = 5
        command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport porta do ssh -j ACCEPT
        tcpflags    = syn

E também as linhas:

[closeSSH]
        sequence    = O inverso da sequência acima, ex: 4112,2056,1028
        seq_timeout = 5
        command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport porta do ssh -j ACCEPT
        tcpflags    = syn

Salvamos o arquivo e saímos. Em seguida devemos editar o arquivo /etc/default/knockd na seguinte linha:

START_KNOCKD=0

Mudar para

START_KNOCKD=1

Essa mudança permite a inicialização do serviço knockd. Após isso iniciamos o serviço:

service knockd start

Na máquina cliente devemos também instalar o knockd mas não precisamos configurar nada, e para utilizá-lo devemos executar o seguinte comando:

knock ip.do.seu.firewall 1028 2056 4112

Isso vai executar o comando do knockd.conf e abrir o firewall para a porta do SSH que definimos. Para terminarmos o acesso, nós saímos do SSH e executamos o mesmo comando invertendo as portas:

knock ip.do.seu.firewall 4112 2056 1028

E a porta será fechada novamente. E para finalizar, apenas a recomendação de executar periodicamente os scripts de busca de SUID BIT e de listagem de pacotes, e sempre manter o sistema operacional atualizado a fim de mantermos o mais seguro possível. Espero ter sido útil!!!

Até a próxima!!!

terça-feira, 25 de junho de 2013

Watch Dog para Nagios

Olá a todos!!!

Como todos já sabem, é possível fazer infinitas customizações no Nagios. Eu mesmo já criei meus próprios plugins usando shell script. Dessa vez, eu tentei algo um pouco mais ousado, que é a criação de um watch dog (sistema automático que detecta falhas e tenta corrigir sozinho) para serviços monitorados pelo Nagios. Na verdade é bem simples, um shell script básico que é executado pelo plugin NRPE. No tutorial que está nesse mesmo blog, vemos que quando utilizamos o NRPE nós configuramos comandos a serem executados no host monitorado através do arquivo nrpe.cfg:

A linha comum para monitorar o Apache num servidor seria:

command[check_http]=/usr/lib/nagios/plugins/check_http -I localhost

O que eu fiz foi criar um script que chama cada comando, ex:

command[check_http]=/usr/lib/nagios/plugins/watch_dog.sh "check_http -I localhost" apache2

Caso o serviço não esteja rodando, ele executa o comando para iniciar o serviço no sistema operacional. Simples, não? Abaixo o script:

#!/bin/bash
# Watch Dog para Nagios 1.0
# Desenvolvido por Rodrigo Garcia em 25/06/2013
# Informe em PDIR="" o caminho para os plugins do Nagios
PDIR="/usr/local/nagios/libexec"
SERV=$(which service)

# O script deve ser chamado colocando como primeiro argumento ($1) o nome do plugin do Nagios e seus argumentos entre aspas
# O segundo argumento ($2) é o nome do serviço a ser executado caso o mesmo não esteja rodando.

$PDIR/$1 $2 > /dev/null

case $? in
"0")
        $PDIR/$1 $2
        ;;
"1")
        $PDIR/$1 $2
        ;;
"2")
        $SERV $2 restart
        if [ $? != "0" ]
        then
                $PDIR/$1 $2
        fi
        ;;
esac

Por enquanto só funciona em Linux. Talvez mais para frente eu desenvolva algo para Windows.
Abraço e até a próxima!!!

sexta-feira, 14 de junho de 2013

Plugin do Nagios para HP-UX

Olá,

Como não encontrei um plugin satisfatório na net que verifcasse a memória no HP-UX eu adaptei um plugin que eu criei para Linux. Abaixo o código para versão 11.31 (para a versão 11.23 mudar o "NR == 5" para "NR == 6"):

#!/sbin/sh
PATH=/sbin:/usr/sbin:/bin:/usr/bin

TMEM=$(swapinfo -tam | awk 'NR == 5 { print $2 }')
UMEM=$(swapinfo -tam | awk 'NR == 5 { print $3 }')
FMEM=$(swapinfo -tam | awk 'NR == 5 { print $4 }')
PMEM=$(echo $(($UMEM * 100 / $TMEM)))

if [ $PMEM -lt $1 ]
        then
                echo "Total(MB)= $TMEM, Livre(MB)= $FMEM Uso(MB)= $UMEM OK|Uso(%)= $PMEM%"
                exit 0
elif [ $PMEM -ge $1  ] && [ $PMEM -lt $2 ]
then
                echo "Total(MB)= $TMEM, Livre(MB)= $FMEM Uso(MB)= $UMEM Atencao!!!|Uso(%)= $PMEM% "
                exit 1
elif [ $PMEM -ge $2 ]
then
                echo "Total(MB)= $TMEM, Livre(MB)= $FMEM Uso(MB)= $UMEM Critico!!!|Uso(%)= $PMEM%"
                exit 2
fi

Espero ter ajudado e até a próxima!!!

quarta-feira, 12 de junho de 2013

Comandos Úteis HP-UX para Administradores Linux

É muito comum acontecer (e aconteceu comigo também) de um administrador Linux pensar que é moleza administrar um sistema Unix HP-UX. Muitos comandos são os mesmos, às vezes muda uma sintaxe ou outra. Porém tem algumas coisas às vezes bem pequenas mas que podem irritar até os mais experientes. Esse pequeno artigo visa ajudar aos que estão habituados com o Linux a se ambientarem no HP-UX.

Para que o backspace funcione (o padrão do sistema é pressionar Esc e em seguida a tecla x para apagar os caracteres) basta digitar o comando:

"stty erase ^?"

E a partir daí já poderá usar o backspace. A dica aqui é incluir esse comando no arquivo .profile que fica na pasta home do usuário, para que sempre que esse usuário logar no sistema, a tecla backspace já fique automaticamente ativada.

O comando "df -h" no Linux nos mostra as partições, os tamanhos, espaço usado, espaço livre, a porcentagem de uso e o ponto de montagem. Esse mesmo comando no HP-UX traz uma saída parecida trazendo o ponto de montagem, a partição e o tamanho em blocos do disco. Para trazer a mesma saída do Linux o comando a ser utilizado é o:

"bdf"

Para mostrar o modelo e arquitetura do servidor, o comando é:

"model"

O HP-UX utiliza pacotes com extensão .depot, e para instalá-los o comando é:

"swinstall -s /caminho/completo/para/o/pacote.depot \*"

Para quem acha que não existe instaladores de pacotes como por exemplo o apt ou yum no HP-UX, eu indico a página http://hpux.connect.org.uk/hppd/packages.html e procure pelo pacote "depothelper" que faz exatamente esse trabalho. A instalação é feita com o comando acima e para executá-lo (como root) o comando é:

"/usr/local/bin/depothelper -h/?"

Quando precisamos desbloquear uma conta de usuário local, devemos executar:

"/usr/lbin/modprpw -k -l usuario"

A opção -k desbloqueia/habilita uma conta, e a opção -l informa ser uma conta local.

Usuários de Linux estão acostumados a iniciar e parar serviços acessando os scripts no diretório "/etc/init.d". Esse padrão não se aplica no HP-UX, mas sim:

"/sbin/init.d"

E os scripts rc (de inicialização) ficam em:

"sbin"

Para sabermos o runlevem do sistema, executamos o comando:

"who -r"

Para completar a nossa linha decomando no Linux usamos a tecla "Tab". No HP-UX utilizamos a tecla "Esc" duas vezes. De forma semelhante, para repetirmos os comandos anteriores no Linux utilizamos a tecla direcional para cima, no HP-UX utilizamos a combinação de teclas "Esc + k".

Para se adicionar um usuário no sistema, o comando é:

"useradd -m usuario"

Para adicionar um usuário a um grupo o comando é:

"usermod -G grupo usuario"

Para os preguiçosos de plantão ou em uma emergência onde não sabe-se os comandos certos, existe uma interface web de administração do sistema. Basta executar o comando:

"smh"

No navegador coloque o ip do servidor seguido da porta 2301:

"http://ip.do.seu.server:2301"

E logue normalmente.

Existe também uma central de administração via shell que é aberta através do comando:

"sam"

Por hoje é só, espero ter sido útil e até a próxima!!!

Fonte: http://www.spritian.com/2012/04/26/useful-hp-ux-commands-for-linux-administrator/

ATUALIZAÇÃO

No sistema Linux, quando precisamos ver a memória total, livre e usada, utilizamos o comando "free". No HP-UX o comando é:

"swapinfo -tam"

quinta-feira, 6 de junho de 2013

Poderes de Super Vaca

Olá a todos,

Muita gente já viu e me perguntou sobre o que significa a mensagem no final da ajuda do APT:

apt-get --help

"Este APT tem poderes de Super Vaca"

 e do Aptitude

aptitude --help

"Este aptitude não contém poderes de Super Vaca"

o que pouca gente sabe é que essas mensagens fazem referência a easter eggs inseridos nos programas. Vamos ao easter egg do APT:

apt-get moo

         (__)
         (oo)
   /------\/
  / |    ||  
 *  /\---/\
    ~~   ~~  
...."Have you mooed today?"...

E é só!

aptitude moo

"Não existem Ovos de Páscoa neste programa."

aptitude moo -v

"Realmente não existem Ovos de Páscoa neste programa."

aptitude moo -vv

"Eu já não lhe disse que não existem Ovos de Páscoa neste programa?"

aptitude moo -vvv

"Pare com isso!"

aptitude moo -vvvv

"Ok, ok, se eu lhe der um Ovo de Páscoa você irá embora?"

aptitude moo -vvvvv

"Tudo bem, você ganhou."

                               /----\
                       -------/      \
                      /               \
                     /                |
   -----------------/                  --------\
   ----------------------------------------------


aptitude moo -vvvvvv


"O que é isso? Isso é um elefante sendo comido por uma cobra, é claro."

E é isso!!! Agora todos sabem o que significa ter ou não poderes de Super Vaca !!!

Abraço e até a próxima!!!

sexta-feira, 24 de maio de 2013

Script de Backup de Arquivos

Olá a todos!!!

Mais uma vez eu trago um script desenvolvido por mim para fazer backup de arquivos de um servidor, compactando-os e salvando-os em um ponto de montagem (de preferência de rede), ele guarda os arquivos de backup por 1 mês e então vai removendo pelo mais antigo. Originalmente esse script possuía 6 linhas (versão 1.0), mas como sempre eu me empolgo e tento fazer o mais completo possível. Eis o script:

#!/bin/bash
##########################################################################
# Script de backup 2.1 (23/05/2013)
# Desenvolvido por Rodrigo Garcia em 19/10/2012
##########################################################################
PATH=/sbin:/usr/sbin:/bin:/usr/bin
##########################################################################
# Informe os arquivos a serem copiados no campo BACKUP="" separados por espaços
##########################################################################
BACKUP=""
##########################################################################
# Informe o ponto de montagem Windows a ser utilizado no backup, ex: "//192.168.0.254/compartilhamento"
##########################################################################
MOUNT=""
##########################################################################
# Informe o username e a senha nos campos abaixo
##########################################################################
USER=""
PASSWD=""
##########################################################################
FN_INS()
{
    echo "Deseja realmente instalar o script de backup (s/n)?"
    read RESPOSTA
    case $RESPOSTA in
        "s")   
            echo "Criando ponto de montagem de rede..."   
            echo "$MOUNT cifs   username=$USER,password=$PASSWD,user,dir_mode=0777,file_mode=0777   0  0 # Backup" >> /etc/fstab
            mkdir /mnt/bkp
            echo "Montando diretório de backup..."
            mount -a
            echo "Script de backup instalado com sucesso!!!"
        ;;
        "n")
            exit
        ;;
        *)
            echo "Opção Inválida!!!"
            exit
        ;;
    esac
}
FN_UNS()
{
    echo "Deseja realmente desinstalar o script de backup (s/n)?"
    read RESPOSTA
    case $RESPOSTA in
        "s")
            echo "Excluindo ponto de montagem de rede..."
            sed -i '/# Backup/d' /etc/fstab
            echo "Desmontando diretório de backup..."
            umount /mnt/bkp
            rm -rf /mnt/bkp
            echo "Script de backup desinstalado com sucesso!!!"
        ;;
        "n")
            exit
        ;;
        *)
            echo "Opção Inválida!!!"
            exit
        ;;
    esac
}
FN_HLP()
{
    echo "Script de Backup de Arquivos 2.1"
    echo "Desenvolvido por Rodrigo Garcia"
    echo "Opções:"
    echo "install    instala automaticamente o ponto de montagem"
    echo "uninstall  remove automaticamente o ponto de montagem"
    echo "run        executa a rotina de backup"
    echo "help       mostra essa mensagem"
}
FN_TAR()
{
        echo "Compactando os arquivos $BACKUP..."
        for BKP in $BACKUP
        do
                tar -Pczf $(hostname)-$(date +%Y-%m-%d).tar.gz $BACKUP
        done
}
FN_CP()
{
        test -d /mnt/bkp/$(hostname)
        if [ $? == 1 ]
        then
                echo "Criando diretorio /mnt/bkp/$(hostname)..."
                mkdir /mnt/bkp/$(hostname)
        fi
        echo "Copiando o backup para a pasta /mnt/bkp/$(hostname)..."
        cp $(hostname)-$(date +%Y-%m-%d).tar.gz /mnt/bkp/$(hostname)
}
FN_RM()
{
        echo "Excluindo arquivo local..."
        rm -rf $(hostname)-$(date +%Y-%m-%d).tar.gz
    echo "Excluindo backups antigos..."
    find /mnt/bkp/$(hostname) -maxdepth 1 -ctime +1 -exec rm -Rf {} \;
}
case $1 in
    "install")
        FN_INS
        exit
    ;;
    "uninstall")
        FN_UNS
        exit
    ;;
    "run")
        FN_TAR
        FN_CP
        FN_RM
        echo "Backup Executado Com Sucesso!!!"
        exit
    ;;
    "help")
        FN_HLP
        exit
    ;;
    *)
        echo "Use $0 {install|uninstall|run|help}"
        exit
    ;;
esac

Espero que seja útil, e até a próxima!!!

segunda-feira, 22 de abril de 2013

Firewall Corporativo com IPtables


Olá a todos!

Como prometido, nesse post eu vou colocar um script para firewall corporativo. Obviamente que eu vou explicar a estrutura do script e o porquê de fazer algumas coisas e não fazer outras. Em primeiro lugar eu quero explicar que nesse script eu não coloquei comandos para carregar módulos, nem para setar opções no kernel, etc, por pensar que essas configurações se tratam do sistema operacional em si e não do firewall como eu vejo muitos fazendo. O firewall foi criado com pequenas particularidades pensando no Debian, mas no geral funciona em qualquer outra distribuição.

1ª Parte:

#!/bin/bash
#
# ## BEGIN INIT INFO
# Provides : Firewall
# Required - Start : networking
# Required - Stop :
# Should - Start : S
# Should - Stop :
# Default - Start : 2 3 4 5
# Default - Stop :
# Short - Description : Firewall - Rodrigo Garcia
# Description : Firewall - Rodrigo Garcia
#
# ## END INIT INFO
################################################################################################
# 1- VARIAVEIS
################################################################################################
IPT=$(which iptables)
HIPRT="1024:65535"
################################################################################################
# 1.1- EXTERNO - Informe a placa de rede externa em IFEXT="" e o IP externo em IPEXT=""
################################################################################################
IFEXT=""
IPEXT=""
################################################################################################
# 1.2- INTERNO - Informe a placa de rede interna em IFINT="" e o ip interno em IPINT=""
################################################################################################
IFINT=""
IPINT=""
################################################################################################
# 1.3- Redes - Informe o IP da WAN (geralmente 0/0) em IPWAN="" e o IP da rede interna (CIDR) em IPLAN=""
################################################################################################
IPWAN=""
IPLAN=""
################################################################################################
# 1.4- Informe em OPENP="" as portas abertas no firewall no formato "porta:protocolo:origem", ex: 22:tcp:192.168.0.2
# e as portas encaminhadas em FRWDP="" como "porta:protocolo:destino:porta", ex: 80:tcp:192.168.0.3:80
# As portas de saída devem ser informadas em OUTPT="" no formato porta:protocolo:destino, ex: 53:udp:0/0 ou 53:udp:$IPWAN
# As portas que devem ser priorizadas, devem ser informadas em TOSPT="" apenas com o numero ex: TOSPT="22 80 443"
################################################################################################
OPENP=""
FRWDP=""
OUTPT=""
TOSPT=""
################################################################################################


No bloco acima, as linhas de 3 a 14 são tags usadas para configurar o script para subir com o sistema operacional. Deve-se colocar o script (já com permissão de execução) em /etc/init.d/ e executar o comando insserv -d firewall . Isso adicionará a sua execução nos runlevels de inicialização.

A primeira seção (1- VARIAVEIS) estão as variáveis globais que serão usadas no script. Começamos com a variável $IPT que já foi explicada no post anterior sobre firewall pessoal. O diferencial está na seção 1.4 que traz as portas que você quer abrir no firewall e as que quer encaminhar para dentro de sua rede, e as portas de saída do firewall e as portas cujos pacotes devem ser priorizados.


################################################################################################
# 2- POLITICA DROP
################################################################################################
FN_DROP()
{
    for CHAIN in INPUT OUTPUT FORWARD
    do
        $IPT -P $CHAIN DROP
    done
}
################################################################################################
# 3- POLITICA ACCEPT
################################################################################################
FN_ACCEPT()
{
    for CHAIN in INPUT OUTPUT FORWARD
    do
        $IPT -P $CHAIN ACCEPT
    done
}
################################################################################################
# 4- LIMPAR FIREWALL
################################################################################################
FN_LIMPA()
{
    for TABLE in filter nat mangle
    do
        $IPT -t $TABLE -X
        $IPT -t $TABLE -F
    done
}
################################################################################################
# 5- LIBERAR LOCALHOST
################################################################################################
FN_LOCAL()
{
    $IPT -I INPUT -i lo -d 127.0.0.1 -j ACCEPT
    $IPT -I OUTPUT -o lo -s 127.0.0.1 -j ACCEPT
}
################################################################################################
# 6- LIBERAR CONEXOES
################################################################################################
FN_CONN()
{
    for CHAIN in INPUT OUTPUT FORWARD
    do
        $IPT -A $CHAIN -m state --state ESTABLISHED,RELATED -j ACCEPT
    done
}
################################################################################################
# 7- ENCAMINHAR REDES
################################################################################################
FN_FRWD()
{
    for FROM in -s -d
    do
        $IPT -A FORWARD $FROM $IPLAN -j ACCEPT
    done
}
################################################################################################
# 8- PING
################################################################################################
FN_PING()
{
    for TYPE in "0" "8"

    do    
         $IPT -A INPUT -i $IFINT -p icmp -s $IPLAN -d $IPINT --icmp-type $TYPE -j ACCEPT
        
$IPT -A OUTPUT -o $IFINT -p icmp -s $IPINT -d $IPLAN --icmp-type $TYPE -j ACCEPT
    done
    $IPT -A INPUT -i $IFEXT -p icmp -s $IPWAN -d $IPEXT --icmp-type 0 -j ACCEPT
    $IPT -A OUTPUT -o $IFEXT -p icmp -s $IPEXT -d $IPWAN --icmp-type 8 -j ACCEPT
}
################################################################################################



O bloco de comandos acima foi feito todo no formato de funções. Por que? Fica muito mais fácil de manupular a estrutura do firewall dessa forma, e podemos facilmente alterar a ordem de execução das funções além de servir para complementarmos com parâmetros de execução do script na parte final. Os comandos acima são os mais básicos para qualquer firewall como liberar comunicação com localhost, permitir entrada de ping só da rede interna, e resposta de ping de todos, encaminhar os pacotes para as redes, etc. Deve ser notado que os comandos utilizam as variáveis locais para facilitar a criação das regras e posteriormente a alteração de IPs, interfaces, etc sem precisar mudar em cada regra.

################################################################################################
# 9- PORTAS DE SAIDA
################################################################################################
FN_OUTPT()
{
    for PORTA in $OUTPT
    do
        PORT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $1 }')

        PROT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $2 }')
        DEST=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $3 }')
        if [ -z $PROT ]
        then
            PROT="tcp"
        fi
        if [ -z $DEST ]
        then
            DEST="$IPWAN"
        fi
        NET=$(echo "$IPLAN" | awk 'BEGIN { FS = "." } ; { print $1 FS $2 FS $3 FS "*"}')

        case $DEST in
        $NET)
            IF=$(echo $IFINT)

            IP=$(echo $IPINT)
        ;;
        *)
            IF=$(echo $IFEXT)

            IP=$(echo $IPEXT)
        ;;
        esac
        $IPT -A INPUT -i $IF -p $PROT -s $DEST --sport $PORT -d $IP --dport $HIPRT -j ACCEPT
        $IPT -A OUTPUT -o $IF -p $PROT -s $IP --sport $HIPRT -d $DEST --dport $PORT -j ACCEPT
    done
}
################################################################################################


 A função acima abre portas para saída do firewall para serviços externos como cosultar um DNS ou instalar pacotes por repositórios, etc.


################################################################################################
# 10- ABRIR PORTAS
################################################################################################
FN_OPENP()
{
    for PORTA in $OPENP
    do
        PORT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $1 }')

        PROT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $2 }')
        FROM=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $3 }')
        if [ -z $PROT ]
        then
            PROT="tcp"
        fi
        if [ -z $FROM ]
        then
            FROM="$IPINT"
        fi
        NET=$(echo "$IPLAN" | awk 'BEGIN { FS = "." } ; { print $1 FS $2 FS $3 FS "*"}')

        case $FROM in
        $NET)
            IF=$(echo $IFINT)

            IP=$(echo $IPINT)
         ;;
        *)
            IF=$(echo $IFEXT)

            IP=$(echo $IPEXT)
        ;;
        esac
        $IPT -A INPUT -i $IF -p $PROT -s $FROM --sport $HIPRT -d $IP --dport $PORT -j ACCEPT
        $IPT -A OUTPUT -o $IF -p $PROT -s $IP --sport $PORT -d $FROM --dport $HIPRT -j ACCEPT
    done
}
################################################################################################


A função acima é a responsável pela abertura das portas no firewall, definindo o protocolo e a origem caso nao sejam especificados na variável, e decidindo qual interface de rede utilizar de acordo com a origem da comunicação.

################################################################################################
# 11- ENCAMINHAR PORTAS
################################################################################################
FN_FWDP()
{
    for PORTA in $FRWDP
    do
        PORT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $1 }')

        PROT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $2 }')
        FWSV=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $3 }')
        FWPT=$(echo $PORTA | awk 'BEGIN { FS = ":" } ; { print $4 }')
        if [ -z $PROT ]
        then
            PROT="tcp"
        fi
        if [ -z $FWPT ]
        then
            FWPT=$(echo $PORT)

        fi
        $IPT -t nat -A PREROUTING -i $IFEXT -p $PROT -s $IPWAN --sport $HIPRT -d $IPEXT --dport $PORT -j DNAT --to $FWSV:$FWPT
    done
}
################################################################################################

Acima temos a função de encaminhamento das portas para a rede interna, e assim como a função de abertura de portas, ela também define o protocolo caso não seja especificado nq variável. Em ambas as funções eu fiz uso do AWK, uma linguagem de edição de textos muito útil e versátil que pode facilitar em muito a vida de um Sysadmin.

################################################################################################
# 12- TOS - PRIORIZACAO DE PACOTES
################################################################################################
FN_TOS()
{
    for PORTA in $TOSPT
    do
        $IPT -t mangle -A PREROUTING -i $IFEXT -p tcp -s $IPWAN -d $IPEXT --sport $PORTA -j TOS --set-tos 16
        $IPT -t mangle -A OUTPUT -o $IFEXT -p tcp -s $IPEXT -d $IPWAN --dport $PORTA -j TOS --set-tos 16
    done
}
################################################################################################


O bloco acima faz a parte de priorização dos pacotes.

################################################################################################
# 13- COMPARTILHAR INTERNET
################################################################################################
FN_SNAT()
{
    $IPT -t nat -A POSTROUTING -o $IFEXT -s $IPLAN -j SNAT --to $IPEXT
}
################################################################################################



Aqui nós temos uma função de compartilhamento da Internet usando SNAT ao invés do MASQUERADE (que é recomendado para IPs dinâmicos).


################################################################################################
# 14- LOG
################################################################################################
FN_LOG()
{
    echo "$0 $1 Executado em $(date +%d-%m-%Y-%H:%M:%S)" 2>&1 >> /var/log/firewall.log
}
################################################################################################


Acima temos a criação de logs de execução em /var/log/firewall.log


################################################################################################
# 15- EXECUCAO DO FIREWALL
################################################################################################
case $1 in
start)
    FN_DROP
    FN_LIMPA
    FN_LOCAL
    FN_CONN
    FN_FRWD
    FN_PING
    FN_OUTPT
    FN_OPENP
    FN_FWDP
    FN_TOS
    FN_SNAT
    FN_LOG "start"
    echo "Starting IPTables Firewall Rules: firewall."
;;
stop)
    FN_ACCEPT
    FN_LIMPA
    FN_LOG "stop"
    echo "Stopping IPTables Firewall Rules: firewall."
;;
restart)
    $0 stop
    $0 start
;;
*)
    echo "Use $0 {start|stop|restart}"
;;
esac


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

Acima temos toda a ordem de execução de cada função, e a forma de execução do firewall através dos parâmetros start, stop ou restart.

Espero ter sido útil, e até a próxima!!!

sábado, 6 de abril de 2013

Firewall Pessoal

Olá a todos!!!

Nesse post eu vou mostrar algo muito simples e útil, que é um firewall pessoal através do IPTables. O IPTables é um front-end para o módulo Netfilter do kernel do Linux.

Ele possui 4 tabelas, a Filter, que é a padrão (controla o tráfego básico de entrada, saída e encaminhamento do firewall), a tabela NAT (responsável por tradução de endereços de redes), a tabela Mangle (que é responsável por regras de ações especiais a serem tomadas pelo firewall) e a tabela RAW (controle de pacotes).

Neste firewall, usaremos apenas a tabela Filter, conforme veremos a seguir. Geralmente (nos sistemas baseados em Debian), o IPTables não contém nenhuma regra e a política do firewall é a ACCEPT, que aceita todos os pacotes de entrada, saída e encaminhamento. Entretando, nos sistemas baseados em Red Hat por exemplo, o firewall possui já algumas regras criadas na instalação do SO. Vamos trabalhar como se já houvessem regras preexistentes.

A primeira ação a ser tomada é limpar todas as regras de todas as tabelas do firewall:

iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

A opção "-F" é a mesma de "--flush" e vai limpar todas as tabelas, e a opção "-X" vai excluir todas as chains personalizadas préexistentes. A seguir, vamos aplicar a política "DROP" no firewall, que vai negar qualquer conexão por padrão:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

O que foi feito acima foi bloquear qualquer conexão de entrada e de encaminhamento no firewall, e permitir todas as conexões de saída. Nesse momento você não conseguirá estabelecer conexão nenhuma, pois conseguirá enviar pacotes de saída, mas não conseguirá receber respostas.

A primeira coisa que devemos liberar no firewall é o localhost:

iptables -A INPUT -i lo -j ACCEPT

Em seguida, devemos liberar as conexões que você estabeleceu, para que haja entrada de respostas de pacotes:

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Agora o próximo passo é liberar a entrada de respostas de ping, e solicitações de ping da rede interna (opcional)

iptables -A INPUT -p icmp --icmp-type 0 -j ACCEPT
iptables -A INPUT -p icmp -s ip.da.rede.interna/máscara --icmp-type 8 -j ACCEPT

O que vamos fazer agora, é liberar as respostas de servidores de DNS externos:

iptables -A INPUT -p udp -s 0/0 --sport 53 -j ACCEPT


Vimos que agora o comando teve algumas novidades:

-s 0/0 = Significa qualquer origem com qualquer máscara de rede
--sport = Significa uma conexão que tem como origem a porta 53 (DNS)

A partir desse momento, você já conseguirá executar com sucesso ping nas pelo nome do endereço que você quiser. Então vamos agora liberar a navegação web:

iptables -A INPUT -p tcp -s 0/0 --sport 80 -j ACCEPT
iptables -A INPUT -p tcp -s 0/0 --sport 443 -j ACCEPT

Pronto! Você já consegue também navegar na internet! Esses são os passos da criação de um firewall pessoal básico, que você mesmo pode personalizar de acordo com suas necessidades. Por exemplo, se quiser acessar algum serviço externo, deverá criar uma regra assim:

iptables -A INPUT -p tcp -s 0/0 --sport "porta do serviço" -j ACCEPT

E se quiser liberar na sua máquina o acesso a um serviço SSh de dentro da rede, deverá criar uma regra como essa:

iptables -A INPUT -p tcp -s ip.da.rede.interna/máscara --dport 22 -j ACCEPT

Para facilitar, eu gosto de criar scripts que aplicam todas essas regras automaticamente e facilitam na adição de novas regras com o uso de variáveis. Por exemplo:

#!/bin/bash
# Script de Firewall criado por Rodrigo Garcia - www.unix4life.blogspot.com
##############################################################
# 1 - VARIÁVEIS
##############################################################
IPT=$(which iptables) # Isso diminui a sua digitação, e traz maior segurança
IF_INT="eth0" # Colocar aqui o nome da placa de rede interna
IP_INT="`ifconfig $IF_INT | awk 'NR == 2{ print $3 }'`"
NET_INT="192.168.0.0/24" # IP da rede interna
##############################################################
# 2 - LIMPAR FIREWALL
##############################################################
for TABLE in filter nat mangle raw
do
$IPT -t $TABLE -F
$IPT -t $TABLE -X
done
##############################################################
# 3 - APLICAR POLITICAS
##############################################################
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT ACCEPT
##############################################################
# 4 - LIBERAR LOCALHOST
##############################################################
$IPT -A INPUT -i lo -j ACCEPT
##############################################################
# 5 - LIBERAR CONEXÕES ESTABELECIDAS
##############################################################
$IPT -A INPUT -i $IF_INT -m state --state ESTABLISHED,RELATED -j ACCEPT
##############################################################
# 6 - ECHO REPLY E ECHO REQUEST VINDO DA REDE INTERNA
##############################################################
$IPT -A INPUT -p icmp --icmp-type 0 -j ACCEPT
$IPT -A INPUT -i $IF_INT -p icmp -s $NET_INT --icmp-type 8 -j ACCEPT
##############################################################
# 7 - LIBERAR RESPOSTAS DE DNS
##############################################################
$IPT -A INPUT -i $IF_INT -p udp -s 0/0 --sport 53 -j ACCEPT
##############################################################
# 8 - LIBERAR NAVEGAÇÃO WEB
##############################################################
$IPT -A INPUT -i $IF_INT -p tcp --sport 80 -j ACCEPT
$IPT -A INPUT -i $IF_INT -p tcp --sport 443 -j ACCEPT
##############################################################

E assim terminamos nosso script! Podemos adicioná-lo na inicialização do sistema editando arquivo /etc/rc.local e adicionando o caminho absoluto para o script.

No próximo post vou colocar um script de firewall para redes corporativas. Até a próxima!!!

quinta-feira, 21 de fevereiro de 2013

IPSec

Olá a todos,

Meu último desafio (nem foi tão grande assim) foi conectar uma unidade do litoral à nossa sede. Os usuários se conectavam via PPTP, mas não estava muito legal dessa forma. A solução encontrada por mim era criar um tunel site-to-site através de IPSec.

Para a unidade, foi utilizado um roteador Cisco RV042 pelo fato de ser uma unidade bem pequena não tendo muito espaço para comportar equipamentos maiores (como é de minha preferência). Na sede eu utilizei uma máquina com Ubuntu Server.

Na ponta da sede o que eu fiz foi instalar o pacote "OpenSwan":

apt-get install openswan

E editar os seguintes arquivos:

/etc/ipsec.conf

config setup
        plutodebug=all
        #nat_traversal=on # Caso a máquina que conectará esteja atrás de um firewall
        oe=off
        protostack=netkey
        interfaces=%none

conn Unidade  # Trocar o nome "Unidade" para qualquer outro que desejar
        left=0.0.0.0  # IP público local
        leftsourceip=1.1.1.1 # IP da máquina que fará a conexão
        leftsubnet=1.1.1.0/24 # IP da rede que a outra ponta deverá enxergar
        leftnexthop=0.0.0.1 # gateway do IP público local
        right=2.2.2.2 # IP público da unidade
        rightsourceip=3.3.3.3 # IP da máquina da unidade que fará a conexão
        rightsubnet=3.3.3.0/24 # IP da rede da unidade
        rightnexthop=2.2.2.1 # Gateway do IP público da unidade
        authby=secret
        auto=start
        auth=esp
        rekey=yes
        keyingtries=0
        keyexchange=ike
        ike=3des-md5;modp1024
        ikelifetime=3600s
        esp=3des-md5;modp1024
        keylife=28800s
        pfs=no

Em seguida devemos configurar o arquivo /etc/ipsec.secrets (no ubuntu, o arquivo é /var/lib/openswan/ipsec.secrets.inc)

0.0.0.0 %any : PSK "chavequevocequiser"

A configuração acima permite que qualquer máquina que tenha as configurações adequadas e a mesma chave configurada acima se conecte no tunel. Caso não queira essa configuração basta alterar "%any" para o IP público da outra ponta.

Caso o tunel esteja configurado no firewall, é necessário adicionar a seguinte regra:

iptables -A INPUT -p udp --dport 500 -j accept

Caso esteja em uma máquina atrás do firewall, a regra muda para:

iptables -t nat -A PREROUTING -p udp -d ip_publico --dport 500 -j DNAT --to ip_da_máquina

E também essa:

iptables -t nat -A PREROUTING -p udp -d ip_publico --dport 4500 -j DNAT --to ip_da_máquina

Agora é só configurar a outra ponta que pode ser outra máquina linux ou um equipamento como o Cisco RV042, utilizando as mesmas configurações porém não esquecendo de fazer as devidas alterações de IPs.

Lembrando que essa é uma VPN básica, existem muito mais recursos de segurança a serem explorados, e cabe a cada um decidir o que é necessário para cada caso.

Espero que tenha sido útil,

Até a próxima!!!

quarta-feira, 9 de janeiro de 2013

Script Para Redundancia Atualizado

Olá a todos!!!

Criei uma versão melhor do script de redundância de links dedicados, e a diferença agora é que ele testa apenas o link principal e caso esteja offline, ele muda para o link secundário. Quando o link principal volta, o script retorna para ele.

#!/bin/bash
# Script de redundancia de links dedicados
# Desenvolvido por Rodrigo Manzzato Alves Garcia em 08/10/2012
# Atualizado em 20/12/2012

PATH=/sbin:/usr/sbin:/bin:/usr/bin

# Informe abaixo o gateway principal
GW_PRIMARIO=""
# Informe abaixo os IPs primários de teste
IP_TESTE_PRIMARIO1=""
IP_TESTE_PRIMARIO2=""
# Informe abaixo o IP do link primario
IP_PRIMARIO_ROUTER=""
# Informe abaixo o gateway do link secundario
GW_SECUNDARIO=""
# Informe abaixo o IP do link secundario
IP_SECUNDARIO_ROUTER=""

# Armazenar gateway padrao na variavel GW_ATUAL
GW_ATUAL=`netstat -nr | awk '$1 ~ /^[0.0.0.0]/ {print $2}'`

# ATENCAO!!! A secao abaixo so deve ser alterada com absoluta certeza de que sabe o que esta fazendo!!!

# Funcao para troca do gateway
function GATEWAY()
{
        netstat -nr | awk -v gw2="$GW2" -v gw="$GW" 'NR > 1 {if ($2 == gw2) print "route add -net " $1 FS "netmask " $3 " gw " gw > "/etc/network/gateway";}'
        netstat -nr | awk -v gw2="$GW2" 'NR > 2 {if ($2 == gw2) print "route del -net " $1 FS "netmask " $3 " gw " gw2 > "/etc/network/gateway_del";}'
    while read ROTA2
        do
                echo -e "`$ROTA2`"
        done < /etc/network/gateway_del
    while read ROTA
        do
                echo -e "`$ROTA`"
        done < /etc/network/gateway
}

# Backup das rotas existentes
echo "#!/bin/bash" > /etc/network/rotas.sh
netstat -nr | awk 'length($2) > 7' | awk 'NR > 1 {print "route add -net " $1 FS "netmask " $3 " gw " $2}' >> /etc/network/rotas.sh

# Teste das redes
ping -c4 $IP_TESTE_PRIMARIO1 -I $IP_PRIMARIO_ROUTER >> /dev/null
    if [ $? = "0" ]
        then   
            if [ $GW_ATUAL = "$GW_PRINCIPAL" ]
                then           
                    exit
                else    # Troca de Gateway caso o link atual não for o principal
                    GW=$GW_PRIMARIO
                    GW2=$GW_SECUNDARIO
                    GATEWAY
                    echo `date` "Rede Principal Ativada" >> /etc/network/gateway.log
                    exit
            fi
        else   
            ping -c4 $IP_TESTE_PRIMARIO2 -I $IP_PRIMARIO_ROUTER >> /dev/null
            if [ $? = "0" ]
                then   
                    exit
                else    # Troca de Gateway caso o link atual não estiver respondendo
                    GW=$GW_SECUNDARIO
                    GW2=$GW_PRIMARIO
                    GATEWAY
                    echo `date` "Rede Secundaria Ativada" >> /etc/network/gateway.log
                    exit
            fi
    fi

Espero que seja útil!!!

Até a próxima!!!

quarta-feira, 2 de janeiro de 2013

Plugin para Nagios

Olá a Todos!!!

Recentemente instalei o Nagios a fim de monitorar meus servidores e roteadores. Senti falta porém de um plugin que checasse a memória ram. Desenvolvi então um plugin em shell script chamado "check_ram":

#!/bin/bash
# Desenvolvido por Rodrigo Garcia em 16/01/2013
# Sobrevivi ao fim do mundo!!!
PATH=/sbin:/usr/sbin:/bin:/usr/bin

TMEM=`free -m | awk 'NR == 2 {print $2}'`
UMEM=`free -m | awk 'NR == 3 {print $3}'`
FMEM=`free -m | awk 'NR == 3 {print $4}'`
PMEM=`echo $((UMEM * 100 / $TMEM))`


if [ $PMEM -lt $1 ]
        then
                echo "Total(MB)= $TMEM, Uso(MB)= $PMEM%, Livre(MB)= $FMEM OK"
                exit 0
        elif [ $PMEM -ge $1  ] && [ $PMEM -lt $2 ]
                then
                        echo "Total(MB)= $TMEM, Uso= $PMEM% , Livre(MB)= $FMEM Atencao!!!"
                        exit 1
        elif [ $PMEM -ge $1 ]
                then
                        echo "Total(MB)= $TMEM, Uso(MB)= $PMEM%, Livre(MB)= $FMEM Critico!!!"
                        exit 2
fi

Sua execução deve conter como parâmetro os níveis de warning e critical pelo valor da porcentagem, por exemplo:

./check_ram 80 90

É isso aí, espero que seja útil!!!

Até a próxima!!!