Skip to content

Commit

Permalink
detect: add ldap.responses.error_message
Browse files Browse the repository at this point in the history
ldap.responses.error_message matches on LDAPResult error message
This keyword maps the following eve fields:
ldap.responses[].bind_response.message
ldap.responses[].search_result_done.message
ldap.responses[].modify_response.message
ldap.responses[].add_response.message
ldap.responses[].del_response.message
ldap.responses[].mod_dn_response.message
ldap.responses[].compare_response.message
ldap.responses[].extended_response.message
It is a sticky buffer
Supports prefiltering

Ticket: #7532
  • Loading branch information
AkakiAlice committed Feb 14, 2025
1 parent 530e9b5 commit c1ae8e2
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 3 deletions.
36 changes: 35 additions & 1 deletion doc/userguide/rules/ldap-keywords.rst
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,38 @@ This is an example of a signature that would alert if a ``success`` result code

.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP success at last index"; :example-rule-emphasis:`ldap.responses.result_code:success,-1;` sid:1;)
alert tcp any any -> any any (msg:"Test LDAP success at last index"; :example-rule-emphasis:`ldap.responses.result_code:success,-1;` sid:1;)

ldap.responses.error_message
----------------------------

Matches on LDAP error messages from response operations.

Comparison is case-sensitive.

Syntax::

ldap.responses.error_message; content:"The Directory Server is shutting down";

``ldap.responses.error_message`` is a 'sticky buffer' and can be used as a ``fast_pattern``.

``ldap.responses.error_message`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.

This keyword maps to the eve fields:
``ldap.responses[].bind_response.message``
``ldap.responses[].search_result_done.message``
``ldap.responses[].modify_response.message``
``ldap.responses[].add_response.message``
``ldap.responses[].del_response.message``
``ldap.responses[].mod_dn_response.message``
``ldap.responses[].compare_response.message``
``ldap.responses[].extended_response.message``

Example
^^^^^^^

Example of a signature that would alert if a packet has the LDAP error message ``Size limit exceeded``:

.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP error message"; ldap.responses.error_message; content:"Size limit exceeded"; sid:1;)
83 changes: 81 additions & 2 deletions rust/src/ldap/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ use crate::detect::uint::{
rs_detect_u8_free, rs_detect_u8_match, DetectUintData,
};
use crate::detect::{
DetectHelperBufferRegister, DetectHelperKeywordRegister, DetectSignatureSetAppProto,
SCSigTableElmt, SigMatchAppendSMToList,
DetectBufferSetActiveList, DetectHelperBufferRegister, DetectHelperGetMultiData,
DetectHelperKeywordRegister, DetectHelperMultiBufferMpmRegister, DetectSignatureSetAppProto,
SCSigTableElmt, SigMatchAppendSMToList, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT,
};
use crate::ldap::types::{LdapMessage, LdapResultCode, ProtocolOp, ProtocolOpCode};

Expand Down Expand Up @@ -64,6 +65,7 @@ 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_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_ERROR_MSG_BUFFER_ID: c_int = 0;

unsafe extern "C" fn ldap_parse_protocol_req_op(
ustr: *const std::os::raw::c_char,
Expand Down Expand Up @@ -407,6 +409,64 @@ unsafe extern "C" fn ldap_detect_responses_result_code_free(_de: *mut c_void, ct
std::mem::drop(Box::from_raw(ctx));
}

unsafe extern "C" fn ldap_detect_responses_error_msg_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_RESPONSES_ERROR_MSG_BUFFER_ID) < 0 {
return -1;
}
return 0;
}

unsafe extern "C" fn ldap_detect_responses_error_msg_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_responses_error_msg,
);
}

unsafe extern "C" fn ldap_tx_get_responses_error_msg(
tx: *const c_void, _flags: u8, local_id: u32, buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, LdapTransaction);

if local_id as usize >= tx.responses.len() {
return false;
}
*buffer = std::ptr::null();
*buffer_len = 0;

let response = &tx.responses[local_id as usize];
// We expect every response in one tx to be the same protocol_op
let str_buffer: &str = match &response.protocol_op {
ProtocolOp::BindResponse(req) => req.result.diagnostic_message.0.as_str(),
ProtocolOp::SearchResultDone(req) => req.diagnostic_message.0.as_str(),
ProtocolOp::ModifyResponse(req) => req.result.diagnostic_message.0.as_str(),
ProtocolOp::AddResponse(req) => req.diagnostic_message.0.as_str(),
ProtocolOp::DelResponse(req) => req.diagnostic_message.0.as_str(),
ProtocolOp::ModDnResponse(req) => req.diagnostic_message.0.as_str(),
ProtocolOp::CompareResponse(req) => req.diagnostic_message.0.as_str(),
ProtocolOp::ExtendedResponse(req) => req.result.diagnostic_message.0.as_str(),
_ => return false,
};

*buffer = str_buffer.as_ptr();
*buffer_len = str_buffer.len() as u32;
return true;
}

#[no_mangle]
pub unsafe extern "C" fn ScDetectLdapRegister() {
let kw = SCSigTableElmt {
Expand Down Expand Up @@ -475,4 +535,23 @@ pub unsafe extern "C" fn ScDetectLdapRegister() {
true, //to client
false, //to server
);
let kw = SCSigTableElmt {
name: b"ldap.responses.error_message\0".as_ptr() as *const libc::c_char,
desc: b"match LDAPResult error message for responses\0".as_ptr() as *const libc::c_char,
url: b"/rules/ldap-keywords.html#ldap.responses.error_message\0".as_ptr()
as *const libc::c_char,
Setup: ldap_detect_responses_error_msg_setup,
flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER,
AppLayerTxMatch: None,
Free: None,
};
let _g_ldap_responses_dn_kw_id = DetectHelperKeywordRegister(&kw);
G_LDAP_RESPONSES_ERROR_MSG_BUFFER_ID = DetectHelperMultiBufferMpmRegister(
b"ldap.responses.error_message\0".as_ptr() as *const libc::c_char,
b"LDAP RESPONSES DISTINGUISHED_NAME\0".as_ptr() as *const libc::c_char,
ALPROTO_LDAP,
true, //to client
false, //to server
ldap_detect_responses_error_msg_get_data,
);
}

0 comments on commit c1ae8e2

Please sign in to comment.