From: Philippe Antoine Date: Sat, 6 Jan 2024 22:09:05 +0000 (+0100) Subject: websocket: configurable logging of payload in alerts X-Git-Tag: suricata-8.0.0-beta1~1461 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0291d37009f4ff4604c2790ac1515a586d3a7773;p=thirdparty%2Fsuricata.git websocket: configurable logging of payload in alerts --- diff --git a/etc/schema.json b/etc/schema.json index 451b1a6f63..24e9da1d1a 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -5674,6 +5674,12 @@ }, "opcode": { "type": "string" + }, + "payload_base64": { + "type": "string" + }, + "payload_printable": { + "type": "string" } }, "additionalProperties": false diff --git a/rust/src/websocket/logger.rs b/rust/src/websocket/logger.rs index ab8b519626..189d3ab7d9 100644 --- a/rust/src/websocket/logger.rs +++ b/rust/src/websocket/logger.rs @@ -21,7 +21,9 @@ use crate::detect::EnumString; use crate::jsonbuilder::{JsonBuilder, JsonError}; use std; -fn log_websocket(tx: &WebSocketTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> { +fn log_websocket( + tx: &WebSocketTransaction, js: &mut JsonBuilder, pp: bool, pb64: bool, +) -> Result<(), JsonError> { js.open_object("websocket")?; js.set_bool("fin", tx.pdu.fin)?; if let Some(xorkey) = tx.pdu.mask { @@ -32,6 +34,15 @@ fn log_websocket(tx: &WebSocketTransaction, js: &mut JsonBuilder) -> Result<(), } else { js.set_string("opcode", &format!("unknown-{}", tx.pdu.opcode))?; } + if pp { + js.set_string( + "payload_printable", + &String::from_utf8_lossy(&tx.pdu.payload), + )?; + } + if pb64 { + js.set_base64("payload_base64", &tx.pdu.payload)?; + } js.close()?; Ok(()) } @@ -41,5 +52,12 @@ pub unsafe extern "C" fn rs_websocket_logger_log( tx: *mut std::os::raw::c_void, js: &mut JsonBuilder, ) -> bool { let tx = cast_pointer!(tx, WebSocketTransaction); - log_websocket(tx, js).is_ok() + log_websocket(tx, js, false, false).is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn SCWebSocketLogDetails( + tx: &WebSocketTransaction, js: &mut JsonBuilder, pp: bool, pb64: bool, +) -> bool { + log_websocket(tx, js, pp, pb64).is_ok() } diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 8465e2a566..eb88af294a 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -85,12 +85,16 @@ #define LOG_JSON_RULE_METADATA BIT_U16(8) #define LOG_JSON_RULE BIT_U16(9) #define LOG_JSON_VERDICT BIT_U16(10) +#define LOG_JSON_WEBSOCKET_PAYLOAD BIT_U16(11) +#define LOG_JSON_WEBSOCKET_PAYLOAD_BASE64 BIT_U16(12) #define METADATA_DEFAULTS ( LOG_JSON_FLOW | \ LOG_JSON_APP_LAYER | \ LOG_JSON_RULE_METADATA) -#define JSON_BODY_LOGGING (LOG_JSON_HTTP_BODY | LOG_JSON_HTTP_BODY_BASE64) +#define JSON_BODY_LOGGING \ + (LOG_JSON_HTTP_BODY | LOG_JSON_HTTP_BODY_BASE64 | LOG_JSON_WEBSOCKET_PAYLOAD | \ + LOG_JSON_WEBSOCKET_PAYLOAD_BASE64) #define JSON_STREAM_BUFFER_SIZE 4096 @@ -293,6 +297,20 @@ static void AlertAddAppLayer(const Packet *p, JsonBuilder *jb, void *tx = AppLayerParserGetTx(p->flow->proto, proto, state, tx_id); if (tx) { jb_get_mark(jb, &mark); + switch (proto) { + // first check some protocols need special options for alerts logging + case ALPROTO_WEBSOCKET: + if (option_flags & + (LOG_JSON_WEBSOCKET_PAYLOAD | LOG_JSON_WEBSOCKET_PAYLOAD_BASE64)) { + bool pp = (option_flags & LOG_JSON_WEBSOCKET_PAYLOAD) != 0; + bool pb64 = (option_flags & LOG_JSON_WEBSOCKET_PAYLOAD_BASE64) != 0; + if (!SCWebSocketLogDetails(tx, jb, pp, pb64)) { + jb_restore_mark(jb, &mark); + } + // nothing more to log or do + return; + } + } if (!al->LogTx(tx, jb)) { jb_restore_mark(jb, &mark); } @@ -874,6 +892,8 @@ 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, "websocket-payload-printable", LOG_JSON_WEBSOCKET_PAYLOAD, &flags); + SetFlag(conf, "websocket-payload", LOG_JSON_WEBSOCKET_PAYLOAD_BASE64, &flags); SetFlag(conf, "verdict", LOG_JSON_VERDICT, &flags); /* Check for obsolete flags and warn that they have no effect. */ diff --git a/suricata.yaml.in b/suricata.yaml.in index 0c83e29660..89d1516a46 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -168,6 +168,8 @@ outputs: # metadata: no # enable inclusion of app layer metadata with alert. Default yes # http-body: yes # Requires metadata; enable dumping of HTTP body in Base64 # http-body-printable: yes # Requires metadata; enable dumping of HTTP body in printable format + # websocket-payload: yes # Requires metadata; enable dumping of WebSocket Payload in Base64 + # websocket-payload-printable: yes # Requires metadata; enable dumping of WebSocket Payload in printable format # Enable the logging of tagged packets for rules using the # "tag" keyword.