From 755b2e38a685e3aa60d0cec1022fbc49e7a290e5 Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Wed, 5 Jul 2023 12:52:53 -0300 Subject: [PATCH 1/4] output/alert: add verdict field Related to Bug #5464 (cherry picked from commit 53b8defd793f0f8fe2ca5459822d0e11f3d69929) --- src/output-json-alert.c | 70 ++++++++++++++++++++++++++++++++++++++++- src/output-json-alert.h | 4 ++- suricata.yaml.in | 4 +++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 9202d308e7be..21eec7beedc6 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2020 Open Information Security Foundation +/* Copyright (C) 2013-2023 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -94,6 +94,7 @@ #define LOG_JSON_HTTP_BODY_BASE64 BIT_U16(7) #define LOG_JSON_RULE_METADATA BIT_U16(8) #define LOG_JSON_RULE BIT_U16(9) +#define LOG_JSON_VERDICT BIT_U16(10) #define METADATA_DEFAULTS ( LOG_JSON_FLOW | \ LOG_JSON_APP_LAYER | \ @@ -572,6 +573,68 @@ static void AlertAddFiles(const Packet *p, JsonBuilder *jb, const uint64_t tx_id } } +bool PacketCheckAction(const Packet *p, const uint8_t a) +{ + if (likely(p->root == NULL)) { + return (p->action & a) != 0; + } else { + /* check against both */ + const uint8_t actions = p->action | p->root->action; + return (actions & a) != 0; + } +} + +/** + * \brief Build verdict object + * + * \param p Pointer to Packet current being logged + * + */ +void EveAddVerdict(JsonBuilder *jb, const Packet *p) +{ + jb_open_object(jb, "verdict"); + + /* add verdict info */ + if (PacketCheckAction(p, ACTION_REJECT_ANY)) { + // check rule to define type of reject packet sent + if (EngineModeIsIPS()) { + JB_SET_STRING(jb, "action", "drop"); + } else { + JB_SET_STRING(jb, "action", "alert"); + } + if (PacketCheckAction(p, ACTION_REJECT)) { + JB_SET_STRING(jb, "reject-target", "to_client"); + } else if (PacketCheckAction(p, ACTION_REJECT_DST)) { + JB_SET_STRING(jb, "reject-target", "to_server"); + } else if (PacketCheckAction(p, ACTION_REJECT_BOTH)) { + JB_SET_STRING(jb, "reject-target", "both"); + } + jb_open_array(jb, "reject"); + switch (p->proto) { + case IPPROTO_UDP: + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + jb_append_string(jb, "icmp-prohib"); + break; + case IPPROTO_TCP: + jb_append_string(jb, "tcp-reset"); + break; + } + jb_close(jb); + + } else if (PacketCheckAction(p, ACTION_DROP) && EngineModeIsIPS()) { + JB_SET_STRING(jb, "action", "drop"); + } else if (p->alerts.alerts[p->alerts.cnt].action & ACTION_PASS) { + JB_SET_STRING(jb, "action", "pass"); + } else { + // TODO make sure we don't have a situation where this wouldn't work + JB_SET_STRING(jb, "action", "alert"); + } + + /* Close verdict */ + jb_close(jb); +} + static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) { MemBuffer *payload = aft->payload_buffer; @@ -708,6 +771,10 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) jb_set_string(jb, "xff", xff_buffer); } + if (json_output_ctx->flags & LOG_JSON_VERDICT) { + EveAddVerdict(jb, p); + } + OutputJsonBuilderBuffer(jb, aft->file_ctx, &aft->json_buffer); jb_free(jb); } @@ -938,6 +1005,7 @@ static void JsonAlertLogSetupMetadata(AlertJsonOutputCtx *json_output_ctx, SetFlag(conf, "payload-printable", LOG_JSON_PAYLOAD, &flags); SetFlag(conf, "http-body-printable", LOG_JSON_HTTP_BODY, &flags); SetFlag(conf, "http-body", LOG_JSON_HTTP_BODY_BASE64, &flags); + SetFlag(conf, "verdict", LOG_JSON_VERDICT, &flags); /* Check for obsolete configuration flags to enable specific * protocols. These are now just aliases for enabling diff --git a/src/output-json-alert.h b/src/output-json-alert.h index 879e39919fff..8fab7bfc4748 100644 --- a/src/output-json-alert.h +++ b/src/output-json-alert.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2014 Open Information Security Foundation +/* Copyright (C) 2013-2023 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -30,6 +30,8 @@ void JsonAlertLogRegister(void); void AlertJsonHeader(void *ctx, const Packet *p, const PacketAlert *pa, JsonBuilder *js, uint16_t flags, JsonAddrInfo *addr); +bool PacketCheckAction(const Packet *p, const uint8_t a); +void EveAddVerdict(JsonBuilder *jb, const Packet *p); #endif /* __OUTPUT_JSON_ALERT_H__ */ diff --git a/suricata.yaml.in b/suricata.yaml.in index eb985c260e93..f284111c9e88 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -164,6 +164,10 @@ outputs: # Enable the logging of tagged packets for rules using the # "tag" keyword. tagged-packets: yes + # Enable logging the final action taken on a packet by the engine + # (e.g: the alert may have action 'allowed' but the verdict be + # 'drop' due to another alert. That's the engine's verdict) + # verdict: yes - anomaly: # Anomaly log records describe unexpected conditions such # as truncated packets, packets with invalid IP/UDP/TCP From 989e5a10e8dc69642a69d94414edb3be869fa342 Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Fri, 28 Jul 2023 15:42:35 -0300 Subject: [PATCH 2/4] output/drop: add verdict field Related to Bug #5464 (cherry picked from commit 0437173848d98812f74a28f283c327178bf500dd) --- doc/userguide/output/eve/eve-json-output.rst | 16 ++++++++++++++++ src/output-json-drop.c | 17 ++++++++++++++--- suricata.yaml.in | 3 +++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst index 5cd9e62192c4..bc0637bf0db7 100644 --- a/doc/userguide/output/eve/eve-json-output.rst +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -288,6 +288,22 @@ enabled, then the log gets more verbose. By using ``custom`` it is possible to select which TLS fields to log. +Drops +~~~~~ + +Drops are event types logged when the engine drops a packet. + +Config:: + + - drop: + alerts: yes # log alerts that caused drops + flows: all # start or all: 'start' logs only a single drop + # per flow direction. All logs each dropped pkt. + # Enable logging the final action taken on a packet by the engine + # (will show more information in case of a drop caused by 'reject') + verdict: yes + + Date modifiers in filename ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 90ca0dba6108..f547178532ae 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation +/* Copyright (C) 2007-2023 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -58,7 +58,8 @@ #define MODULE_NAME "JsonDropLog" -#define LOG_DROP_ALERTS 1 +#define LOG_DROP_ALERTS BIT_U8(1) +#define LOG_DROP_VERDICT BIT_U8(2) typedef struct JsonDropOutputCtx_ { LogFileCtx *file_ctx; @@ -155,6 +156,10 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) /* Close drop. */ jb_close(js); + if (aft->drop_ctx->flags & LOG_DROP_VERDICT) { + EveAddVerdict(js, p); + } + if (aft->drop_ctx->flags & LOG_DROP_ALERTS) { int logged = 0; int i; @@ -280,7 +285,7 @@ static OutputInitResult JsonDropLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ const char *extended = ConfNodeLookupChildValue(conf, "alerts"); if (extended != NULL) { if (ConfValIsTrue(extended)) { - drop_ctx->flags = LOG_DROP_ALERTS; + drop_ctx->flags |= LOG_DROP_ALERTS; } } extended = ConfNodeLookupChildValue(conf, "flows"); @@ -294,6 +299,12 @@ static OutputInitResult JsonDropLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ "'flow' are 'start' and 'all'"); } } + extended = ConfNodeLookupChildValue(conf, "verdict"); + if (extended != NULL) { + if (ConfValIsTrue(extended)) { + drop_ctx->flags |= LOG_DROP_VERDICT; + } + } } drop_ctx->file_ctx = ajt->file_ctx; diff --git a/suricata.yaml.in b/suricata.yaml.in index f284111c9e88..37ed645a5fb0 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -254,6 +254,9 @@ outputs: # alerts: yes # log alerts that caused drops # flows: all # start or all: 'start' logs only a single drop # # per flow direction. All logs each dropped pkt. + # Enable logging the final action taken on a packet by the engine + # (will show more information in case of a drop caused by 'reject') + # verdict: yes - smtp: #extended: yes # enable this for extended logging information # this includes: bcc, message-id, subject, x_mailer, user-agent From 84fde716914b183e1cfb47a3abd64f60da5e7547 Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Thu, 22 Dec 2022 20:47:24 -0300 Subject: [PATCH 3/4] userguide/eve: format and reorganize alert section The `field action` portion seemed to be comprised of a more generic section that followed it. Also formatted the section for lines to be within the character limit. (cherry picked from commit 9900bdc162cc876151e680ea088f89b54edb038f) --- doc/userguide/output/eve/eve-json-format.rst | 72 ++++++++++++++++---- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/doc/userguide/output/eve/eve-json-format.rst b/doc/userguide/output/eve/eve-json-format.rst index 2a2e557480cc..d713bb338e95 100644 --- a/doc/userguide/output/eve/eve-json-format.rst +++ b/doc/userguide/output/eve/eve-json-format.rst @@ -73,23 +73,17 @@ generated the event. Event type: Alert ----------------- -Field action -~~~~~~~~~~~~ - -Possible values: "allowed" and "blocked" - -Example: - -:: - - - "action":"allowed" +This field contains data about a signature that matched, such as +``signature_id`` (``sid`` in the rule) and the ``signature`` (``msg`` in the +rule). -Action is set to "allowed" unless a rule used the "drop" action and Suricata is in IPS mode, or when the rule used the "reject" action. - -It can also contain information about Source and Target of the attack in the alert.source and alert.target field it target keyword is used in +It can also contain information about Source and Target of the attack in the +``alert.source`` and ``alert.target`` field if target keyword is used in the signature. +This event will also have the ``pcap_cnt`` field, when running in pcap mode, to +indicate which packet triggered the signature. + :: "alert": { @@ -109,6 +103,56 @@ the signature. "port": 80 }, +Action field +~~~~~~~~~~~~ + +Possible values: "allowed" and "blocked". + +Example: + +:: + + "action":"allowed" + +Action is set to "allowed" unless a rule used the "drop" action and Suricata is +in IPS mode, or when the rule used the "reject" action. It is important to note +that this does not necessarily indicate the final verdict for a given packet or +flow, since one packet may match on several rules. + +.. _verdict-alert: + +Verdict +~~~~~~~ + +An object containning info on the final action that will be applied to a given +packet, based on all the signatures triggered by it and other possible events +(e.g., a flow drop). For that reason, it is possible for an alert with +an action ``allowed`` to have a verdict ``drop``, in IPS mode, for instance, if +that packet was dropped due to a different alert. + +* Action: ``alert``, ``pass``, ``drop`` (this latter only occurs in IPS mode) +* Reject-target: ``to_server``, ``to_client``, ``both`` (only occurs for 'reject' rules) +* Reject: an array of strings with possible reject types: ``tcp-reset``, + ``icmp-prohib`` (only occurs for 'reject' rules) + +Example: + +:: + + "verdict": { + "action": "drop", + "reject-target": "to_client", + "reject": "[icmp-prohib]" + } + + +Pcap Field +~~~~~~~~~~ + +If pcap log capture is active in `multi` mode, a `capture_file` key will be added to the event +with value being the full path of the pcap file where the corresponding packets +have been extracted. + Event type: Anomaly ------------------- From 4669862c310a867a1aa42f751317b8115abd12c8 Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Fri, 28 Jul 2023 15:25:25 -0300 Subject: [PATCH 4/4] userguide: add sections about missing appprotos The section about eve json format was missing IKE, and DHCP sections. --- doc/userguide/output/eve/eve-json-format.rst | 181 +++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/doc/userguide/output/eve/eve-json-format.rst b/doc/userguide/output/eve/eve-json-format.rst index d713bb338e95..2325a9d73f4c 100644 --- a/doc/userguide/output/eve/eve-json-format.rst +++ b/doc/userguide/output/eve/eve-json-format.rst @@ -1849,3 +1849,184 @@ Example of HTTP2 logging, of a request and response: ] } } + + +Event type: IKE +--------------- + +The parser implementations for IKEv1 and IKEv2 have a slightly different feature +set. They can be distinguished using the "version_major" field (which equals +either 1 or 2). +The unique properties are contained within a separate "ikev1" and "ikev2" sub-object. + +Fields +~~~~~~ + +* "init_spi", "resp_spi": The Security Parameter Index (SPI) of the initiator and responder. +* "version_major": Major version of the ISAKMP header. +* "version_minor": Minor version of the ISAKMP header. +* "payload": List of payload types in the current packet. +* "exchange_type": Type of the exchange, as numeric values. +* "exchange_type_verbose": Type of the exchange, in human-readable form. Needs ``extended: yes`` set in the ``ike`` EVE output option. +* "alg_enc", "alg_hash", "alg_auth", "alg_dh", "alg_esn": Properties of the chosen security association by the server. +* "ikev1.encrypted_payloads": Set to ``true`` if the payloads in the packet are encrypted. +* "ikev1.doi": Value of the domain of interpretation (DOI). +* "ikev1.server.key_exchange_payload", "ikev1.client.key_exchange_payload": Public key exchange payloads of the server and client. +* "ikev1.server.key_exchange_payload_length", "ikev1.client.key_exchange_payload_length": Length of the public key exchange payload. +* "ikev1.server.nonce_payload", "ikev1.client.nonce_payload": Nonce payload of the server and client. +* "ikev1.server.nonce_payload_length", "ikev1.client.nonce_payload_length": Length of the nonce payload. +* "ikev1.client.client_proposals": List of the security associations proposed to the server. +* "ikev1.vendor_ids": List of the vendor IDs observed in the communication. +* "server_proposals": List of server proposals with parameters, if there are more than one. This is a non-standard case; this field is only present if such a situation was observed in the inspected traffic. + + + +Examples +~~~~~~~~ + +Example of IKE logging: + +:: + + "ike": { + "version_major": 1, + "version_minor": 0, + "init_spi": "8511617bfea2f172", + "resp_spi": "c0fc6bae013de0f5", + "message_id": 0, + "exchange_type": 2, + "exchange_type_verbose": "Identity Protection", + "sa_life_type": "LifeTypeSeconds", + "sa_life_type_raw": 1, + "sa_life_duration": "Unknown", + "sa_life_duration_raw": 900, + "alg_enc": "EncAesCbc", + "alg_enc_raw": 7, + "alg_hash": "HashSha2_256", + "alg_hash_raw": 4, + "alg_auth": "AuthPreSharedKey", + "alg_auth_raw": 1, + "alg_dh": "GroupModp2048Bit", + "alg_dh_raw": 14, + "sa_key_length": "Unknown", + "sa_key_length_raw": 256, + "alg_esn": "NoESN", + "payload": [ + "VendorID", + "Transform", + "Proposal", + "SecurityAssociation" + ], + "ikev1": { + "doi": 1, + "encrypted_payloads": false, + "client": { + "key_exchange_payload": "0bf7907681a656aabed38fb1ba8918b10d707a8e635a...", + "key_exchange_payload_length": 256, + "nonce_payload": "1427d158fc1ed6bbbc1bd81e6b74960809c87d18af5f0abef14d5274ac232904", + "nonce_payload_length": 32, + "proposals": [ + { + "sa_life_type": "LifeTypeSeconds", + "sa_life_type_raw": 1, + "sa_life_duration": "Unknown", + "sa_life_duration_raw": 900, + "alg_enc": "EncAesCbc", + "alg_enc_raw": 7, + "alg_hash": "HashSha2_256", + "alg_hash_raw": 4, + "alg_auth": "AuthPreSharedKey", + "alg_auth_raw": 1, + "alg_dh": "GroupModp2048Bit", + "alg_dh_raw": 14, + "sa_key_length": "Unknown", + "sa_key_length_raw": 256 + } + ] + }, + "server": { + "key_exchange_payload": "1e43be52b088ec840ff81865074b6d459b5ca7813b46...", + "key_exchange_payload_length": 256, + "nonce_payload": "04d78293ead007bc1a0f0c6c821a3515286a935af12ca50e08905b15d6c8fcd4", + "nonce_payload_length": 32 + }, + "vendor_ids": [ + "4048b7d56ebce88525e7de7f00d6c2d3", + "4a131c81070358455c5728f20e95452f", + "afcad71368a1f1c96b8696fc77570100", + "7d9419a65310ca6f2c179d9215529d56", + "cd60464335df21f87cfdb2fc68b6a448", + "90cb80913ebb696e086381b5ec427b1f" + ] + }, + } + + +Event type: DHCP +----------------- + +The default DHCP logging level only logs enough information to map a +MAC address to an IP address. Enable extended mode to log all DHCP +message types in full detail. + +Fields +~~~~~~ + +* "type": message type (e.g. request, reply) +* "id": DHCP transaction id +* "client_mac": client MAC address +* "assigned_ip": IP address given by DHCP server +* "client_ip": client IP address +* "dhcp_type": DHCP message type +* "client_id": DHCP client identifier +* "hostname": DHCP client host name +* "params": DHCP parameter request list +* "requested_ip": DHCP client requesting specific IP address +* "relay_ip": BOOTP relay agent IP address +* "next_server_ip": BOOTP next IP address to use for booting process +* "subnet_mask": subnet mask to use with client IP address +* "routers": IP address(es) to be used as default gateways on DHCP client +* "lease_time": Duration of IP address assignment to client +* "renewal_time": Time in seconds since client began IP address request or renewal process +* "rebinding_time": Time in seconds before the client begins to renew its IP address lease +* "dns_servers": IP address(es) of servers the client will use for DNS queries + +Examples +~~~~~~~~ + +Example of DHCP log entry (default logging level): + +:: + + "dhcp": { + "type":"reply", + "id":755466399, + "client_mac":"54:ee:75:51:e0:66", + "assigned_ip":"100.78.202.125", + "dhcp_type":"ack", + "renewal_time":21600, + "client_id":"54:ee:75:51:e0:66" + } + +Example of DHCP log entry (extended logging enabled): + +:: + + "dhcp": { + "type":"reply", + "id":2787908432, + "client_mac":"54:ee:75:51:e0:66", + "assigned_ip":"192.168.1.120", + "client_ip":"0.0.0.0", + "relay_ip":"192.168.1.1", + "next_server_ip":"0.0.0.0", + "dhcp_type":"offer", + "subnet_mask":"255.255.255.0", + "routers":["192.168.1.100"], + "hostname":"test", + "lease_time":86400, + "renewal_time":21600, + "rebinding_time":43200, + "client_id":"54:ee:75:51:e0:66", + "dns_servers":["192.168.1.50","192.168.1.49"] + }