iptables: corresponde apenas ao primeiro pacote de conexão TCP estabelecida

2

Nos meus arquivos de log do Apache, eu encontro muitas entradas que contêm "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 ou lixo similar. Eles vêm de conexões não-RFC2616 (HTTP / 1.1 sem nome de host).

Não quero que meus arquivos de log sejam spamados com essas mensagens. Então eu quero rejeitar essas conexões usando o iptables. Portanto, eu quero procurar pela string "HTTP / 1.1" seguida por dois CR / LFs subsequentes (CR / LF / CR / LF) (o que dá no total a string hexagonal 485454502f312e310d0a0d0a ) na carga útil dos pacotes.

Mas é estúpido desperdiçar ciclos de CPU procurando por essa string em todos os pacotes TPC quando eu sei que está no primeiro pacote. Ele até estaria errado porque "HTTP / 1.1" seguido por dois CR / LFs subseqüentes pode ser uma parte legal da transmissão dentro da carga útil de solicitações http.

Aqui, o link é uma solução para esse problema, mas não entendo a parte que identifica o primeiro pacote de uma conexão tcp estabelecida.

O que não entendo é por que todos os 3 pacotes do TCP-Handshake inicial (SYN, ACK + SYN, ACK) podem ser vistos na cadeia INPUT ou em uma cadeia que só pode ser alcançada a partir do INPUT. Até onde entendi o iptables e suas cadeias, o segundo pacote (ACK + SYN) nunca passa por INPUT. Eu acho que passa OUTPUT porque é eu (ou seja, o servidor) que está enviando.

Este é o script do spamcleaner.org, eu mudei apenas alguns comentários na primeira parte do script, mas deixei todos os comandos inalterados:

#!/bin/bash

# allow loopback
iptables -A INPUT -i lo -j ACCEPT

# DROP any IP that is in the blacklist "w00tlist" and set the
# blacklist-timeout to 6 hour
iptables -A INPUT -p tcp -m recent --name w00tlist --update --seconds 21600 -j DROP

# create the chain "w00tchain"
iptables -N w00tchain

# this chain will add the IP to the blacklist "w00tlist"
# and will reset the connection:
iptables -A w00tchain -m recent --set --name w00tlist -p tcp \
-j REJECT --reject-with tcp-reset

# create another chain named "w00t". It's purpose is to identify the first packet
# of an newly established tcp-connection and to search for a string in it:
iptables -N w00t

# redirect all incoming (no outgoing!) TCP packets to the chain "w00t":
iptables -A INPUT -p tcp -j w00t

# all remaining rules are part of the chain "w00t"
#---------------------------------------------------------------
# all following comments in lowercase are unchanged from spamcleaner.org
# COMMENTS IN UPPERCASE ARE FROM ME
#---------------------------------------------------------------

# look for the SYN packet and create the list :
iptables -A w00t -m recent -p tcp --syn --dport 80 --set  

# look for the SYN,ACK packet and update the list :
iptables -A w00t -m recent -p tcp --tcp-flags PSH,SYN,ACK SYN,ACK --sport 80 --update
#---------------------------------------------------------------------------------
# THIS IS WHAT I DON'T UNDERSTAND:
# THE CHAIN w00t CAN ONLY BE REACHED FROM THE CHAIN INPUT. SO WE ARE DEALING HERE
# WITH PACKETS THAT THE CLIENT IS SENDING AND THAT THE SERVER IS RECEIVING. BUT IN
# STEP 2 OF TCP-HANDSHAKE ITS THE SERVER WHO IS SENDING AND THE CLIENT WHO IS
# RECEIVING. SO THE PACKET WITH SYN AND ACK SET AND WITH sport 80 GOES THROUGH THE
# CHAIN "OUTPUT", NOT "INPUT". SO HOW CAN IT BE DETECTED IN CHAIN w00t?
#---------------------------------------------------------------------------------

# look for the ACK packet and update the list :
iptables -A w00t -m recent -p tcp --tcp-flags PSH,SYN,ACK ACK --dport 80 --update

# look for the hexadecimal string in the first PSH+ACK.
# If found, redirect to w00tchain in order to blacklist the IP and
# to close the connection.
# Delete our list, we do not want to filter any further packet from that connection :
iptables -A w00t -m recent -p tcp --tcp-flags PSH,ACK PSH,ACK --dport 80 --remove \
-m string --to 80 --algo bm --hex-string '|485454502f312e310d0a0d0a|' -j w00tchain

E há uma segunda coisa que não entendo:

A última regra está procurando pela cadeia hexagonal em um pacote que possui seus conjuntos de sinalizadores PSH e ACK. Mas como posso ter certeza de que o PSH está definido para o meu pacote? Não tenho certeza, mas acho que é possível e legal enviar pacotes TCP que tenham sua bandeira PSH desativada.

EDITAR: Há uma terceira pergunta: o que acontece se o servidor receber dois usuários usavam mais solicitações HTTP sobre TCP dos mesmos endereços IP ao mesmo tempo (cada solicitação com seu próprio número de porta)?

    
por Hubert Schölnast 29.09.2014 / 09:31

1 resposta

0

Esqueça o IPTables. Você pode simplesmente usar mod_security com ação nolog. Algo parecido com isto (não testado):

SecRule REQUEST_URI "^/w00tw00t\.at\.ISC\.SANS\.DFind" phase:1,nolog,deny,id:1000

Ou você pode criar um virtualhost fictício com logs separados, o que apenas nega todas as solicitações e as configura como primeiro. Os clientes que não forneceriam um nome de host ou fornecessem um nome de host desconhecido sempre terminariam lá.

    
por 30.09.2014 / 21:38

Tags