Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next/742/20250221/v1 #12653

Merged
merged 11 commits into from
Feb 21, 2025
112 changes: 100 additions & 12 deletions doc/userguide/rules/ldap-keywords.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Syntax::

ldap.request.operation uses :ref:`unsigned 8-bit integer <rules-integer-keywords>`.

This keyword maps to the eve field ``ldap.request.operation``
This keyword maps to the EVE field ``ldap.request.operation``

Examples
^^^^^^^^
Expand All @@ -61,11 +61,11 @@ Example of a signatures that would alert if the packet has an LDAP bind request

.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP bind request"; :example-rule-emphasis:`ldap.request.operation:0;` sid:1;)
alert ldap any any -> any any (msg:"Test LDAP bind request"; :example-rule-emphasis:`ldap.request.operation:0;` sid:1;)

.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP bind request"; :example-rule-emphasis:`ldap.request.operation:bind_request;` sid:1;)
alert ldap any any -> any any (msg:"Test LDAP bind request"; :example-rule-emphasis:`ldap.request.operation:bind_request;` sid:1;)

ldap.responses.operation
------------------------
Expand All @@ -79,7 +79,7 @@ Syntax::

ldap.responses.operation uses :ref:`unsigned 8-bit integer <rules-integer-keywords>`.

This keyword maps to the eve field ``ldap.responses[].operation``
This keyword maps to the EVE field ``ldap.responses[].operation``

An LDAP request operation can receive multiple responses. By default, the ldap.responses.operation
keyword matches all indices, but it is possible to specify a particular index for matching
Expand All @@ -104,31 +104,31 @@ Example of a signatures that would alert if the packet has an LDAP bind response

.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP bind response"; :example-rule-emphasis:`ldap.responses.operation:1;` sid:1;)
alert ldap any any -> any any (msg:"Test LDAP bind response"; :example-rule-emphasis:`ldap.responses.operation:1;` sid:1;)

.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP bind response"; :example-rule-emphasis:`ldap.responses.operation:bind_response;` sid:1;)
alert ldap any any -> any any (msg:"Test LDAP bind response"; :example-rule-emphasis:`ldap.responses.operation:bind_response;` sid:1;)

Example of a signature that would alert if the packet has an LDAP search_result_done response operation at index 1:

.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP search response"; :example-rule-emphasis:`ldap.responses.operation:search_result_done,1;` sid:1;)
alert ldap any any -> any any (msg:"Test LDAP search response"; :example-rule-emphasis:`ldap.responses.operation:search_result_done,1;` sid:1;)

Example of a signature that would alert if all the responses are of type search_result_entry:

.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP search response"; :example-rule-emphasis:`ldap.responses.operation:search_result_entry,all;` sid:1;)
alert ldap any any -> any any (msg:"Test LDAP search response"; :example-rule-emphasis:`ldap.responses.operation:search_result_entry,all;` sid:1;)

The keyword ldap.responses.operation supports back to front indexing with negative numbers,
this means that -1 will represent the last index, -2 the second to last index, and so on.
This is an example of a signature that would alert if a search_result_entry response is found at the last index:

.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP search response"; :example-rule-emphasis:`ldap.responses.operation:search_result_entry,-1;` sid:1;)
alert ldap any any -> any any (msg:"Test LDAP search response"; :example-rule-emphasis:`ldap.responses.operation:search_result_entry,-1;` sid:1;)

ldap.responses.count
--------------------
Expand All @@ -147,7 +147,7 @@ It can be matched exactly, or compared using the ``op`` setting::

ldap.responses.count uses :ref:`unsigned 32-bit integer <rules-integer-keywords>`.

This keyword maps to the eve field ``len(ldap.responses[])``
This keyword maps to the EVE field ``len(ldap.responses[])``

Examples
^^^^^^^^
Expand All @@ -156,10 +156,98 @@ Example of a signature that would alert if a packet has 0 LDAP responses:

.. container:: example-rule

alert ip any any -> any any (msg:"Packet has 0 LDAP responses"; :example-rule-emphasis:`ldap.responses.count:0;` sid:1;)
alert ldap any any -> any any (msg:"Packet has 0 LDAP responses"; :example-rule-emphasis:`ldap.responses.count:0;` sid:1;)

Example of a signature that would alert if a packet has more than 2 LDAP responses:

.. container:: example-rule

alert ip any any -> any any (msg:"Packet has more than 2 LDAP responses"; :example-rule-emphasis:`ldap.responses.count:>2;` sid:1;)
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;)

ldap.responses.dn
-----------------

Matches on LDAP distinguished names from response operations.

Comparison is case-sensitive.

Syntax::

ldap.responses.dn; content:dc=example,dc=com;

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

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

This keyword maps to the EVE fields:
``ldap.responses[].search_result_entry.base_object``
``ldap.responses[].bind_response.matched_dn``
``ldap.responses[].search_result_done.matched_dn``
``ldap.responses[].modify_response.matched_dn``
``ldap.responses[].add_response.matched_dn``
``ldap.responses[].del_response.matched_dn``
``ldap.responses[].mod_dn_response.matched_dn``
``ldap.responses[].compare_response.matched_dn``
``ldap.responses[].extended_response.matched_dn``

Example
^^^^^^^

Example of a signature that would alert if a packet has the LDAP distinguished name ``dc=example,dc=com``:

.. container:: example-rule

alert ldap any any -> any any (msg:"Test LDAPDN"; :example-rule-emphasis:`ldap.responses.dn; content:"dc=example,dc=com";` sid:1;)

It is possible to use the keyword ``ldap.responses.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 result entry operation at index 1 on the responses array,
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.responses.operation:search_result_entry,1; ldap.responses.dn; content:"dc=example,dc=com";` sid:1;)
6 changes: 4 additions & 2 deletions rust/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ vendor:
update-bindings:
if HAVE_BINDGEN
$(BINDGEN) \
-o sys/src/sys.rs \
-o sys/src/sys.rs.tmp \
--rust-target 1.68 \
--no-layout-tests \
--disable-header-comment \
Expand All @@ -120,7 +120,9 @@ if HAVE_BINDGEN
$(abs_top_srcdir)/src/bindgen.h \
-- \
-DHAVE_CONFIG_H -I../src -I../rust/gen $(CPPFLAGS)
sed -i '1i\// This file is automatically generated. Do not edit.\n' sys/src/sys.rs
printf "// This file is automatically generated. Do not edit.\n\n" > sys/src/sys.rs
cat sys/src/sys.rs.tmp >> sys/src/sys.rs
rm -f sys/src/sys.rs.tmp
else
@echo "error: bindgen not installed, can't update bindings"
exit 1
Expand Down
2 changes: 1 addition & 1 deletion rust/src/applayertemplate/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ unsafe extern "C" fn template_buffer_get(
}

#[no_mangle]
pub unsafe extern "C" fn ScDetectTemplateRegister() {
pub unsafe extern "C" fn SCDetectTemplateRegister() {
/* TEMPLATE_START_REMOVE */
if conf_get_node("app-layer.protocols.template").is_none() {
return;
Expand Down
34 changes: 20 additions & 14 deletions rust/src/dcerpc/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ use crate::dcerpc::dcerpc::*;
use crate::dcerpc::dcerpc_udp::*;
use crate::jsonbuilder::{JsonBuilder, JsonError};

fn log_bind_interfaces(jsb: &mut JsonBuilder, state: &DCERPCState) -> Result<(), JsonError> {
if let Some(bind) = &state.bind {
jsb.open_array("interfaces")?;
for uuid in &bind.uuid_list {
jsb.start_object()?;
let ifstr = Uuid::from_slice(uuid.uuid.as_slice());
let ifstr = ifstr.map(|uuid| uuid.to_hyphenated().to_string()).unwrap();
jsb.set_string("uuid", &ifstr)?;
let vstr = format!("{}.{}", uuid.version, uuid.versionminor);
jsb.set_string("version", &vstr)?;
jsb.set_uint("ack_result", uuid.result as u64)?;
jsb.close()?;
}
jsb.close()?;
}
return Ok(());
}

fn log_dcerpc_header_tcp(
jsb: &mut JsonBuilder, state: &DCERPCState, tx: &DCERPCTransaction,
) -> Result<(), JsonError> {
Expand All @@ -32,21 +50,9 @@ fn log_dcerpc_header_tcp(
jsb.set_uint("frag_cnt", tx.frag_cnt_ts as u64)?;
jsb.set_uint("stub_data_size", tx.stub_data_buffer_ts.len() as u64)?;
jsb.close()?;
log_bind_interfaces(jsb, state)?;
}
DCERPC_TYPE_BIND => if let Some(bind) = &state.bind {
jsb.open_array("interfaces")?;
for uuid in &bind.uuid_list {
jsb.start_object()?;
let ifstr = Uuid::from_slice(uuid.uuid.as_slice());
let ifstr = ifstr.map(|uuid| uuid.to_hyphenated().to_string()).unwrap();
jsb.set_string("uuid", &ifstr)?;
let vstr = format!("{}.{}", uuid.version, uuid.versionminor);
jsb.set_string("version", &vstr)?;
jsb.set_uint("ack_result", uuid.result as u64)?;
jsb.close()?;
}
jsb.close()?;
},
DCERPC_TYPE_BIND => log_bind_interfaces(jsb, state)?,
_ => {}
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion rust/src/enip/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1330,7 +1330,7 @@ unsafe extern "C" fn service_name_get_data(
);
}
#[no_mangle]
pub unsafe extern "C" fn ScDetectEnipRegister() {
pub unsafe extern "C" fn SCDetectEnipRegister() {
let kw = SCSigTableElmt {
name: b"cip_service\0".as_ptr() as *const libc::c_char,
desc: b"match on CIP Service, and optionnally class and attribute\0".as_ptr()
Expand Down
6 changes: 3 additions & 3 deletions rust/src/ja4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl JA4 {
// If the first ALPN value is only a single character, then that character is treated as both the first and last character.
if alpn.len() == 2 {
// GREASE values are 2 bytes, so this could be one -- check
let v: u16 = (alpn[0] as u16) << 8 | alpn[alpn.len() - 1] as u16;
let v: u16 = ((alpn[0] as u16) << 8) | alpn[alpn.len() - 1] as u16;
if JA4::is_grease(v) {
return;
}
Expand Down Expand Up @@ -288,12 +288,12 @@ mod tests {
fn test_is_grease() {
let mut alpn = "foobar".as_bytes();
let mut len = alpn.len();
let v: u16 = (alpn[0] as u16) << 8 | alpn[len - 1] as u16;
let v: u16 = ((alpn[0] as u16) << 8) | alpn[len - 1] as u16;
assert!(!JA4::is_grease(v));

alpn = &[0x0a, 0x0a];
len = alpn.len();
let v: u16 = (alpn[0] as u16) << 8 | alpn[len - 1] as u16;
let v: u16 = ((alpn[0] as u16) << 8) | alpn[len - 1] as u16;
assert!(JA4::is_grease(v));
}

Expand Down
2 changes: 1 addition & 1 deletion rust/src/jsonbuilder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ impl JsonBuilder {
offset += 1;
buf[offset] = b'0';
offset += 1;
buf[offset] = HEX[(x >> 4 & 0xf) as usize];
buf[offset] = HEX[((x >> 4) & 0xf) as usize];
offset += 1;
buf[offset] = HEX[(x & 0xf) as usize];
offset += 1;
Expand Down
Loading
Loading