]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect: add ldap.request.attribute_type
authorAlice Akaki <akakialice@gmail.com>
Thu, 13 Feb 2025 05:18:37 +0000 (01:18 -0400)
committerJason Ish <jason.ish@oisf.net>
Mon, 7 Apr 2025 21:25:04 +0000 (15:25 -0600)
ldap.request.attribute_type matches on LDAP attribute type/description
This keyword maps the following eve fields:
ldap.request.search_request.attributes[]
ldap.request.modify_request.changes[].modification.attribute_type
ldap.request.add_request.attributes[].name
ldap.request.compare_request.attribute_value_assertion.description
It is a sticky buffer
Supports multiple buffer matching
Supports prefiltering

Ticket: #7533

doc/userguide/rules/ldap-keywords.rst
doc/userguide/rules/multi-buffer-matching.rst
rust/src/ldap/detect.rs

index dd196a13e768ae0f97757757d67611d51ca44f0c..d530177a79ba1beb5acc1d8cd939c28cbac856ad 100644 (file)
@@ -455,4 +455,46 @@ Example of a signature that would alert if a packet has the LDAP error message `
 
 .. container:: example-rule
 
-  alert ldap any any -> any any (msg:"Test LDAP error message"; ldap.responses.message; content:"Size limit exceeded"; sid:1;)
\ No newline at end of file
+  alert ldap any any -> any any (msg:"Test LDAP error message"; ldap.responses.message; content:"Size limit exceeded"; sid:1;)
+
+ldap.request.attribute_type
+---------------------------
+
+Matches on LDAP attribute type from request operations.
+
+Comparison is case-sensitive.
+
+Syntax::
+
+ ldap.request.attribute_type; content:"<content to match against>";
+
+``ldap.request.attribute_type`` is a 'sticky buffer' and can be used as a ``fast_pattern``.
+
+``ldap.request.attribute_type`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+This keyword maps to the EVE fields:
+
+   - ``ldap.request.search_request.attributes[]``
+   - ``ldap.request.modify_request.changes[].modification.attribute_type``
+   - ``ldap.request.add_request.attributes[].name``
+   - ``ldap.request.compare_request.attribute_value_assertion.description``
+
+Example
+^^^^^^^
+
+Example of a signature that would alert if a packet has the LDAP attribute type ``objectClass``:
+
+.. container:: example-rule
+
+  alert ldap any any -> any any (msg:"Test attribute type"; :example-rule-emphasis:`ldap.request.attribute_type; content:"objectClass";` sid:1;)
+
+It is possible to use the keyword ``ldap.request.operation`` in the same rule to
+specify the operation to match.
+
+Here is an example of a signature that would alert if a packet has an LDAP
+add request operation and contains the LDAP attribute type
+``objectClass``.
+
+.. container:: example-rule
+
+  alert ldap any any -> any any (msg:"Test attribute type and operation"; :example-rule-emphasis:`ldap.request.operation:add_request; ldap.request.attribute_type; content:"objectClass";` sid:1;)
index 1985f389a99671e2e3fa14a3c280b46fe5d563be..35a511f403a1d8926114ce21ece95198e75992fa 100644 (file)
@@ -86,6 +86,7 @@ following keywords:
 * ``ike.vendor``
 * ``krb5_cname``
 * ``krb5_sname``
+* ``ldap.request.attribute_type``
 * ``ldap.responses.dn``
 * ``ldap.responses.message``
 * ``mqtt.subscribe.topic``
index 857b400982911f420699136a85c87542477ad569..6ea4f7d69dc983d1d413e149538ff627821a6295 100644 (file)
@@ -70,6 +70,7 @@ static mut G_LDAP_RESPONSES_DN_BUFFER_ID: c_int = 0;
 static mut G_LDAP_RESPONSES_RESULT_CODE_KW_ID: c_int = 0;
 static mut G_LDAP_RESPONSES_RESULT_CODE_BUFFER_ID: c_int = 0;
 static mut G_LDAP_RESPONSES_MSG_BUFFER_ID: c_int = 0;
+static mut G_LDAP_REQUEST_ATTRIBUTE_TYPE_BUFFER_ID: c_int = 0;
 
 unsafe extern "C" fn ldap_parse_protocol_req_op(
     ustr: *const std::os::raw::c_char,
@@ -560,6 +561,80 @@ unsafe extern "C" fn ldap_tx_get_responses_msg(
     return true;
 }
 
+unsafe extern "C" fn ldap_detect_request_attibute_type_setup(
+    de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char,
+) -> c_int {
+    if DetectSignatureSetAppProto(s, ALPROTO_LDAP) != 0 {
+        return -1;
+    }
+    if DetectBufferSetActiveList(de, s, G_LDAP_REQUEST_ATTRIBUTE_TYPE_BUFFER_ID) < 0 {
+        return -1;
+    }
+    return 0;
+}
+
+unsafe extern "C" fn ldap_detect_request_attribute_type_get_data(
+    de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8,
+    tx: *const c_void, list_id: c_int, local_id: u32,
+) -> *mut c_void {
+    return DetectHelperGetMultiData(
+        de,
+        transforms,
+        flow,
+        flow_flags,
+        tx,
+        list_id,
+        local_id,
+        ldap_tx_get_req_attribute_type,
+    );
+}
+
+unsafe extern "C" fn ldap_tx_get_req_attribute_type(
+    tx: *const c_void, _flags: u8, local_id: u32, buffer: *mut *const u8, buffer_len: *mut u32,
+) -> bool {
+    let tx = cast_pointer!(tx, LdapTransaction);
+
+    *buffer = std::ptr::null();
+    *buffer_len = 0;
+    if let Some(request) = &tx.request {
+        let str_buffer: &str = match &request.protocol_op {
+            ProtocolOp::SearchRequest(req) => {
+                if local_id as usize >= req.attributes.len() {
+                    return false;
+                }
+                req.attributes[local_id as usize].0.as_str()
+            }
+            ProtocolOp::ModifyRequest(req) => {
+                if local_id as usize >= req.changes.len() {
+                    return false;
+                }
+                req.changes[local_id as usize]
+                    .modification
+                    .attr_type
+                    .0
+                    .as_str()
+            }
+            ProtocolOp::AddRequest(req) => {
+                if local_id as usize >= req.attributes.len() {
+                    return false;
+                }
+                req.attributes[local_id as usize].attr_type.0.as_str()
+            }
+            ProtocolOp::CompareRequest(req) => {
+                if local_id > 0 {
+                    return false;
+                }
+                req.ava.attribute_desc.0.as_str()
+            }
+            _ => return false,
+        };
+        *buffer = str_buffer.as_ptr();
+        *buffer_len = str_buffer.len() as u32;
+        return true;
+    }
+    return false;
+}
+
 #[no_mangle]
 pub unsafe extern "C" fn SCDetectLdapRegister() {
     let kw = SCSigTableElmt {
@@ -682,4 +757,23 @@ pub unsafe extern "C" fn SCDetectLdapRegister() {
         false, //to server
         ldap_detect_responses_msg_get_data,
     );
+    let kw = SCSigTableElmt {
+        name: b"ldap.request.attribute_type\0".as_ptr() as *const libc::c_char,
+        desc: b"match request LDAP attribute type\0".as_ptr() as *const libc::c_char,
+        url: b"/rules/ldap-keywords.html#ldap.request.attribute_type\0".as_ptr()
+            as *const libc::c_char,
+        Setup: ldap_detect_request_attibute_type_setup,
+        flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER,
+        AppLayerTxMatch: None,
+        Free: None,
+    };
+    let _g_ldap_request_attribute_type_kw_id = DetectHelperKeywordRegister(&kw);
+    G_LDAP_REQUEST_ATTRIBUTE_TYPE_BUFFER_ID = DetectHelperMultiBufferMpmRegister(
+        b"ldap.request.attribute_type\0".as_ptr() as *const libc::c_char,
+        b"LDAP REQUEST ATTRIBUTE TYPE\0".as_ptr() as *const libc::c_char,
+        ALPROTO_LDAP,
+        false, //to client
+        true,  //to server
+        ldap_detect_request_attribute_type_get_data,
+    );
 }