detect/dcerpc: support generic integer for opnum keyword

Ticket: 8179
pull/15240/head
Philippe Antoine 6 months ago committed by Victor Julien
parent 67379b009a
commit 5f9e436c3f

@ -43,17 +43,21 @@ interface in a DCERPC header.
The format of the keyword::
dcerpc.opnum:<u16>;
dcerpc.opnum:[>,<,!,=]<u16>;
dcerpc.opnum:<u16>,<u16>,<u16>....;
dcerpc.opnum:<u16>-<u16>;
Examples::
dcerpc.opnum:15;
dcerpc.opnum:>10;
dcerpc.opnum:12,24,62,61;
dcerpc.opnum:12,18-24,5;
dcerpc.opnum:12-14,12,121,62-78;
.. note:: earlier versions of the documentation incorrectly stated that greater than, less than, etc. notation was supported. This may be added later, see ticket `#8179 <https://redmine.openinfosecfoundation.org/issues/8179>`_).
.. note:: earlier versions of the documentation incorrectly stated that greater than, less than, etc. notation was supported. This was added in suricata 9, see ticket `#8179 <https://redmine.openinfosecfoundation.org/issues/8179>`_).
dcerpc.opnum can since suricata 9 use an :ref:`unsigned 16-bits integer <rules-integer-keywords>`.
dcerpc.stub_data
----------------

@ -64,10 +64,16 @@ impl DCEOpnumRange {
}
#[derive(Debug)]
pub struct DCEOpnumData {
pub(crate) struct DCEOpnumDataRanges {
pub data: Vec<DCEOpnumRange>,
}
#[derive(Debug)]
pub(crate) enum DCEOpnumData {
Ranges(DCEOpnumDataRanges),
Num(DetectUintData<u16>),
}
fn match_backuuid(
tx: &DCERPCTransaction, state: &mut DCERPCState, if_data: &mut DCEIfaceData,
) -> u8 {
@ -174,7 +180,7 @@ fn convert_str_to_u32(arg: &str) -> Result<u32, ()> {
}
}
fn parse_opnum_data(arg: &str) -> Result<DCEOpnumData, ()> {
fn parse_opnum_data_ranges(arg: &str) -> Result<DCEOpnumData, ()> {
let split_args: Vec<&str> = arg.split(',').collect();
let mut dce_opnum_data: Vec<DCEOpnumRange> = Vec::new();
for range in split_args.iter() {
@ -207,9 +213,19 @@ fn parse_opnum_data(arg: &str) -> Result<DCEOpnumData, ()> {
dce_opnum_data.push(opnum_range);
}
Ok(DCEOpnumData {
Ok(DCEOpnumData::Ranges(DCEOpnumDataRanges {
data: dce_opnum_data,
})
}))
}
fn parse_opnum_data(arg: &str) -> Result<DCEOpnumData, ()> {
if let Ok(r) = parse_opnum_data_ranges(arg) {
return Ok(r);
}
if let Ok((_, du16)) = detect_parse_uint::<u16>(arg) {
return Ok(DCEOpnumData::Num(du16));
}
return Err(());
}
#[no_mangle]
@ -262,13 +278,22 @@ unsafe extern "C" fn dcerpc_tx_match_dce_opnum(tx: *mut c_void, ctx: *const SigM
return 0;
}
let opnum = tx.get_req_opnum();
for range in opnum_data.data.iter() {
if range.range2 == DETECT_DCE_OPNUM_RANGE_UNINITIALIZED {
if range.range1 == opnum as u32 {
match opnum_data {
DCEOpnumData::Num(ref num_data) => {
if detect_match_uint(num_data, opnum) {
return 1;
}
} else if range.range1 <= opnum as u32 && range.range2 >= opnum as u32 {
return 1;
}
DCEOpnumData::Ranges(ref ranges_data) => {
for range in ranges_data.data.iter() {
if range.range2 == DETECT_DCE_OPNUM_RANGE_UNINITIALIZED {
if range.range1 == opnum as u32 {
return 1;
}
} else if range.range1 <= opnum as u32 && range.range2 >= opnum as u32 {
return 1;
}
}
}
}
@ -504,6 +529,9 @@ mod test {
fn test_parse_opnum_data() {
let arg = "12";
let opnum_data = parse_opnum_data(arg).unwrap();
let DCEOpnumData::Ranges(opnum_data) = opnum_data else {
panic!("Result should have been ranges.");
};
assert_eq!(1, opnum_data.data.len());
assert_eq!(12, opnum_data.data[0].range1);
assert_eq!(
@ -513,12 +541,18 @@ mod test {
let arg = "12,24";
let opnum_data = parse_opnum_data(arg).unwrap();
let DCEOpnumData::Ranges(opnum_data) = opnum_data else {
panic!("Result should have been ranges.");
};
assert_eq!(2, opnum_data.data.len());
assert_eq!(12, opnum_data.data[0].range1);
assert_eq!(24, opnum_data.data[1].range1);
let arg = "12,12-24";
let opnum_data = parse_opnum_data(arg).unwrap();
let DCEOpnumData::Ranges(opnum_data) = opnum_data else {
panic!("Result should have been ranges.");
};
assert_eq!(2, opnum_data.data.len());
assert_eq!(12, opnum_data.data[0].range1);
assert_eq!(12, opnum_data.data[1].range1);
@ -526,6 +560,9 @@ mod test {
let arg = "12-14,12,121,62-78";
let opnum_data = parse_opnum_data(arg).unwrap();
let DCEOpnumData::Ranges(opnum_data) = opnum_data else {
panic!("Result should have been ranges.");
};
assert_eq!(4, opnum_data.data.len());
assert_eq!(12, opnum_data.data[0].range1);
assert_eq!(14, opnum_data.data[0].range2);
@ -534,6 +571,9 @@ mod test {
let arg = "12,26,62,61,6513-6666";
let opnum_data = parse_opnum_data(arg).unwrap();
let DCEOpnumData::Ranges(opnum_data) = opnum_data else {
panic!("Result should have been ranges.");
};
assert_eq!(5, opnum_data.data.len());
assert_eq!(61, opnum_data.data[3].range1);
assert_eq!(6513, opnum_data.data[4].range1);

@ -101,13 +101,22 @@ pub(crate) unsafe extern "C" fn smb_tx_match_dce_opnum(
SCLogDebug!("smb_tx_match_dce_opnum: start");
if let Some(SMBTransactionTypeData::DCERPC(ref x)) = tx.type_data {
if x.req_cmd == DCERPC_TYPE_REQUEST {
for range in dce_data.data.iter() {
if range.range2 == DETECT_DCE_OPNUM_RANGE_UNINITIALIZED {
if range.range1 == x.opnum as u32 {
match dce_data {
DCEOpnumData::Num(ref num_data) => {
if detect_match_uint(num_data, x.opnum) {
return 1;
}
} else if range.range1 <= x.opnum as u32 && range.range2 >= x.opnum as u32 {
return 1;
}
DCEOpnumData::Ranges(ref ranges_data) => {
for range in ranges_data.data.iter() {
if range.range2 == DETECT_DCE_OPNUM_RANGE_UNINITIALIZED {
if range.range1 == x.opnum as u32 {
return 1;
}
} else if range.range1 <= x.opnum as u32 && range.range2 >= x.opnum as u32 {
return 1;
}
}
}
}
}

Loading…
Cancel
Save