From: Victor Julien Date: Sat, 30 Nov 2024 07:46:56 +0000 (+0100) Subject: tests: add bug 7422 tests X-Git-Tag: suricata-7.0.9~85 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5499db25d50a95e85cdebfe6bbed08417563f3f9;p=thirdparty%2Fsuricata-verify.git tests: add bug 7422 tests Tests various forms of RST triggering handling of unACK'd data. --- diff --git a/tests/tcp-rst-unacked-stream-01-raw/README.md b/tests/tcp-rst-unacked-stream-01-raw/README.md new file mode 100644 index 000000000..66bd7beae --- /dev/null +++ b/tests/tcp-rst-unacked-stream-01-raw/README.md @@ -0,0 +1,8 @@ +Test +==== + +Test series that tests if a RST that comes in before all data is ACK'd the +unACK'd data is still reassembled and inspected, but does not trigger a GAP +event. + +This test tests raw reassembly inspection of unack'd data w/o GAP. diff --git a/tests/tcp-rst-unacked-stream-01-raw/input.pcap b/tests/tcp-rst-unacked-stream-01-raw/input.pcap new file mode 100644 index 000000000..a37d82e71 Binary files /dev/null and b/tests/tcp-rst-unacked-stream-01-raw/input.pcap differ diff --git a/tests/tcp-rst-unacked-stream-01-raw/test.rules b/tests/tcp-rst-unacked-stream-01-raw/test.rules new file mode 100644 index 000000000..84c751a02 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-01-raw/test.rules @@ -0,0 +1,2 @@ +alert tcp any any -> any any (content:"Let Me In"; sid:1;) +alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;) diff --git a/tests/tcp-rst-unacked-stream-01-raw/test.yaml b/tests/tcp-rst-unacked-stream-01-raw/test.yaml new file mode 100644 index 000000000..e489751d5 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-01-raw/test.yaml @@ -0,0 +1,20 @@ +requires: + min-version: 8 + +checks: + - filter: + count: 1 + match: + event_type: alert + alert.signature_id: 1 + pkt_src: "stream (flow timeout)" + - filter: + count: 0 + match: + event_type: alert + alert.signature_id: 2210048 + - filter: + count: 1 + match: + event_type: stats + stats.tcp.reassembly_gap: 0 diff --git a/tests/tcp-rst-unacked-stream-01-raw/writepcap.py b/tests/tcp-rst-unacked-stream-01-raw/writepcap.py new file mode 100755 index 000000000..c96dae0f2 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-01-raw/writepcap.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +from scapy.all import * + +pkts = [] + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)]) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535) +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1001,ack=2,window=65535)/"Please " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1008,ack=2,window=65535)/"Let " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1012,ack=2,window=65535)/"Me " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1015,ack=2,window=65535)/"In!" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='RA',seq=2,ack=1008,window=65535)/"Access Denied" + +wrpcap('input.pcap', pkts) diff --git a/tests/tcp-rst-unacked-stream-02-raw-ips/README.md b/tests/tcp-rst-unacked-stream-02-raw-ips/README.md new file mode 100644 index 000000000..4fe7d6b91 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-02-raw-ips/README.md @@ -0,0 +1,8 @@ +Test +==== + +Test series that tests if a RST that comes in before all data is ACK'd the +unACK'd data is still reassembled and inspected, but does not trigger a GAP +event. + +This test tests raw reassembly inspection of unack'd data w/o GAP in IPS mode. diff --git a/tests/tcp-rst-unacked-stream-02-raw-ips/input.pcap b/tests/tcp-rst-unacked-stream-02-raw-ips/input.pcap new file mode 100644 index 000000000..a37d82e71 Binary files /dev/null and b/tests/tcp-rst-unacked-stream-02-raw-ips/input.pcap differ diff --git a/tests/tcp-rst-unacked-stream-02-raw-ips/test.rules b/tests/tcp-rst-unacked-stream-02-raw-ips/test.rules new file mode 100644 index 000000000..84c751a02 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-02-raw-ips/test.rules @@ -0,0 +1,2 @@ +alert tcp any any -> any any (content:"Let Me In"; sid:1;) +alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;) diff --git a/tests/tcp-rst-unacked-stream-02-raw-ips/test.yaml b/tests/tcp-rst-unacked-stream-02-raw-ips/test.yaml new file mode 100644 index 000000000..ceceeb89b --- /dev/null +++ b/tests/tcp-rst-unacked-stream-02-raw-ips/test.yaml @@ -0,0 +1,20 @@ +requires: + min-version: 8 + +checks: + - filter: + count: 1 + match: + event_type: alert + alert.signature_id: 1 + pcap_cnt: 7 + - filter: + count: 0 + match: + event_type: alert + alert.signature_id: 2210048 + - filter: + count: 1 + match: + event_type: stats + stats.tcp.reassembly_gap: 0 diff --git a/tests/tcp-rst-unacked-stream-02-raw-ips/writepcap.py b/tests/tcp-rst-unacked-stream-02-raw-ips/writepcap.py new file mode 100755 index 000000000..c96dae0f2 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-02-raw-ips/writepcap.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +from scapy.all import * + +pkts = [] + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)]) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535) +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1001,ack=2,window=65535)/"Please " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1008,ack=2,window=65535)/"Let " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1012,ack=2,window=65535)/"Me " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1015,ack=2,window=65535)/"In!" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='RA',seq=2,ack=1008,window=65535)/"Access Denied" + +wrpcap('input.pcap', pkts) diff --git a/tests/tcp-rst-unacked-stream-03-gap/README.md b/tests/tcp-rst-unacked-stream-03-gap/README.md new file mode 100644 index 000000000..cc17663e5 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-03-gap/README.md @@ -0,0 +1,8 @@ +Test +==== + +Test series that tests if a RST that comes in before all data is ACK'd the +unACK'd data is still reassembled and inspected, but does not trigger a GAP +event. + +This test tests raw reassembly inspection of unack'd data with GAP. diff --git a/tests/tcp-rst-unacked-stream-03-gap/input.pcap b/tests/tcp-rst-unacked-stream-03-gap/input.pcap new file mode 100644 index 000000000..b20f5d40c Binary files /dev/null and b/tests/tcp-rst-unacked-stream-03-gap/input.pcap differ diff --git a/tests/tcp-rst-unacked-stream-03-gap/test.rules b/tests/tcp-rst-unacked-stream-03-gap/test.rules new file mode 100644 index 000000000..82570ea6f --- /dev/null +++ b/tests/tcp-rst-unacked-stream-03-gap/test.rules @@ -0,0 +1,2 @@ +alert tcp any any -> any any (content:"Me In"; sid:1;) +alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;) diff --git a/tests/tcp-rst-unacked-stream-03-gap/test.yaml b/tests/tcp-rst-unacked-stream-03-gap/test.yaml new file mode 100644 index 000000000..e489751d5 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-03-gap/test.yaml @@ -0,0 +1,20 @@ +requires: + min-version: 8 + +checks: + - filter: + count: 1 + match: + event_type: alert + alert.signature_id: 1 + pkt_src: "stream (flow timeout)" + - filter: + count: 0 + match: + event_type: alert + alert.signature_id: 2210048 + - filter: + count: 1 + match: + event_type: stats + stats.tcp.reassembly_gap: 0 diff --git a/tests/tcp-rst-unacked-stream-03-gap/writepcap.py b/tests/tcp-rst-unacked-stream-03-gap/writepcap.py new file mode 100755 index 000000000..df3d93a37 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-03-gap/writepcap.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +from scapy.all import * + +pkts = [] + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)]) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535) +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1001,ack=2,window=65535)/"Please " +#pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1008,ack=2,window=65535)/"Let " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1012,ack=2,window=65535)/"Me " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1015,ack=2,window=65535)/"In!" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='RA',seq=2,ack=1008,window=65535)/"Access Denied" + +wrpcap('input.pcap', pkts) diff --git a/tests/tcp-rst-unacked-stream-04-gap-ips/README.md b/tests/tcp-rst-unacked-stream-04-gap-ips/README.md new file mode 100644 index 000000000..26b966a4b --- /dev/null +++ b/tests/tcp-rst-unacked-stream-04-gap-ips/README.md @@ -0,0 +1,8 @@ +Test +==== + +Test series that tests if a RST that comes in before all data is ACK'd the +unACK'd data is still reassembled and inspected, but does not trigger a GAP +event. + +This test tests raw reassembly inspection of unack'd data with GAP in IPS mode. diff --git a/tests/tcp-rst-unacked-stream-04-gap-ips/input.pcap b/tests/tcp-rst-unacked-stream-04-gap-ips/input.pcap new file mode 100644 index 000000000..da81997e2 Binary files /dev/null and b/tests/tcp-rst-unacked-stream-04-gap-ips/input.pcap differ diff --git a/tests/tcp-rst-unacked-stream-04-gap-ips/test.rules b/tests/tcp-rst-unacked-stream-04-gap-ips/test.rules new file mode 100644 index 000000000..82570ea6f --- /dev/null +++ b/tests/tcp-rst-unacked-stream-04-gap-ips/test.rules @@ -0,0 +1,2 @@ +alert tcp any any -> any any (content:"Me In"; sid:1;) +alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;) diff --git a/tests/tcp-rst-unacked-stream-04-gap-ips/test.yaml b/tests/tcp-rst-unacked-stream-04-gap-ips/test.yaml new file mode 100644 index 000000000..2e993fed1 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-04-gap-ips/test.yaml @@ -0,0 +1,20 @@ +requires: + min-version: 8 + +checks: + - filter: + count: 1 + match: + event_type: alert + alert.signature_id: 1 + pcap_cnt: 6 + - filter: + count: 0 + match: + event_type: alert + alert.signature_id: 2210048 + - filter: + count: 1 + match: + event_type: stats + stats.tcp.reassembly_gap: 0 diff --git a/tests/tcp-rst-unacked-stream-04-gap-ips/writepcap.py b/tests/tcp-rst-unacked-stream-04-gap-ips/writepcap.py new file mode 100755 index 000000000..cbe933939 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-04-gap-ips/writepcap.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +from scapy.all import * + +pkts = [] + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)]) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535) +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1001,ack=2,window=65535)/"Please " +#pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1008,ack=2,window=65535)/"Let " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1012,ack=2,window=65535)/"Me " +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1015,ack=2,window=65535)/"In!" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='RA',seq=2,ack=1001,window=65535)/"Access Denied" + +wrpcap('input.pcap', pkts) diff --git a/tests/tcp-rst-unacked-stream-05-http-nogap/README.md b/tests/tcp-rst-unacked-stream-05-http-nogap/README.md new file mode 100644 index 000000000..b577a6a9b --- /dev/null +++ b/tests/tcp-rst-unacked-stream-05-http-nogap/README.md @@ -0,0 +1,8 @@ +Test +==== + +Test series that tests if a RST that comes in before all data is ACK'd the +unACK'd data is still reassembled and inspected, but does not trigger a GAP +event. + +This test tests HTTP reassembly inspection of unack'd data w/o GAP. diff --git a/tests/tcp-rst-unacked-stream-05-http-nogap/input.pcap b/tests/tcp-rst-unacked-stream-05-http-nogap/input.pcap new file mode 100644 index 000000000..b0272f70e Binary files /dev/null and b/tests/tcp-rst-unacked-stream-05-http-nogap/input.pcap differ diff --git a/tests/tcp-rst-unacked-stream-05-http-nogap/test.rules b/tests/tcp-rst-unacked-stream-05-http-nogap/test.rules new file mode 100644 index 000000000..5979085d5 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-05-http-nogap/test.rules @@ -0,0 +1,2 @@ +alert tcp any any -> any any (content:"User-Agent: Mozilla"; sid:1;) +alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;) diff --git a/tests/tcp-rst-unacked-stream-05-http-nogap/test.yaml b/tests/tcp-rst-unacked-stream-05-http-nogap/test.yaml new file mode 100644 index 000000000..e489751d5 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-05-http-nogap/test.yaml @@ -0,0 +1,20 @@ +requires: + min-version: 8 + +checks: + - filter: + count: 1 + match: + event_type: alert + alert.signature_id: 1 + pkt_src: "stream (flow timeout)" + - filter: + count: 0 + match: + event_type: alert + alert.signature_id: 2210048 + - filter: + count: 1 + match: + event_type: stats + stats.tcp.reassembly_gap: 0 diff --git a/tests/tcp-rst-unacked-stream-05-http-nogap/writepcap.py b/tests/tcp-rst-unacked-stream-05-http-nogap/writepcap.py new file mode 100755 index 000000000..e5f7df890 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-05-http-nogap/writepcap.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +from scapy.all import * + +pkts = [] + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)]) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535) +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535) + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)/"GET / HTTP/1.0\r\n" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=18,ack=1001,window=65535)/"Cookie: abcdef\r\n" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=34,ack=1001,window=65535)/"User-Agent: " +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=46,ack=1001,window=65535)/"Mozilla\r\n\r\n" + +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='RA',seq=1001,ack=18,window=65535) + +wrpcap('input.pcap', pkts) diff --git a/tests/tcp-rst-unacked-stream-06-http-nogap-ips/README.md b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/README.md new file mode 100644 index 000000000..f82be04a1 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/README.md @@ -0,0 +1,8 @@ +Test +==== + +Test series that tests if a RST that comes in before all data is ACK'd the +unACK'd data is still reassembled and inspected, but does not trigger a GAP +event. + +This test tests HTTP reassembly inspection of unack'd data w/o GAP in IPS mode. diff --git a/tests/tcp-rst-unacked-stream-06-http-nogap-ips/input.pcap b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/input.pcap new file mode 100644 index 000000000..b0272f70e Binary files /dev/null and b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/input.pcap differ diff --git a/tests/tcp-rst-unacked-stream-06-http-nogap-ips/test.rules b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/test.rules new file mode 100644 index 000000000..5979085d5 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/test.rules @@ -0,0 +1,2 @@ +alert tcp any any -> any any (content:"User-Agent: Mozilla"; sid:1;) +alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;) diff --git a/tests/tcp-rst-unacked-stream-06-http-nogap-ips/test.yaml b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/test.yaml new file mode 100644 index 000000000..ceceeb89b --- /dev/null +++ b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/test.yaml @@ -0,0 +1,20 @@ +requires: + min-version: 8 + +checks: + - filter: + count: 1 + match: + event_type: alert + alert.signature_id: 1 + pcap_cnt: 7 + - filter: + count: 0 + match: + event_type: alert + alert.signature_id: 2210048 + - filter: + count: 1 + match: + event_type: stats + stats.tcp.reassembly_gap: 0 diff --git a/tests/tcp-rst-unacked-stream-06-http-nogap-ips/writepcap.py b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/writepcap.py new file mode 100755 index 000000000..e5f7df890 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-06-http-nogap-ips/writepcap.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +from scapy.all import * + +pkts = [] + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)]) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535) +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535) + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)/"GET / HTTP/1.0\r\n" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=18,ack=1001,window=65535)/"Cookie: abcdef\r\n" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=34,ack=1001,window=65535)/"User-Agent: " +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=46,ack=1001,window=65535)/"Mozilla\r\n\r\n" + +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='RA',seq=1001,ack=18,window=65535) + +wrpcap('input.pcap', pkts) diff --git a/tests/tcp-rst-unacked-stream-07-http/README.md b/tests/tcp-rst-unacked-stream-07-http/README.md new file mode 100644 index 000000000..e20c87b9a --- /dev/null +++ b/tests/tcp-rst-unacked-stream-07-http/README.md @@ -0,0 +1,8 @@ +Test +==== + +Test series that tests if a RST that comes in before all data is ACK'd the +unACK'd data is still reassembled and inspected, but does not trigger a GAP +event. + +This test tests HTTP reassembly inspection of unack'd data with GAP. diff --git a/tests/tcp-rst-unacked-stream-07-http/input.pcap b/tests/tcp-rst-unacked-stream-07-http/input.pcap new file mode 100644 index 000000000..921bbaa57 Binary files /dev/null and b/tests/tcp-rst-unacked-stream-07-http/input.pcap differ diff --git a/tests/tcp-rst-unacked-stream-07-http/test.rules b/tests/tcp-rst-unacked-stream-07-http/test.rules new file mode 100644 index 000000000..5979085d5 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-07-http/test.rules @@ -0,0 +1,2 @@ +alert tcp any any -> any any (content:"User-Agent: Mozilla"; sid:1;) +alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;) diff --git a/tests/tcp-rst-unacked-stream-07-http/test.yaml b/tests/tcp-rst-unacked-stream-07-http/test.yaml new file mode 100644 index 000000000..e489751d5 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-07-http/test.yaml @@ -0,0 +1,20 @@ +requires: + min-version: 8 + +checks: + - filter: + count: 1 + match: + event_type: alert + alert.signature_id: 1 + pkt_src: "stream (flow timeout)" + - filter: + count: 0 + match: + event_type: alert + alert.signature_id: 2210048 + - filter: + count: 1 + match: + event_type: stats + stats.tcp.reassembly_gap: 0 diff --git a/tests/tcp-rst-unacked-stream-07-http/writepcap.py b/tests/tcp-rst-unacked-stream-07-http/writepcap.py new file mode 100755 index 000000000..81952ff74 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-07-http/writepcap.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +from scapy.all import * + +pkts = [] + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)]) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535) +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535) + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)/"GET / HTTP/1.0\r\n" +#pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=18,ack=1001,window=65535)/"Cookie: abcdef\r\n" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=34,ack=1001,window=65535)/"User-Agent: " +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=46,ack=1001,window=65535)/"Mozilla\r\n\r\n" + +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='RA',seq=1001,ack=18,window=65535) + +wrpcap('input.pcap', pkts) diff --git a/tests/tcp-rst-unacked-stream-08-http-ips/README.md b/tests/tcp-rst-unacked-stream-08-http-ips/README.md new file mode 100644 index 000000000..305ccf6ef --- /dev/null +++ b/tests/tcp-rst-unacked-stream-08-http-ips/README.md @@ -0,0 +1,8 @@ +Test +==== + +Test series that tests if a RST that comes in before all data is ACK'd the +unACK'd data is still reassembled and inspected, but does not trigger a GAP +event. + +This test tests HTTP reassembly inspection of unack'd data with GAP in IPS mode. diff --git a/tests/tcp-rst-unacked-stream-08-http-ips/input.pcap b/tests/tcp-rst-unacked-stream-08-http-ips/input.pcap new file mode 100644 index 000000000..921bbaa57 Binary files /dev/null and b/tests/tcp-rst-unacked-stream-08-http-ips/input.pcap differ diff --git a/tests/tcp-rst-unacked-stream-08-http-ips/test.rules b/tests/tcp-rst-unacked-stream-08-http-ips/test.rules new file mode 100644 index 000000000..5979085d5 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-08-http-ips/test.rules @@ -0,0 +1,2 @@ +alert tcp any any -> any any (content:"User-Agent: Mozilla"; sid:1;) +alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;) diff --git a/tests/tcp-rst-unacked-stream-08-http-ips/test.yaml b/tests/tcp-rst-unacked-stream-08-http-ips/test.yaml new file mode 100644 index 000000000..2e993fed1 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-08-http-ips/test.yaml @@ -0,0 +1,20 @@ +requires: + min-version: 8 + +checks: + - filter: + count: 1 + match: + event_type: alert + alert.signature_id: 1 + pcap_cnt: 6 + - filter: + count: 0 + match: + event_type: alert + alert.signature_id: 2210048 + - filter: + count: 1 + match: + event_type: stats + stats.tcp.reassembly_gap: 0 diff --git a/tests/tcp-rst-unacked-stream-08-http-ips/writepcap.py b/tests/tcp-rst-unacked-stream-08-http-ips/writepcap.py new file mode 100755 index 000000000..81952ff74 --- /dev/null +++ b/tests/tcp-rst-unacked-stream-08-http-ips/writepcap.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +from scapy.all import * + +pkts = [] + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)]) +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535) +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535) + +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)/"GET / HTTP/1.0\r\n" +#pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=18,ack=1001,window=65535)/"Cookie: abcdef\r\n" +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=34,ack=1001,window=65535)/"User-Agent: " +pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=46,ack=1001,window=65535)/"Mozilla\r\n\r\n" + +pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='RA',seq=1001,ack=18,window=65535) + +wrpcap('input.pcap', pkts)