DevSecOps

14 ago, 2009

Analisando o Three-Way Handshake

Publicidade

Neste artigo, iremos verificar na prática o tão famoso processo three-way handshake, utilizado para o estabelecimento de conexões tcp.

Por que digo que será na prática? Porque iremos utilizar o Wireshark para analisar um conjunto de pacotes que foram trocados durante o estabelecimento de uma conexão; para ver a teoria que envolve o three-way handshare, sugiro consultar a Wikipedia.

Ao final, também veremos como utilizar as informações adquiridas para elevar o nível de segurança em regras de um Firewall em Linux.

Analisando o Three-Way Handshake

Primeiramente, é preciso ter o Wireshark instalado; em seguida, iremos fazer o download do arquivo tcpshake.zip, que contém uma seqüência inicial de estabelecimento de conexão TCP. Depois, iremos descompactá-lo e abrir o arquivo tcpshake.cap através do Wireshark.

Selecionando o primeiro pacote, veremos seus detalhes na janela abaixo. Vamos expandir o último cabeçalho, Transmission Control Protocol (TCP); ali, vemos a informação Flags: 0x02 (SYN).

Isso significa que este primeiro pacote está tentando estabelecer uma conexão; ou seja, o endereço de origem (IP 130.57.20.10, que chamaremos de cliente) através da porta TCP 1026 está tentando conectar-se à porta TCP 524 no endereço de destino (IP 130.57.20.1, que chamaremos de Servidor); estas informações constam no cabeçalho anterior, Internet Protocol (IP).

Em seguida, vamos selecionar o segundo pacote na janela superior; abaixo, no Cabeçalho TCP, temos a informação Flags: 0x12 (SYN, ACK).

Isso significa que o Servidor aceitou a conexão naquela porta (ou seja, há um serviço respondendo às requisições) e enviou um aceite (ACKnowledgement) ao cliente.

Ao selecionarmos o terceiro pacote na janela superior temos, no Cabeçalho TCP, a informação Flags: 0x10 (ACK).

Ou seja, o cliente informa ao Servidor que recebeu seu aceite, e que pode estabelecer a conexão.

São trocados três pacotes iniciais para o estabelecimento de uma conexão, então, temos aí o Three-Way Handshake (ou, traduzindo, aperto de mão de três vias).

Se qualquer um destes pacotes for perdido, a conexão não poderá ser estabelecida.

Mas como podemos melhorar a segurança em regras de Firewall Linux?

Ambiente proposto

Vamos supor que precisamos liberar aos usuários da rede interna acesso a um Servidor de Correio que está localizado na Internet (geralmente, em um provedor). Assim, para que os usuários possam enviar e receber seus emails, devem ser liberadas as portas 25 e 110. Então, supondo que o endereço IP do Servidor de Correio seja 200.200.200.20, criamos as seguintes regras no Firewall:

iptables -A FORWARD -s 192.168.0.0/24 -d 200.200.200.20 --dport  25 -j ACCEPT
iptables -A FORWARD -d 192.168.0.0/24 -s 200.200.200.20 --sport 25 -j ACCEPT
iptables -A FORWARD -s 192.168.0.0/24 -d 200.200.200.20 --dport 110 -j ACCEPT
iptables -A FORWARD -d 192.168.0.0/24 -s 200.200.200.20 --sport 110 -j ACCEPT

Deste modo, liberamos as máquinas para acessar as portas necessárias, e também o retorno das conexões (lembre-se do three-way handshake).

Observação: para alguns isso pode parecer estranho, mas já vi regras criadas exatamente desta maneira.

Porém, nas regras de retorno, abrimos uma brecha de segurança: se alguém tomar o controle do Servidor do Provedor, e iniciar uma conexão através dele, utilizando uma das portas liberadas (25 ou 110) como origem, este Servidor poderá conectar-se à QUALQUER porta de qualquer máquina da rede Interna. E isso não é bom.

Tentando estabelecer uma conexão com uma máquina na rede Interna (um servidor de email local, por exemplo) utilizando uma porta randômica (determinada pelo Sistema Operacional), teremos o seguinte:

# telnet 192.168.0.9 25
Trying 192.168.0.9...
telnet: Unable to connect to remote host: Connection timed out

A tentativa atingirá o tempo limite (timeout) e será encerrada.

Porém, se a porta de origem especificada for uma das portas liberadas (a porta 25, por exemplo), teremos:

# nc -p 25 192.168.0.9 25
220 localhost.localdomain ESMTP Sendmail 8.14.3/8.14.3; Thu, 13 Aug 2009 00:46:05 -0400

Pronto! Conexão estabelecida.

Nota: Obviamente, há um pouco de exagero aqui; neste cenário fictício, para que alguém possa entrar em um Servidor na rede interna através do Provedor, é necessário que haja também uma regra de DNAT no Firewall Linux, permitindo que um endereço válido na Internet seja traduzido para um endereço interno. De qualquer forma, estamos caminhando para tornar as regras mais seguras.

Então, o que podemos melhorar nestas regras?

Podemos configurar as regras de retorno para que não aceitem que as conexões sejam iniciadas a partir do provedor. Elas, então, ficariam desta maneira:

iptables -A FORWARD -s 192.168.0.0/24 -d 200.200.200.20 --dport  25         -j ACCEPT
iptables -A FORWARD -d 192.168.0.0/24 -s 200.200.200.20 --sport 25 ! --syn -j ACCEPT
iptables -A FORWARD -s 192.168.0.0/24 -d 200.200.200.20 --dport 110 -j ACCEPT
iptables -A FORWARD -d 192.168.0.0/24 -s 200.200.200.20 --sport 110 ! --syn -j ACCEPT

Onde o ! –syn significa que somente pacotes com a flag SYN desabilitada satisfazem a regra.

Com as novas regras configuradas, a mesma tentativa de conexão executada anteriormente resultará em:

# nc -p 25 192.168.0.9 25
(UNKNOWN) [192.168.0.9] 25 (smtp) : Connection timed out

As conexões originadas na rede local com destino ao servidor do provedor terão sucesso; porém, conexões originadas no provedor com destino à rede interna não serão estabelecidas.

Conclusão

Através do Wireshark e de uma captura exemplo, analisamos o processo de estabelecimento de uma conexão tcp; além disso, utilizamos as informações que adquirimos para elevar o nível de segurança de regras de um firewall linux.

Neste artigo, também foi utilizado o netcat para estabelecer uma conexão com uma porta de origem pré-determinada. Mais informações sobre ele podem ser obtidas aqui.

Até a próxima!