]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect: add ldap.request.dn
authorAlice Akaki <akakialice@gmail.com>
Tue, 4 Feb 2025 02:37:15 +0000 (22:37 -0400)
committerVictor Julien <victor@inliniac.net>
Fri, 21 Feb 2025 13:57:14 +0000 (14:57 +0100)
ldap.request.dn matches on LDAPDN from request operations
This keyword maps the following eve fields:
ldap.request.bind_request.name
ldap.request.add_request.entry
ldap.request.search_request.base_object
ldap.request.modify_request.object
ldap.request.del_request.dn
ldap.request.mod_dn_request.entry
ldap.request.compare_request.entry
It is a sticky buffer
Supports prefiltering

Ticket: #7471

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

index b839f4f7a0bc7665df66a346c6a9c18c3fd20fbf..47e240a19166391c135551b74360fc18bde8f27f 100644 (file)
@@ -163,3 +163,45 @@ Example of a signature that would alert if a packet has more than 2 LDAP respons
 .. container:: example-rule
 
   alert ldap any any -> any any (msg:"Packet has more than 2 LDAP responses"; :example-rule-emphasis:`ldap.responses.count:>2;` sid:1;)
+
+ldap.request.dn
+---------------
+
+Matches on LDAP distinguished names from request operations.
+
+Comparison is case-sensitive.
+
+Syntax::
+
+ ldap.request.dn; content:dc=example,dc=com;
+
+``ldap.request.dn`` is a 'sticky buffer' and can be used as a ``fast_pattern``.
+
+This keyword maps to the EVE fields:
+``ldap.request.bind_request.name``
+``ldap.request.add_request.entry``
+``ldap.request.search_request.base_object``
+``ldap.request.modify_request.object``
+``ldap.request.del_request.dn``
+``ldap.request.mod_dn_request.entry``
+``ldap.request.compare_request.entry``
+
+Example
+^^^^^^^
+
+Example of a signature that would alert if a packet has the LDAP distinguished name ``uid=jdoe,ou=People,dc=example,dc=com``:
+
+.. container:: example-rule
+
+  alert ldap any any -> any any (msg:"Test LDAPDN"; :example-rule-emphasis:`ldap.request.dn; content:"uid=jdoe,ou=People,dc=example,dc=com";` 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
+search request operation and contains the LDAP distinguished name
+``dc=example,dc=com``.
+
+.. container:: example-rule
+
+  alert ldap any any -> any any (msg:"Test LDAPDN and operation"; :example-rule-emphasis:`ldap.request.operation:search_request; ldap.request.dn; content:"dc=example,dc=com";` sid:1;)
index fbd0c56f5ae2f0a0f5593e32f1e072a1253e6175..6088575112ef4cb6a7771b7907a4f5773dcc60fd 100644 (file)
@@ -21,10 +21,11 @@ use crate::detect::uint::{
     rs_detect_u8_free, rs_detect_u8_match, DetectUintData,
 };
 use crate::detect::{
-    DetectHelperBufferRegister, DetectHelperKeywordRegister, DetectSignatureSetAppProto,
-    SCSigTableElmt, SigMatchAppendSMToList,
+    DetectBufferSetActiveList, DetectHelperBufferMpmRegister, DetectHelperBufferRegister,
+    DetectHelperGetData, DetectHelperKeywordRegister, DetectSignatureSetAppProto, SCSigTableElmt,
+    SigMatchAppendSMToList, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT,
 };
-use crate::ldap::types::{LdapMessage, ProtocolOpCode};
+use crate::ldap::types::{LdapMessage, ProtocolOp, ProtocolOpCode};
 
 use std::ffi::CStr;
 use std::os::raw::{c_int, c_void};
@@ -53,6 +54,7 @@ static mut G_LDAP_RESPONSES_OPERATION_KW_ID: c_int = 0;
 static mut G_LDAP_RESPONSES_OPERATION_BUFFER_ID: c_int = 0;
 static mut G_LDAP_RESPONSES_COUNT_KW_ID: c_int = 0;
 static mut G_LDAP_RESPONSES_COUNT_BUFFER_ID: c_int = 0;
+static mut G_LDAP_REQUEST_DN_BUFFER_ID: c_int = 0;
 
 unsafe extern "C" fn ldap_parse_protocol_req_op(
     ustr: *const std::os::raw::c_char,
@@ -263,6 +265,59 @@ unsafe extern "C" fn ldap_detect_responses_count_free(_de: *mut c_void, ctx: *mu
     rs_detect_u32_free(ctx);
 }
 
+unsafe extern "C" fn ldap_detect_request_dn_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_DN_BUFFER_ID) < 0 {
+        return -1;
+    }
+    return 0;
+}
+
+unsafe extern "C" fn ldap_detect_request_dn_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,
+) -> *mut c_void {
+    return DetectHelperGetData(
+        de,
+        transforms,
+        flow,
+        flow_flags,
+        tx,
+        list_id,
+        ldap_tx_get_request_dn,
+    );
+}
+
+unsafe extern "C" fn ldap_tx_get_request_dn(
+    tx: *const c_void, _flags: u8, 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::BindRequest(req) => req.name.0.as_str(),
+            ProtocolOp::AddRequest(req) => req.entry.0.as_str(),
+            ProtocolOp::SearchRequest(req) => req.base_object.0.as_str(),
+            ProtocolOp::ModifyRequest(req) => req.object.0.as_str(),
+            ProtocolOp::DelRequest(req) => req.0.as_str(),
+            ProtocolOp::ModDnRequest(req) => req.entry.0.as_str(),
+            ProtocolOp::CompareRequest(req) => req.entry.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 {
@@ -314,4 +369,22 @@ pub unsafe extern "C" fn SCDetectLdapRegister() {
         true,  //to client
         false, //to server
     );
+    let kw = SCSigTableElmt {
+        name: b"ldap.request.dn\0".as_ptr() as *const libc::c_char,
+        desc: b"match request LDAPDN\0".as_ptr() as *const libc::c_char,
+        url: b"/rules/ldap-keywords.html#ldap.request.dn\0".as_ptr() as *const libc::c_char,
+        Setup: ldap_detect_request_dn_setup,
+        flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER,
+        AppLayerTxMatch: None,
+        Free: None,
+    };
+    let _g_ldap_request_dn_kw_id = DetectHelperKeywordRegister(&kw);
+    G_LDAP_REQUEST_DN_BUFFER_ID = DetectHelperBufferMpmRegister(
+        b"ldap.request.dn\0".as_ptr() as *const libc::c_char,
+        b"LDAP REQUEST DISTINGUISHED_NAME\0".as_ptr() as *const libc::c_char,
+        ALPROTO_LDAP,
+        false, //to client
+        true,  //to server
+        ldap_detect_request_dn_get_data,
+    );
 }