detect: add dcerpc.ptype keyword

Add keyword to match on the DCERPC PDU type. This information is found
in the DCERPC Header as a u8 so, the DetectUint* API is leveraged.

Feature 8733
pull/15925/head
Shivani Bhardwaj 3 months ago
parent 71c8f2349d
commit 81a80a7064

@ -59,6 +59,53 @@ Examples::
dcerpc.opnum can since suricata 9 use an :ref:`unsigned 16-bits integer <rules-integer-keywords>`.
dcerpc.ptype
------------
Match on the PDU type of a DCERPC header. On a to_server match the request PDU
type is used, on a to_client match the response PDU type is used.
The format of the keyword::
dcerpc.ptype:<u8>;
dcerpc.ptype:[>,<,!,=]<u8>;
The PDU type values are:
===== =====================
Value PDU type
===== =====================
0 request
1 ping
2 response
3 fault
4 working
5 nocall
6 reject
7 ack
8 cl_cancel
9 fack
10 cancel_ack
11 bind
12 bind_ack
13 bind_nak
14 alter_context
15 alter_context_resp
16 auth3
17 shutdown
18 co_cancel
19 orphaned
20 rts
===== =====================
Examples::
dcerpc.ptype:11;
dcerpc.ptype:!0;
dcerpc.ptype:>10;
dcerpc.ptype uses an :ref:`unsigned 8-bits integer <rules-integer-keywords>`.
dcerpc.stub_data
----------------

@ -450,7 +450,12 @@
}
},
"request": {
"type": "string"
"type": "string",
"suricata": {
"keywords": [
"dcerpc.ptype"
]
}
},
"res": {
"type": "object",
@ -465,7 +470,12 @@
}
},
"response": {
"type": "string"
"type": "string",
"suricata": {
"keywords": [
"dcerpc.ptype"
]
}
},
"rpc_version": {
"type": "string"

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Open Information Security Foundation
/* Copyright (C) 2020-2026 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -22,7 +22,9 @@ use super::dcerpc::{
use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER};
use crate::detect::uint::{detect_match_uint, detect_parse_uint, DetectUintData};
use crate::detect::{helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer};
use crate::smb::detect::{smb_tx_get_stub_data, smb_tx_match_dce_iface, smb_tx_match_dce_opnum};
use crate::smb::detect::{
smb_tx_get_stub_data, smb_tx_match_dce_iface, smb_tx_match_dce_opnum, smb_tx_match_dce_ptype,
};
use crate::smb::smb::ALPROTO_SMB;
use std::ffi::CStr;
use std::os::raw::{c_char, c_int, c_void};
@ -439,9 +441,85 @@ unsafe extern "C" fn dcerpc_tx_get_stub_data(
return buffer;
}
fn parse_dcerpc_ptype(arg: &str) -> Option<DetectUintData<u8>> {
if let Ok((_, ctx)) = detect_parse_uint::<u8>(arg) {
return Some(ctx);
}
None
}
unsafe extern "C" fn dcerpc_ptype_parse(carg: *const c_char) -> *mut c_void {
if let Ok(arg) = CStr::from_ptr(carg).to_str() {
if let Some(detect) = parse_dcerpc_ptype(arg) {
return Box::into_raw(Box::new(detect)) as *mut _;
}
}
return std::ptr::null_mut();
}
unsafe extern "C" fn dcerpc_ptype_setup(
de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char,
) -> c_int {
if SCDetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0 {
return -1;
}
let ctx = dcerpc_ptype_parse(raw);
if ctx.is_null() {
return -1;
}
if SCSigMatchAppendSMToList(
de,
s,
G_DCERPC_PTYPE_KW_ID,
ctx as *mut SigMatchCtx,
G_DCERPC_GENERIC_BUFFER_ID,
)
.is_null()
{
dcerpc_ptype_free(std::ptr::null_mut(), ctx);
return -1;
}
return 0;
}
unsafe fn dcerpc_tx_match_dce_ptype(tx: *mut c_void, ctx: *const SigMatchCtx, flags: u8) -> c_int {
let tx = cast_pointer!(tx, DCERPCTransaction);
let du8 = cast_pointer!(ctx, DetectUintData<u8>);
if flags & STREAM_TOSERVER != 0 {
if tx.req_seen && detect_match_uint(du8, tx.req_cmd) {
return 1;
}
} else if tx.resp_seen && detect_match_uint(du8, tx.resp_cmd) {
return 1;
}
return 0;
}
unsafe extern "C" fn dcerpc_ptype_match(
_de: *mut DetectEngineThreadCtx, f: *mut crate::flow::Flow, flags: u8, _state: *mut c_void,
tx: *mut c_void, _sig: *const Signature, ctx: *const SigMatchCtx,
) -> c_int {
if SCFlowGetAppProtocol(f) == ALPROTO_DCERPC {
return dcerpc_tx_match_dce_ptype(tx, ctx, flags);
}
if smb_tx_match_dce_ptype(tx, ctx, flags) != 1 {
return 0;
}
return 1;
}
unsafe extern "C" fn dcerpc_ptype_free(_de: *mut DetectEngineCtx, ptr: *mut c_void) {
if !ptr.is_null() {
std::mem::drop(Box::from_raw(ptr as *mut DetectUintData<u8>));
}
}
static mut G_DCERPC_OPNUM_KW_ID: u16 = 0;
static mut G_DCERPC_GENERIC_BUFFER_ID: c_int = 0;
static mut G_DCERPC_IFACE_KW_ID: u16 = 0;
static mut G_DCERPC_PTYPE_KW_ID: u16 = 0;
static mut G_DCERPC_STUB_BUFFER_ID: c_int = 0;
#[no_mangle]
@ -490,6 +568,17 @@ pub unsafe extern "C" fn SCDetectDcerpcRegister() {
b"dce_iface\0".as_ptr() as *const libc::c_char,
);
let kw = SCSigTableAppLiteElmt {
name: b"dcerpc.ptype\0".as_ptr() as *const libc::c_char,
desc: b"match on the PDU type in a DCERPC header\0".as_ptr() as *const libc::c_char,
url: b"/rules/dcerpc-keywords.html#dcerpc-ptype\0".as_ptr() as *const libc::c_char,
AppLayerTxMatch: Some(dcerpc_ptype_match),
Setup: Some(dcerpc_ptype_setup),
Free: Some(dcerpc_ptype_free),
flags: 0,
};
G_DCERPC_PTYPE_KW_ID = SCDetectHelperKeywordRegister(&kw);
let kw_stub = SigTableElmtStickyBuffer {
name: String::from("dcerpc.stub_data"),
desc: String::from("match on the stub data in a DCERPC packet"),

@ -19,7 +19,7 @@ use super::smb::ALPROTO_SMB;
use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER};
use crate::dcerpc::dcerpc::DCERPC_TYPE_REQUEST;
use crate::dcerpc::detect::{DCEIfaceData, DCEOpnumData, DETECT_DCE_OPNUM_RANGE_UNINITIALIZED};
use crate::detect::uint::detect_match_uint;
use crate::detect::uint::{detect_match_uint, DetectUintData};
use crate::detect::{helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer};
use crate::direction::Direction;
use crate::smb::smb::*;
@ -125,6 +125,25 @@ pub(crate) unsafe extern "C" fn smb_tx_match_dce_opnum(
return 0;
}
pub(crate) unsafe extern "C" fn smb_tx_match_dce_ptype(
tx: *mut c_void, ctx: *const SigMatchCtx, flags: u8,
) -> u8 {
let tx = cast_pointer!(tx, SMBTransaction);
let du8 = cast_pointer!(ctx, DetectUintData<u8>);
if let Some(SMBTransactionTypeData::DCERPC(ref x)) = tx.type_data {
if flags & STREAM_TOSERVER != 0 {
if x.req_set && detect_match_uint(du8, x.req_cmd) {
return 1;
}
} else if x.res_set && detect_match_uint(du8, x.res_cmd) {
return 1;
}
}
return 0;
}
/* mimic logic that is/was in the C code:
* - match on REQUEST (so not on BIND/BINDACK (probably for mixing with
* dce_opnum and dce_stub_data)

Loading…
Cancel
Save