]> git.ipfire.org Git - thirdparty/suricata-verify.git/commitdiff
pgsql: add tests with alert metadata
authorJuliana Fajardini <jufajardini@oisf.net>
Mon, 10 Jun 2024 23:38:46 +0000 (20:38 -0300)
committerVictor Julien <victor@inliniac.net>
Fri, 20 Sep 2024 09:49:18 +0000 (11:49 +0200)
Check for transaction metadata in PGSQL alerts.
Add `engine-analysis` tests for the used rules, as well, to better
describe them and compare with expected behavior.

Related to
Task #7000

tests/pgsql/pgsql-7000-ids/README.md [new file with mode: 0644]
tests/pgsql/pgsql-7000-ids/suricata.yaml [new file with mode: 0644]
tests/pgsql/pgsql-7000-ids/test.rules [new file with mode: 0644]
tests/pgsql/pgsql-7000-ids/test.yaml [new file with mode: 0644]
tests/rules/pgsql-7000/suricata.yaml [new file with mode: 0644]
tests/rules/pgsql-7000/test.rules [new file with mode: 0644]
tests/rules/pgsql-7000/test.yaml [new file with mode: 0644]

diff --git a/tests/pgsql/pgsql-7000-ids/README.md b/tests/pgsql/pgsql-7000-ids/README.md
new file mode 100644 (file)
index 0000000..bd3dffc
--- /dev/null
@@ -0,0 +1,18 @@
+# Description
+
+Showcase engine behavior with simple pgsql stream rules and alert metadata.
+
+## Behavior
+
+The 2 rules will match on the PGSQL queries for `SELECT` (sid 1) and `DELETE FROM`,
+(sid 2) with one extra alert for sid 1 due to the portion of the stream
+containing the last seen SELECT after the real message was seen.
+
+## Pcap
+
+This test uses the pcap from PGSQL test `pgsql-simple-query-rollback`
+
+## Redmine ticket
+
+Partly related to:
+https://redmine.openinfosecfoundation.org/issues/7000
diff --git a/tests/pgsql/pgsql-7000-ids/suricata.yaml b/tests/pgsql/pgsql-7000-ids/suricata.yaml
new file mode 100644 (file)
index 0000000..aac151f
--- /dev/null
@@ -0,0 +1,17 @@
+%YAML 1.1
+---
+
+outputs:
+  - eve-log:
+      enabled: yes
+      filetype: regular
+      filename: eve.json
+      types:
+        - pgsql
+        - alert:
+            payload-printable: yes
+
+app-layer:
+  protocols:
+    pgsql:
+      enabled: yes
diff --git a/tests/pgsql/pgsql-7000-ids/test.rules b/tests/pgsql/pgsql-7000-ids/test.rules
new file mode 100644 (file)
index 0000000..9bb1441
--- /dev/null
@@ -0,0 +1,5 @@
+# Rules are similar but would match on different postgresql transactions
+# disclaimer: these rules are not a good example of pgsql rules for a real-life scenario,
+# as there are no pgsql keywords used
+alert pgsql any any -> any any (msg:"Pgsql table select"; content:"select"; nocase; sid:1;)
+alert pgsql any any -> any any (msg:"Pgsql table delete"; content:"delete from"; nocase; sid:2;)
diff --git a/tests/pgsql/pgsql-7000-ids/test.yaml b/tests/pgsql/pgsql-7000-ids/test.yaml
new file mode 100644 (file)
index 0000000..fb7906c
--- /dev/null
@@ -0,0 +1,183 @@
+requires:
+   min-version: 8
+args:
+- -k none
+
+pcap: ../pgsql-simple-query-rollback/input.pcap
+
+checks:
+- filter:
+    count: 9
+    match:
+      event_type: alert
+# check 2
+- filter:
+    count: 1
+    match:
+      alert.signature: Pgsql table delete
+      alert.signature_id: 2
+      app_proto: pgsql
+      direction: to_server
+      event_type: alert
+      payload_printable: Q....DELETE FROM new_table WHERE NAME='Remus';.
+      pcap_cnt: 21
+      pgsql.request.simple_query: DELETE FROM new_table WHERE NAME='Remus';
+      pgsql.response.command_completed: DELETE 1
+      pgsql.tx_id: 6
+      stream: 1
+      tx_id: 5
+# check 3
+- filter:
+    count: 1
+    match:
+      alert.signature: Pgsql table delete
+      alert.signature_id: 2
+      app_proto: pgsql
+      direction: to_server
+      event_type: alert
+      payload_printable: Q...1DELETE FROM new_table WHERE NAME='Londubat';.
+      pcap_cnt: 24
+      pgsql.request.simple_query: DELETE FROM new_table WHERE NAME='Londubat';
+      pgsql.response.command_completed: DELETE 1
+      pgsql.tx_id: 7
+      stream: 1
+      tx_id: 6
+# check 4
+- filter:
+    count: 1
+    match:
+      alert.signature: Pgsql table delete
+      alert.signature_id: 2
+      app_proto: pgsql
+      direction: to_server
+      event_type: alert
+      payload_printable: Q...1DELETE FROM new_table WHERE NAME='Hermione';.
+      pcap_cnt: 26
+      pgsql.request.simple_query: DELETE FROM new_table WHERE NAME='Hermione';
+      pgsql.response.command_completed: DELETE 1
+      pgsql.tx_id: 8
+      stream: 1
+      tx_id: 7
+# check 5
+- filter:
+    count: 1
+    match:
+      alert.signature: Pgsql table delete
+      alert.signature_id: 2
+      app_proto: pgsql
+      direction: to_server
+      event_type: alert
+      payload_printable: Q.../DELETE FROM new_table WHERE NAME='Maugre';.
+      pcap_cnt: 28
+      pgsql.request.simple_query: DELETE FROM new_table WHERE NAME='Maugre';
+      pgsql.response.command_completed: DELETE 1
+      pgsql.tx_id: 9
+      stream: 1
+      tx_id: 8
+# check 6
+- filter:
+    count: 1
+    match:
+      alert.signature: Pgsql table select
+      alert.signature_id: 1
+      app_proto: pgsql
+      direction: to_server
+      event_type: alert
+      payload_printable: Q....SELECT 1/0;.
+      pcap_cnt: 43
+      pgsql.request.simple_query: SELECT 1/0;
+      pgsql.response.code: '22012'
+      pgsql.response.file: d:\pginstaller_13.auto\postgres.windows-x64\src\backend\utils\adt\int.c
+      pgsql.response.line: '824'
+      pgsql.response.message: division by zero
+      pgsql.response.routine: int4div
+      pgsql.response.severity_localizable: ERROR
+      pgsql.response.severity_non_localizable: ERROR
+      pgsql.tx_id: 14
+      stream: 1
+      tx_id: 13
+# check 7
+- filter:
+    count: 1
+    match:
+      alert.signature: Pgsql table select
+      alert.signature_id: 1
+      app_proto: pgsql
+      direction: to_server
+      event_type: alert
+      payload_printable: Q....SELECT * FROM new_table;.
+      pcap_cnt: 57
+      pgsql.request.simple_query: SELECT * FROM new_table;
+      pgsql.response.code: 25P02
+      pgsql.response.file: d:\pginstaller_13.auto\postgres.windows-x64\src\backend\tcop\postgres.c
+      pgsql.response.line: '1105'
+      pgsql.response.message: current transaction is aborted, commands ignored until
+        end of transaction block
+      pgsql.response.routine: exec_simple_query
+      pgsql.response.severity_localizable: ERROR
+      pgsql.response.severity_non_localizable: ERROR
+      pgsql.tx_id: 17
+      stream: 1
+      tx_id: 16
+# check 8
+- filter:
+    count: 1
+    match:
+      alert.signature: Pgsql table select
+      alert.signature_id: 1
+      app_proto: pgsql
+      direction: to_server
+      event_type: alert
+      payload_printable: Q....SELECT 1/0;.
+      pcap_cnt: 76
+      pgsql.request.simple_query: SELECT 1/0;
+      pgsql.response.code: '22012'
+      pgsql.response.file: d:\pginstaller_13.auto\postgres.windows-x64\src\backend\utils\adt\int.c
+      pgsql.response.line: '824'
+      pgsql.response.message: division by zero
+      pgsql.response.routine: int4div
+      pgsql.response.severity_localizable: ERROR
+      pgsql.response.severity_non_localizable: ERROR
+      pgsql.tx_id: 23
+      stream: 1
+      tx_id: 22
+# check 9
+- filter:
+    count: 1
+    match:
+      alert.signature: Pgsql table select
+      alert.signature_id: 1
+      app_proto: pgsql
+      direction: to_server
+      event_type: alert
+      payload_printable: Q....SELECT * FROM new_table;.
+      pcap_cnt: 84
+      pgsql.request.simple_query: SELECT * FROM new_table;
+      pgsql.response.command_completed: SELECT 8
+      pgsql.response.data_rows: 8
+      pgsql.response.data_size: 236
+      pgsql.response.field_count: 2
+      pgsql.tx_id: 26
+      stream: 1
+      tx_id: 25
+# check 10
+- filter:
+    count: 1
+    match:
+      alert.signature: Pgsql table select
+      alert.signature_id: 1
+      app_proto: pgsql
+      direction: to_client
+      event_type: alert
+      payload_printable: "T...5..name...@*..............email...@*...........\"..D...1.....\n\
+        Dumbledore....prof_dumbledore@gmail.comD...2.....\nMcGonagall....prof_mc.gonagall@gmail.comD...'......Rogue....prof_rogue@yahoo.comD...)......Hagrid....prof_hagrid@gmail.comD...,......Hermione....prof_gramger@gmail.comD...'......Remus....prof_lupin@gmail.comD...)......Maugre....prof_folloy@gmail.comD...-......Londubat....prof_londubat@gmail.comC...\r\
+        SELECT 8.Z....I"
+      pcap_cnt: 87
+      pgsql.request.simple_query: SELECT * FROM new_table;
+      pgsql.response.command_completed: SELECT 8
+      pgsql.response.data_rows: 8
+      pgsql.response.data_size: 236
+      pgsql.response.field_count: 2
+      pgsql.tx_id: 26
+      stream: 1
+      tx_id: 25
diff --git a/tests/rules/pgsql-7000/suricata.yaml b/tests/rules/pgsql-7000/suricata.yaml
new file mode 100644 (file)
index 0000000..d6dd6a5
--- /dev/null
@@ -0,0 +1,22 @@
+%YAML 1.1
+---
+
+outputs:
+  - eve-log:
+      enabled: yes
+      filetype: regular
+      filename: eve.json
+      types:
+        - pgsql
+        - alert:
+            payload: yes
+            payload-printable: yes
+            packet: yes
+
+engine-analysis:
+  rules: yes
+
+app-layer:
+  protocols:
+    pgsql:
+      enabled: yes
diff --git a/tests/rules/pgsql-7000/test.rules b/tests/rules/pgsql-7000/test.rules
new file mode 100644 (file)
index 0000000..c2a60ed
--- /dev/null
@@ -0,0 +1,4 @@
+# disclaimer: these rules are not a good example of pgsql rules for a real-life scenario,
+# as there are no pgsql keywords used
+alert pgsql any any -> any any (msg:"Pgsql table select"; content:"select"; nocase; sid:1;)
+alert pgsql any any -> any any (msg:"Pgsql table delete"; content:"delete from"; nocase; sid:2;)
diff --git a/tests/rules/pgsql-7000/test.yaml b/tests/rules/pgsql-7000/test.yaml
new file mode 100644 (file)
index 0000000..ef41a0e
--- /dev/null
@@ -0,0 +1,92 @@
+requires:
+  pcap: false
+  min-version: 7
+
+args:
+- --engine-analysis
+
+checks:
+- filter:
+    filename: rules.json
+    count: 1
+    match:
+      id: 1
+      raw: "alert pgsql any any -> any any (msg:\"Pgsql table select\"; content:\"select\"; nocase; sid:1;)"
+      app_proto: "pgsql"
+      requirements[0]: "payload"
+      requirements[1]: "flow"
+      type: "stream"
+      flags[0]: "src_any"
+      flags[1]: "dst_any"
+      flags[2]: "sp_any"
+      flags[3]: "dp_any"
+      flags[4]: "applayer"
+      flags[5]: "need_stream"
+      flags[6]: "toserver"
+      flags[7]: "toclient"
+      flags[8]: "prefilter"
+      pkt_engines[0].name: "payload"
+      pkt_engines[0].is_mpm: true
+      lists.payload.matches[0].name: content
+      lists.payload.matches[0].content.pattern: "select"
+      lists.payload.matches[0].content.length: 6
+      lists.payload.matches[0].content.nocase: true
+      lists.payload.matches[0].content.negated: false
+      lists.payload.matches[0].content.starts_with: false
+      lists.payload.matches[0].content.ends_with: false
+      lists.payload.matches[0].content.is_mpm: true
+      lists.payload.matches[0].content.no_double_inspect: true
+      lists.payload.matches[0].content.fast_pattern: false
+      lists.payload.matches[0].content.relative_next: false
+      mpm.buffer: "payload"
+      mpm.pattern: "select"
+      mpm.length: 6
+      mpm.nocase: true
+      mpm.starts_with: false
+      mpm.ends_with: false
+      mpm.is_mpm: true
+      mpm.no_double_inspect: true
+      mpm.fast_pattern: false
+      mpm.relative_next: false
+- filter:
+    filename: rules.json
+    count: 1
+    match:
+      id: 2
+      raw: "alert pgsql any any -> any any (msg:\"Pgsql table delete\"; content:\"delete from\"; nocase; sid:2;)"
+      app_proto: "pgsql"
+      requirements[0]: "payload"
+      requirements[1]: "flow"
+      type: "stream"
+      flags[0]: "src_any"
+      flags[1]: "dst_any"
+      flags[2]: "sp_any"
+      flags[3]: "dp_any"
+      flags[4]: "applayer"
+      flags[5]: "need_stream"
+      flags[6]: "toserver"
+      flags[7]: "toclient"
+      flags[8]: "prefilter"
+      pkt_engines[0].name: "payload"
+      pkt_engines[0].is_mpm: true
+      lists.payload.matches[0].name: content
+      lists.payload.matches[0].content.pattern: "delete|20|from"
+      lists.payload.matches[0].content.length: 11
+      lists.payload.matches[0].content.nocase: true
+      lists.payload.matches[0].content.negated: false
+      lists.payload.matches[0].content.starts_with: false
+      lists.payload.matches[0].content.ends_with: false
+      lists.payload.matches[0].content.is_mpm: true
+      lists.payload.matches[0].content.no_double_inspect: true
+      lists.payload.matches[0].content.fast_pattern: false
+      lists.payload.matches[0].content.relative_next: false
+      mpm.buffer: "payload"
+      mpm.pattern: "delete|20|from"
+      mpm.length: 11
+      mpm.nocase: true
+      mpm.starts_with: false
+      mpm.ends_with: false
+      mpm.is_mpm: true
+      mpm.no_double_inspect: true
+      mpm.fast_pattern: false
+      mpm.relative_next: false