Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions rust/src/dcerpc/dcerpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ impl DCERPCState {
Ok((leftover_bytes, back)) => {
for (uuid_internal_id, r) in back.ctxitems.iter().enumerate() {
for uuid in self.interface_uuids.iter_mut().rev() {
if uuid.internal_id == uuid_internal_id as u16 && uuid.call_id == call_id{
if uuid.internal_id == uuid_internal_id as u16 && uuid.call_id == call_id {
uuid.result = r.ack_result;
uuid.acked = true;
if uuid.result == 0 {
Expand Down Expand Up @@ -940,8 +940,10 @@ impl DCERPCState {
}
}
DCERPC_TYPE_BINDACK | DCERPC_TYPE_ALTER_CONTEXT_RESP => {
let retval =
self.process_bindack_pdu(&cur_i[parsed as usize..fraglen as usize], hdr.call_id);
let retval = self.process_bindack_pdu(
&cur_i[parsed as usize..fraglen as usize],
hdr.call_id,
);
if retval == -1 {
return AppLayerResult::err();
}
Expand Down
106 changes: 66 additions & 40 deletions rust/src/dcerpc/dcerpc_udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@
* 02110-1301, USA.
*/

use crate::core;
use crate::applayer::{self, *};
use crate::core;
use crate::dcerpc::dcerpc::{
DCERPCTransaction, DCERPC_MAX_TX, DCERPC_TYPE_REQUEST, DCERPC_TYPE_RESPONSE, PFCL1_FRAG, PFCL1_LASTFRAG,
get_alstate_progress, ALPROTO_DCERPC, PARSER_NAME, cfg_max_stub_size,
cfg_max_stub_size, get_alstate_progress, DCERPCTransaction, ALPROTO_DCERPC, DCERPC_MAX_TX,
DCERPC_TYPE_REQUEST, DCERPC_TYPE_RESPONSE, PARSER_NAME, PFCL1_FRAG, PFCL1_LASTFRAG,
};
use crate::dcerpc::parser;
use crate::direction::{Direction, DIR_BOTH};
use crate::flow::Flow;
use nom8::Err;
use std;
use std::collections::VecDeque;
use std::ffi::CString;
use suricata_sys::sys::{
AppLayerParserState, AppProto, SCAppLayerParserConfParserEnabled,
SCAppLayerProtoDetectConfProtoDetectionEnabled, SCAppLayerProtoDetectPMRegisterPatternCSwPP,
};
use std;
use std::ffi::CString;
use std::collections::VecDeque;
use crate::dcerpc::parser;

// Constant DCERPC UDP Header length
pub const DCERPC_UDP_HDR_LEN: i32 = 80;
Expand Down Expand Up @@ -82,7 +82,7 @@ impl DCERPCUDPState {
Default::default()
}

fn create_tx(&mut self, hdr: &DCERPCHdrUdp) -> DCERPCTransaction {
fn create_tx(&mut self, hdr: &DCERPCHdrUdp) -> DCERPCTransaction {
let mut tx = DCERPCTransaction::new();
tx.id = self.tx_id;
tx.endianness = hdr.drep[0] & 0x10;
Expand All @@ -107,22 +107,29 @@ impl DCERPCUDPState {
}

pub fn free_tx(&mut self, tx_id: u64) {
SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id+1);
SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id + 1);
let len = self.transactions.len();
let mut found = false;
let mut index = 0;
for i in 0..len {
let tx = &self.transactions[i];
if tx.id == tx_id { //+ 1 {
if tx.id == tx_id {
//+ 1 {
found = true;
index = i;
SCLogDebug!("tx {} progress {}/{}", tx.id, tx.req_done, tx.resp_done);
break;
}
}
if found {
SCLogDebug!("freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}",
tx_id, tx_id+1, index, self.transactions.len(), self.tx_id);
SCLogDebug!(
"freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}",
tx_id,
tx_id + 1,
index,
self.transactions.len(),
self.tx_id
);
self.tx_index_completed = 0;
self.transactions.remove(index);
}
Expand Down Expand Up @@ -165,7 +172,13 @@ impl DCERPCUDPState {
let mut otx = self.find_incomplete_tx(hdr);
if otx.is_none() {
let ntx = self.create_tx(hdr);
SCLogDebug!("new tx id {}, last tx_id {}, {} {}", ntx.id, self.tx_id, ntx.seqnum, ntx.activityuuid[0]);
SCLogDebug!(
"new tx id {}, last tx_id {}, {} {}",
ntx.id,
self.tx_id,
ntx.seqnum,
ntx.activityuuid[0]
);
self.transactions.push_back(ntx);
otx = self.transactions.back_mut();
}
Expand All @@ -182,7 +195,8 @@ impl DCERPCUDPState {
if input.len() + tx.stub_data_buffer_ts.len() < max_size {
tx.stub_data_buffer_ts.extend_from_slice(input);
} else if tx.stub_data_buffer_ts.len() < max_size {
tx.stub_data_buffer_ts.extend_from_slice(&input[..max_size - tx.stub_data_buffer_ts.len()]);
tx.stub_data_buffer_ts
.extend_from_slice(&input[..max_size - tx.stub_data_buffer_ts.len()]);
}
if done {
tx.req_done = true;
Expand All @@ -194,7 +208,8 @@ impl DCERPCUDPState {
if input.len() + tx.stub_data_buffer_tc.len() < max_size {
tx.stub_data_buffer_tc.extend_from_slice(input);
} else if tx.stub_data_buffer_tc.len() < max_size {
tx.stub_data_buffer_tc.extend_from_slice(&input[..max_size - tx.stub_data_buffer_tc.len()]);
tx.stub_data_buffer_tc
.extend_from_slice(&input[..max_size - tx.stub_data_buffer_tc.len()]);
}
if done {
tx.resp_done = true;
Expand Down Expand Up @@ -223,7 +238,11 @@ impl DCERPCUDPState {
return AppLayerResult::err();
}
if leftover_bytes.len() < header.fraglen as usize {
SCLogDebug!("Insufficient data: leftover_bytes {}, fraglen {}", leftover_bytes.len(), header.fraglen);
SCLogDebug!(
"Insufficient data: leftover_bytes {}, fraglen {}",
leftover_bytes.len(),
header.fraglen
);
return AppLayerResult::err();
}
if !self.handle_fragment_data(&header, &leftover_bytes[..header.fraglen as usize]) {
Expand All @@ -247,8 +266,7 @@ impl DCERPCUDPState {

unsafe extern "C" fn parse(
_flow: *mut Flow, state: *mut std::os::raw::c_void, _pstate: *mut AppLayerParserState,
stream_slice: StreamSlice,
_data: *mut std::os::raw::c_void,
stream_slice: StreamSlice, _data: *mut std::os::raw::c_void,
) -> AppLayerResult {
let state = cast_pointer!(state, DCERPCUDPState);
if !stream_slice.is_gap() {
Expand All @@ -261,24 +279,23 @@ extern "C" fn state_free(state: *mut std::os::raw::c_void) {
std::mem::drop(unsafe { Box::from_raw(state as *mut DCERPCUDPState) });
}

extern "C" fn state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void {
extern "C" fn state_new(
_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
) -> *mut std::os::raw::c_void {
let state = DCERPCUDPState::new();
let boxed = Box::new(state);
return Box::into_raw(boxed) as *mut _;
}

unsafe extern "C" fn state_transaction_free(
state: *mut std::os::raw::c_void, tx_id: u64,
) {
unsafe extern "C" fn state_transaction_free(state: *mut std::os::raw::c_void, tx_id: u64) {
let dce_state = cast_pointer!(state, DCERPCUDPState);
SCLogDebug!("freeing tx {}", tx_id);
dce_state.free_tx(tx_id);
}

unsafe extern "C" fn get_tx_data(
tx: *mut std::os::raw::c_void)
-> *mut suricata_sys::sys::AppLayerTxData
{
tx: *mut std::os::raw::c_void,
) -> *mut suricata_sys::sys::AppLayerTxData {
let tx = cast_pointer!(tx, DCERPCTransaction);
return &mut tx.tx_data.0;
}
Expand All @@ -290,11 +307,11 @@ unsafe extern "C" fn get_tx(
match dce_state.get_tx(tx_id) {
Some(tx) => {
return tx as *const _ as *mut _;
},
}
None => {
return std::ptr::null_mut();
}
}
}
}

unsafe extern "C" fn get_tx_cnt(vtx: *mut std::os::raw::c_void) -> u64 {
Expand All @@ -307,21 +324,21 @@ fn probe(input: &[u8]) -> (bool, bool) {
match parser::parse_dcerpc_udp_header(input) {
Ok((leftover_bytes, hdr)) => {
let is_request = hdr.pkt_type == 0x00;
let is_dcerpc = hdr.rpc_vers == 0x04 &&
hdr.fragnum == 0 &&
leftover_bytes.len() >= hdr.fraglen as usize &&
(hdr.flags2 & 0xfc == 0) &&
(hdr.drep[0] & 0xee == 0) &&
(hdr.drep[1] <= 3);
let is_dcerpc = hdr.rpc_vers == 0x04
&& hdr.fragnum == 0
&& leftover_bytes.len() >= hdr.fraglen as usize
&& (hdr.flags2 & 0xfc == 0)
&& (hdr.drep[0] & 0xee == 0)
&& (hdr.drep[1] <= 3);
return (is_dcerpc, is_request);
},
}
Err(_) => (false, false),
}
}

unsafe extern "C" fn probe_udp(_f: *const Flow, direction: u8, input: *const u8,
len: u32, rdir: *mut u8) -> AppProto
{
unsafe extern "C" fn probe_udp(
_f: *const Flow, direction: u8, input: *const u8, len: u32, rdir: *mut u8,
) -> AppProto {
SCLogDebug!("Probing the packet for DCERPC/UDP");
if len == 0 || input.is_null() {
return core::ALPROTO_UNKNOWN;
Expand All @@ -345,9 +362,18 @@ unsafe extern "C" fn probe_udp(_f: *const Flow, direction: u8, input: *const u8,

fn register_pattern_probe() -> i8 {
unsafe {
if SCAppLayerProtoDetectPMRegisterPatternCSwPP(core::IPPROTO_UDP, ALPROTO_DCERPC,
b"|04 00|\0".as_ptr() as *const std::os::raw::c_char, 2, 0,
Direction::ToServer.into(), Some(probe_udp), 0, 0) < 0 {
if SCAppLayerProtoDetectPMRegisterPatternCSwPP(
core::IPPROTO_UDP,
ALPROTO_DCERPC,
b"|04 00|\0".as_ptr() as *const std::os::raw::c_char,
2,
0,
Direction::ToServer.into(),
Some(probe_udp),
0,
0,
) < 0
{
SCLogDebug!("TOSERVER => SCAppLayerProtoDetectPMRegisterPatternCSwPP FAILED");
return -1;
}
Expand Down
3 changes: 1 addition & 2 deletions rust/src/dcerpc/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ fn match_backuuid(
if let Some(x) = &if_data.du16 {
if !detect_match_uint(x, uuidentry.version) {
SCLogDebug!("Interface version did not match");
continue
continue;
}
}

Expand Down Expand Up @@ -408,7 +408,6 @@ unsafe extern "C" fn dcerpc_stub_data_setup(
pub const DETECT_CI_FLAGS_DCE_LE: u8 = 1 << 2;
pub const DETECT_CI_FLAGS_DCE_BE: u8 = 1 << 3;


unsafe extern "C" fn dcerpc_tx_get_stub_data(
det_ctx: *mut DetectEngineThreadCtx, transforms: *const DetectEngineTransforms,
_flow: *mut Flow, dir: u8, tx: *mut c_void, list_id: c_int,
Expand Down
2 changes: 1 addition & 1 deletion rust/src/dcerpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@

pub mod dcerpc;
pub mod dcerpc_udp;
pub mod parser;
pub mod detect;
pub mod log;
pub mod parser;
41 changes: 28 additions & 13 deletions rust/src/dcerpc/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ use crate::dcerpc::dcerpc::{
use crate::dcerpc::dcerpc_udp::DCERPCHdrUdp;
use nom8::bytes::streaming::take;
use nom8::combinator::cond;
use nom8::multi::count;
use nom8::number::complete::{le_u16, le_u32, le_u8, u16, u32};
use nom8::number::Endianness;
use nom8::multi::count;
use nom8::{IResult, Parser};

fn uuid_to_vec(uuid: Uuid) -> Vec<u8> {
Expand Down Expand Up @@ -77,7 +77,11 @@ pub(super) fn parse_dcerpc_udp_header(i: &[u8]) -> IResult<&[u8], DCERPCHdrUdp>
let (i, flags1) = le_u8.parse(i)?;
let (i, flags2) = le_u8.parse(i)?;
let (i, drep) = take(3_usize).parse(i)?;
let endianness = if drep[0] == 0 { Endianness::Big } else { Endianness::Little };
let endianness = if drep[0] == 0 {
Endianness::Big
} else {
Endianness::Little
};
let (i, serial_hi) = le_u8.parse(i)?;
let (i, objectuuid) = take(16_usize).parse(i)?;
let (i, interfaceuuid) = take(16_usize).parse(i)?;
Expand All @@ -104,21 +108,21 @@ pub(super) fn parse_dcerpc_udp_header(i: &[u8]) -> IResult<&[u8], DCERPCHdrUdp>
Err(_e) => {
SCLogDebug!("{}", _e);
vec![0]
},
}
},
interfaceuuid: match parse_uuid(interfaceuuid) {
Ok((_, vect)) => assemble_uuid(vect),
Err(_e) => {
SCLogDebug!("{}", _e);
vec![0]
},
}
},
activityuuid: match parse_uuid(activityuuid){
activityuuid: match parse_uuid(activityuuid) {
Ok((_, vect)) => assemble_uuid(vect),
Err(_e) => {
SCLogDebug!("{}", _e);
vec![0]
},
}
},
server_boot,
if_vers,
Expand All @@ -136,9 +140,9 @@ pub(super) fn parse_dcerpc_udp_header(i: &[u8]) -> IResult<&[u8], DCERPCHdrUdp>

pub(super) fn parse_dcerpc_bindack_result(i: &[u8]) -> IResult<&[u8], DCERPCBindAckResult> {
let (i, ack_result) = le_u16.parse(i)?;
let (i, ack_reason) = le_u16.parse(i)?;
let (i, transfer_syntax) = take(16_usize).parse(i)?;
let (i, syntax_version) = le_u32.parse(i)?;
let (i, ack_reason) = le_u16.parse(i)?;
let (i, transfer_syntax) = take(16_usize).parse(i)?;
let (i, syntax_version) = le_u32.parse(i)?;
let result = DCERPCBindAckResult {
ack_result,
ack_reason,
Expand All @@ -154,7 +158,10 @@ pub(super) fn parse_dcerpc_bindack(i: &[u8]) -> IResult<&[u8], DCERPCBindAck> {
let (i, _assoc_group) = take(4_usize).parse(i)?;
let (i, sec_addr_len) = le_u16.parse(i)?;
let (i, _) = take(sec_addr_len).parse(i)?;
let (i, _) = cond((sec_addr_len.wrapping_add(2)) % 4 != 0, |b| take(4 - (sec_addr_len.wrapping_add(2)) % 4).parse(b)).parse(i)?;
let (i, _) = cond((sec_addr_len.wrapping_add(2)) % 4 != 0, |b| {
take(4 - (sec_addr_len.wrapping_add(2)) % 4).parse(b)
})
.parse(i)?;
let (i, numctxitems) = le_u8.parse(i)?;
let (i, _) = take(3_usize).parse(i)?; // Padding
let (i, ctxitems) = count(parse_dcerpc_bindack_result, numctxitems as usize).parse(i)?;
Expand Down Expand Up @@ -184,7 +191,9 @@ pub(super) fn parse_bindctx_item(i: &[u8], endianness: Endianness) -> IResult<&[
_ => uuid_to_vec(vect),
},
// Shouldn't happen
Err(_e) => {vec![0]},
Err(_e) => {
vec![0]
}
},
version,
versionminor,
Expand All @@ -211,7 +220,11 @@ pub(super) fn parse_dcerpc_header(i: &[u8]) -> IResult<&[u8], DCERPCHdr> {
let (i, hdrtype) = le_u8.parse(i)?;
let (i, pfc_flags) = le_u8.parse(i)?;
let (i, packed_drep) = take(4_usize).parse(i)?;
let endianness = if packed_drep[0] & 0x10 == 0 { Endianness::Big } else { Endianness::Little };
let endianness = if packed_drep[0] & 0x10 == 0 {
Endianness::Big
} else {
Endianness::Little
};
let (i, frag_length) = u16(endianness).parse(i)?;
let (i, auth_length) = u16(endianness).parse(i)?;
let (i, call_id) = u32(endianness).parse(i)?;
Expand All @@ -228,7 +241,9 @@ pub(super) fn parse_dcerpc_header(i: &[u8]) -> IResult<&[u8], DCERPCHdr> {
Ok((i, header))
}

pub(super) fn parse_dcerpc_request(i: &[u8], endianness: Endianness) -> IResult<&[u8], DCERPCRequest> {
pub(super) fn parse_dcerpc_request(
i: &[u8], endianness: Endianness,
) -> IResult<&[u8], DCERPCRequest> {
let (i, _pad) = take(4_usize).parse(i)?;
let (i, ctxid) = u16(endianness).parse(i)?;
let (i, opnum) = u16(endianness).parse(i)?;
Expand Down
2 changes: 1 addition & 1 deletion scripts/rustfmt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ rustfmt --check rust/src/dns/*.rs rust/src/applayertemplate/*.rs rust/src/asn1/*
rust/src/http2/*.rs rust/src/ike/*.rs rust/src/modbus/*.rs rust/src/mqtt/*.rs \
rust/src/nfs/*.rs rust/src/pgsql/*.rs rust/src/rdp/*.rs rust/src/sdp/*.rs \
rust/src/sip/*.rs rust/src/telnet/*.rs rust/src/tftp/*.rs rust/src/x509/*.rs \
rust/src/snmp/*.rs rust/src/llmnr/*.rs rust/src/detect/*.rs
rust/src/snmp/*.rs rust/src/llmnr/*.rs rust/src/detect/*.rs rust/src/dcerpc/*.rs
Loading
Loading