From: Daniel Olatunji Date: Fri, 19 Jan 2024 07:39:19 +0000 (+0100) Subject: detect-engine-state: add assorted tests X-Git-Tag: suricata-6.0.16~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=795de87b8d9c9b719eddf85cf5cf1efec258eb81;p=thirdparty%2Fsuricata-verify.git detect-engine-state: add assorted tests Task: 6146 Add previously Suricata unittests as Suricata-verify tests. --- diff --git a/tests/engine-state/detect-engine-state-01/README.md b/tests/engine-state/detect-engine-state-01/README.md new file mode 100644 index 000000000..770889858 --- /dev/null +++ b/tests/engine-state/detect-engine-state-01/README.md @@ -0,0 +1,7 @@ +## Description +Test multiple pipelined http transactions. + +https://redmine.openinfosecfoundation.org/issues/6146 + +## PCAP +PCAP file generated by passing the `input.t` file to python2 `htptopcap.py` script in engine-state folder; as in `python2 htptopcap.py input.t`. \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-01/input.pcap b/tests/engine-state/detect-engine-state-01/input.pcap new file mode 100644 index 000000000..43a8b74b9 Binary files /dev/null and b/tests/engine-state/detect-engine-state-01/input.pcap differ diff --git a/tests/engine-state/detect-engine-state-01/input.t b/tests/engine-state/detect-engine-state-01/input.t new file mode 100644 index 000000000..4c118173f --- /dev/null +++ b/tests/engine-state/detect-engine-state-01/input.t @@ -0,0 +1,25 @@ +>>> +POST / HTTP/1.0 + +>>> +User-Agent: Mozilla/1.0 +Content-Length: 10 + +>>> +Cookie: dummy + + +>>> +Http Body! +>>> +GET /?var=val HTTP/1.1 + +>>> +User-Agent: Firefox/1.0 + +>>> +Cookie: dummy2 +Content-Length: 10 + +Http Body! +<<< diff --git a/tests/engine-state/detect-engine-state-01/test.rules b/tests/engine-state/detect-engine-state-01/test.rules new file mode 100644 index 000000000..498acc870 --- /dev/null +++ b/tests/engine-state/detect-engine-state-01/test.rules @@ -0,0 +1,3 @@ +alert tcp any any -> any any (content:"POST"; http_method; content:"dummy"; http_cookie; sid:1; rev:1;) +alert tcp any any -> any any (flow:to_server; content:"POST"; http_method; content:"/"; http_uri; content:"Mozilla"; http_header; content:"dummy"; http_cookie; content:"body"; nocase; http_client_body; sid:2; rev:1;) +alert tcp any any -> any any (flow:to_server; content:"GET"; http_method; content:"Firefox"; http_header; content:"dummy2"; http_cookie; sid:3; rev:1;) diff --git a/tests/engine-state/detect-engine-state-01/test.yaml b/tests/engine-state/detect-engine-state-01/test.yaml new file mode 100644 index 000000000..2c069a9f0 --- /dev/null +++ b/tests/engine-state/detect-engine-state-01/test.yaml @@ -0,0 +1,32 @@ +requires: + min-version: 7 +args: +- -k none +- --set stream.midstream=true + +checks: +- filter: + count: 1 + match: + event_type: alert + alert.action: allowed + alert.signature_id: 1 + +- filter: + count: 1 + match: + event_type: alert + alert.action: allowed + alert.signature_id: 2 + +- filter: + count: 1 + match: + event_type: alert + alert.action: allowed + alert.signature_id: 3 + +- filter: + count: 1 + match: + event_type: flow diff --git a/tests/engine-state/detect-engine-state-02/README.md b/tests/engine-state/detect-engine-state-02/README.md new file mode 100644 index 000000000..4f853b4ce --- /dev/null +++ b/tests/engine-state/detect-engine-state-02/README.md @@ -0,0 +1,7 @@ +## Description +Test state-based signature handling using the filestore and filename keyword. + +https://redmine.openinfosecfoundation.org/issues/6146 + +## PCAP +PCAP file generated by passing the `input.t` file to python2 `htptopcap.py` script in engine-state folder; as in `python2 htptopcap.py input.t`. \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-02/input.pcap b/tests/engine-state/detect-engine-state-02/input.pcap new file mode 100644 index 000000000..49f9e662f Binary files /dev/null and b/tests/engine-state/detect-engine-state-02/input.pcap differ diff --git a/tests/engine-state/detect-engine-state-02/input.t b/tests/engine-state/detect-engine-state-02/input.t new file mode 100644 index 000000000..a2eb2c0d0 --- /dev/null +++ b/tests/engine-state/detect-engine-state-02/input.t @@ -0,0 +1,13 @@ +>>> +POST /upload.cgi HTTP/1.1 +Host: www.server.lan +Content-Type: multipart/form-data; boundary=---------------------------277531038314945 +Content-Length: 215 + +-----------------------------277531038314945 +Content-Disposition: form-data; name="uploadfile_0"; filename="somepicture1.jpg" +Content-Type: image/jpeg + +filecontent +-----------------------------277531038314945-- +<<< \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-02/suricata.yaml b/tests/engine-state/detect-engine-state-02/suricata.yaml new file mode 100644 index 000000000..dabc36d39 --- /dev/null +++ b/tests/engine-state/detect-engine-state-02/suricata.yaml @@ -0,0 +1,17 @@ +%YAML 1.1 +--- + +outputs: + - eve-log: + enabled: yes + types: + - files + - stats + - http + - alert + - flow + - file-store: + version: 2 + enabled: yes + stream-depth: 0 + write-fileinfo: true \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-02/test.rules b/tests/engine-state/detect-engine-state-02/test.rules new file mode 100644 index 000000000..74cb177d8 --- /dev/null +++ b/tests/engine-state/detect-engine-state-02/test.rules @@ -0,0 +1,4 @@ +alert http any any -> any any (flow:to_server; content:"POST"; http_method; content:"upload.cgi"; http_uri; filestore; sid:1; rev:1;) +alert http any any -> any any (content:"GET"; http_method; content:"upload.cgi"; http_uri; filestore; sid:2; rev:1;) +alert http any any -> any any (content:"GET"; http_method; content:"upload.cgi"; http_uri; filename:"nomatch"; sid:3; rev:1;) +alert http any any -> any any (content:"POST"; http_method; content:"upload.cgi"; http_uri; filename:"nomatch"; filestore; sid:4; rev:1;) \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-02/test.yaml b/tests/engine-state/detect-engine-state-02/test.yaml new file mode 100644 index 000000000..ca9dcc5a8 --- /dev/null +++ b/tests/engine-state/detect-engine-state-02/test.yaml @@ -0,0 +1,44 @@ +requires: + min-version: 7 +args: +- -k none +- --set stream.midstream=true + +checks: +- filter: + count: 1 + match: + event_type: alert + alert.action: allowed + alert.signature_id: 1 + +- filter: + count: 0 + match: + event_type: alert + alert.action: allowed + alert.signature_id: 2 + +- filter: + count: 0 + match: + event_type: alert + alert.action: allowed + alert.signature_id: 3 + +- filter: + count: 0 + match: + event_type: alert + alert.action: allowed + alert.signature_id: 4 + +- filter: + count: 1 + match: + event_type: http + +- filter: + count: 1 + match: + event_type: flow \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-03/README.md b/tests/engine-state/detect-engine-state-03/README.md new file mode 100644 index 000000000..acec935b2 --- /dev/null +++ b/tests/engine-state/detect-engine-state-03/README.md @@ -0,0 +1,7 @@ +## Description +Test that, file not stored if rule alert not triggered. + +https://redmine.openinfosecfoundation.org/issues/6146 + +## PCAP +PCAP file generated by passing the `input.t` file to python2 `htptopcap.py` script in engine-state folder; as in `python2 htptopcap.py input.t`. \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-03/input.pcap b/tests/engine-state/detect-engine-state-03/input.pcap new file mode 100644 index 000000000..49f9e662f Binary files /dev/null and b/tests/engine-state/detect-engine-state-03/input.pcap differ diff --git a/tests/engine-state/detect-engine-state-03/input.t b/tests/engine-state/detect-engine-state-03/input.t new file mode 100644 index 000000000..68fcad93e --- /dev/null +++ b/tests/engine-state/detect-engine-state-03/input.t @@ -0,0 +1,15 @@ +>>> +POST /upload.cgi HTTP/1.1 +Host: www.server.lan +Content-Type: multipart/form-data; boundary=---------------------------277531038314945 +Content-Length: 215 + +-----------------------------277531038314945 +Content-Disposition: form-data; name="uploadfile_0"; filename="somepicture1.jpg" +Content-Type: image/jpeg + + +>>> +filecontent +-----------------------------277531038314945-- +<<< \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-03/suricata.yaml b/tests/engine-state/detect-engine-state-03/suricata.yaml new file mode 100644 index 000000000..dabc36d39 --- /dev/null +++ b/tests/engine-state/detect-engine-state-03/suricata.yaml @@ -0,0 +1,17 @@ +%YAML 1.1 +--- + +outputs: + - eve-log: + enabled: yes + types: + - files + - stats + - http + - alert + - flow + - file-store: + version: 2 + enabled: yes + stream-depth: 0 + write-fileinfo: true \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-03/test.rules b/tests/engine-state/detect-engine-state-03/test.rules new file mode 100644 index 000000000..ed52bb6a6 --- /dev/null +++ b/tests/engine-state/detect-engine-state-03/test.rules @@ -0,0 +1 @@ +alert http any any -> any any (content:"GET"; http_method; content:"upload.cgi"; http_uri; filestore; sid:1; rev:1;) \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-03/test.yaml b/tests/engine-state/detect-engine-state-03/test.yaml new file mode 100644 index 000000000..78b7c9f35 --- /dev/null +++ b/tests/engine-state/detect-engine-state-03/test.yaml @@ -0,0 +1,33 @@ +requires: + min-version: 7 +args: +- -k none +- --set stream.midstream=true + +checks: + +- filter: + count: 1 + match: + event_type: fileinfo + has-key: flow_id + +- filter: + count: 1 + match: + event_type: stats + +- filter: + count: 0 + match: + event_type: alert + alert.action: allowed + alert.signature_id: 1 + +- filter: + count: 1 + match: + event_type: flow + +- shell: + args: test ! -e filestore/5a/5ab24eb0866bafe7d8c0d07f03f09aef7a4caa991a9dc1edd96e64683b750fe2 diff --git a/tests/engine-state/detect-engine-state-04/README.md b/tests/engine-state/detect-engine-state-04/README.md new file mode 100644 index 000000000..deeb7ac10 --- /dev/null +++ b/tests/engine-state/detect-engine-state-04/README.md @@ -0,0 +1,7 @@ +## Description +Test multiple files in a tx. + +https://redmine.openinfosecfoundation.org/issues/6146 + +## PCAP +PCAP file generated by passing the `input.t` file to python2 `htptopcap.py` script in engine-state folder; as in `python2 htptopcap.py input.t`. \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-04/input.pcap b/tests/engine-state/detect-engine-state-04/input.pcap new file mode 100644 index 000000000..e9eaee455 Binary files /dev/null and b/tests/engine-state/detect-engine-state-04/input.pcap differ diff --git a/tests/engine-state/detect-engine-state-04/input.t b/tests/engine-state/detect-engine-state-04/input.t new file mode 100644 index 000000000..6627cc778 --- /dev/null +++ b/tests/engine-state/detect-engine-state-04/input.t @@ -0,0 +1,24 @@ +>>> +POST /upload.cgi HTTP/1.1 +Host: www.server.lan +Content-Type: multipart/form-data; boundary=---------------------------277531038314945 +Content-Length: 385 + +-----------------------------277531038314945 +Content-Disposition: form-data; name="uploadfile_0"; filename="AAAApicture1.jpg" +Content-Type: image/jpeg + + +>>> +file +>>> +content +-----------------------------277531038314945 + +>>> +Content-Disposition: form-data; name="uploadfile_1"; filename="BBBBpicture2.jpg" +Content-Type: image/jpeg + +filecontent2 +-----------------------------277531038314945-- +<<< \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-04/suricata.yaml b/tests/engine-state/detect-engine-state-04/suricata.yaml new file mode 100644 index 000000000..dabc36d39 --- /dev/null +++ b/tests/engine-state/detect-engine-state-04/suricata.yaml @@ -0,0 +1,17 @@ +%YAML 1.1 +--- + +outputs: + - eve-log: + enabled: yes + types: + - files + - stats + - http + - alert + - flow + - file-store: + version: 2 + enabled: yes + stream-depth: 0 + write-fileinfo: true \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-04/test.rules b/tests/engine-state/detect-engine-state-04/test.rules new file mode 100644 index 000000000..2b97216f5 --- /dev/null +++ b/tests/engine-state/detect-engine-state-04/test.rules @@ -0,0 +1 @@ +alert http any any -> any any (content:"POST"; http_method; content:"upload.cgi"; http_uri; filename:"BBBBpicture"; filestore; sid:1; rev:1;) \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-04/test.yaml b/tests/engine-state/detect-engine-state-04/test.yaml new file mode 100644 index 000000000..6f87dae88 --- /dev/null +++ b/tests/engine-state/detect-engine-state-04/test.yaml @@ -0,0 +1,28 @@ +requires: + min-version: 7 +args: +- -k none +- --set stream.midstream=true + +checks: + +- filter: + count: 1 + match: + event_type: alert + alert.action: allowed + alert.signature_id: 1 + +- filter: + count: 1 + match: + event_type: http + +- filter: + count: 1 + match: + event_type: flow + flow.alerted: true + +- shell: + args: test -e filestore/ec/ec3a53b52eb11808d59d29ffd01568edf2d62cdc9c02def84d0a11704d552de2 \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-05/README.md b/tests/engine-state/detect-engine-state-05/README.md new file mode 100644 index 000000000..64013b860 --- /dev/null +++ b/tests/engine-state/detect-engine-state-05/README.md @@ -0,0 +1,9 @@ +## Description +Test multiple files in a tx. + +Both files should match; no other matches. + +https://redmine.openinfosecfoundation.org/issues/6146 + +## PCAP +PCAP file generated by passing the `input.t` file to python2 `htptopcap.py` script in engine-state folder; as in `python2 htptopcap.py input.t`. \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-05/input.pcap b/tests/engine-state/detect-engine-state-05/input.pcap new file mode 100644 index 000000000..13bbb3b84 Binary files /dev/null and b/tests/engine-state/detect-engine-state-05/input.pcap differ diff --git a/tests/engine-state/detect-engine-state-05/input.t b/tests/engine-state/detect-engine-state-05/input.t new file mode 100644 index 000000000..c8ea57a5e --- /dev/null +++ b/tests/engine-state/detect-engine-state-05/input.t @@ -0,0 +1,24 @@ +>>> +POST /upload.cgi HTTP/1.1 +Host: www.server.lan +Content-Type: multipart/form-data; boundary=---------------------------277531038314945 +Content-Length: 385 + +-----------------------------277531038314945 +Content-Disposition: form-data; name="uploadfile_0"; filename="somepicture1.jpg" +Content-Type: image/jpeg + + +>>> +file +>>> +content +-----------------------------277531038314945 + +>>> +Content-Disposition: form-data; name="uploadfile_1"; filename="somepicture2.jpg" +Content-Type: image/jpeg + +filecontent2 +-----------------------------277531038314945-- +<<< \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-05/suricata.yaml b/tests/engine-state/detect-engine-state-05/suricata.yaml new file mode 100644 index 000000000..dabc36d39 --- /dev/null +++ b/tests/engine-state/detect-engine-state-05/suricata.yaml @@ -0,0 +1,17 @@ +%YAML 1.1 +--- + +outputs: + - eve-log: + enabled: yes + types: + - files + - stats + - http + - alert + - flow + - file-store: + version: 2 + enabled: yes + stream-depth: 0 + write-fileinfo: true \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-05/test.rules b/tests/engine-state/detect-engine-state-05/test.rules new file mode 100644 index 000000000..70b431ef7 --- /dev/null +++ b/tests/engine-state/detect-engine-state-05/test.rules @@ -0,0 +1,2 @@ +alert http any any -> any any (content:"POST"; http_method; content:"upload.cgi"; http_uri; filename:"somepicture"; filestore; sid:1; rev:1;) +alert http any any -> any any (filename:"somepicture"; filestore; sid:2; rev:1;) \ No newline at end of file diff --git a/tests/engine-state/detect-engine-state-05/test.yaml b/tests/engine-state/detect-engine-state-05/test.yaml new file mode 100644 index 000000000..fa5fdbaf6 --- /dev/null +++ b/tests/engine-state/detect-engine-state-05/test.yaml @@ -0,0 +1,54 @@ +requires: + min-version: 7 +args: +- -k none +- --set stream.midstream=true + +checks: +- filter: + count: 1 + match: + alert.action: allowed + alert.signature_id: 1 + event_type: alert + files[0].filename: somepicture1.jpg + +- filter: + count: 1 + match: + alert.action: allowed + alert.signature_id: 2 + event_type: alert + files[0].filename: somepicture1.jpg + +- shell: + args: test -e filestore/5a/5ab24eb0866bafe7d8c0d07f03f09aef7a4caa991a9dc1edd96e64683b750fe2 + +- filter: + count: 1 + match: + alert.action: allowed + alert.signature_id: 1 + event_type: alert + files[0].filename: somepicture2.jpg + +- filter: + count: 1 + match: + alert.action: allowed + alert.signature_id: 2 + event_type: alert + files[0].filename: somepicture2.jpg + +- shell: + args: test -e filestore/ec/ec3a53b52eb11808d59d29ffd01568edf2d62cdc9c02def84d0a11704d552de2 + +- filter: + count: 1 + match: + event_type: http + +- filter: + count: 1 + match: + event_type: flow \ No newline at end of file diff --git a/tests/engine-state/htptopcap.py b/tests/engine-state/htptopcap.py new file mode 100644 index 000000000..09c01b9b1 --- /dev/null +++ b/tests/engine-state/htptopcap.py @@ -0,0 +1,130 @@ +#! /usr/bin/env python + +# @author: Philippe Antoine + +import sys +import binascii +from threading import Thread +import time +import socket + +# Create a pcap from a htp test file +# Launches a server on port 8080 +# Launches a client in another thread that connects to it +# Both client and server read the htp test file +# And they send and receive data as described (without analysing it) +# So, you need to capture traffic on port 8080 while running the script + +def removeOneEOL(s): + r = s + if r[-1] == '\n': + r = r[:-1] + if r[-1] == '\r': + r = r[:-1] + return r + + +class ServerThread(Thread): + + def __init__(self, filename): + Thread.__init__(self) + self.filename = filename + + def run(self): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(("127.0.0.1", 8080)) + s.listen(1) + conn, addr = s.accept() + f = open(self.filename) + state = 0 + sending = "" + receiving = "" + + for l in f.readlines(): + # change of state + if l.rstrip() == "<<<" or l.rstrip() == ">>>": + # Receiving or sending buffer + if state == 1: + conn.send(removeOneEOL(sending)) + print "server sent", len(removeOneEOL(sending)) + elif state == 2: + data = conn.recv(len(removeOneEOL(receiving))) + print "server recvd", len(data) + if l.rstrip() == "<<<": + state = 1 + sending = "" + elif l.rstrip() == ">>>": + state = 2 + receiving = "" + else: + if state == 1: + sending += l + elif state == 2: + receiving += l + + # Receiving or sending last buffer + if state == 1: + conn.send(sending) + print "server sent", len(sending) + elif state == 2: + data = conn.recv(len(receiving)) + print "server recvd", len(data) + conn.close() + s.close() + f.close() + + +class ClientThread(Thread): + + def __init__(self, filename): + Thread.__init__(self) + self.filename = filename + + def run(self): + time.sleep(1) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(("127.0.0.1", 8080)) + f = open(self.filename) + state = 0 + sending = "" + receiving = "" + + for l in f.readlines(): + if l.rstrip() == "<<<" or l.rstrip() == ">>>": + if state == 1: + s.send(removeOneEOL(sending)) + print "client sent", len(removeOneEOL(sending)) + elif state == 2: + data = s.recv(len(removeOneEOL(receiving))) + print "client recvd", len(data) + if l.rstrip() == "<<<": + state = 2 + receiving = "" + elif l.rstrip() == ">>>": + state = 1 + sending = "" + else: + if state == 1: + sending += l + elif state == 2: + receiving += l + + if state == 1: + s.send(sending) + print "client sent", len(sending) + elif state == 2: + data = s.recv(len(receiving)) + print "client recvd", len(data) + s.close() + f.close() + +t1 = ServerThread(sys.argv[1]) +t2 = ClientThread(sys.argv[1]) + +# Launch threads +t1.start() +t2.start() + +# Wait for threads to finish +t1.join() +t2.join()