mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
367 lines
12 KiB
Rust
367 lines
12 KiB
Rust
/* Copyright (C) 2020 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
|
|
* Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
use crate::dcerpc::dcerpc::{
|
|
BindCtxItem, DCERPCBind, DCERPCBindAck, DCERPCBindAckResult, DCERPCHdr, DCERPCRequest, Uuid,
|
|
};
|
|
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::{IResult, Parser};
|
|
|
|
fn uuid_to_vec(uuid: Uuid) -> Vec<u8> {
|
|
let mut uuidtmp = uuid;
|
|
let mut vect: Vec<u8> = Vec::new();
|
|
vect.append(&mut uuidtmp.time_low);
|
|
vect.append(&mut uuidtmp.time_mid);
|
|
vect.append(&mut uuidtmp.time_hi_and_version);
|
|
vect.push(uuidtmp.clock_seq_hi_and_reserved);
|
|
vect.push(uuidtmp.clock_seq_low);
|
|
vect.append(&mut uuidtmp.node);
|
|
vect
|
|
}
|
|
|
|
fn assemble_uuid(uuid: Uuid) -> Vec<u8> {
|
|
let mut uuidtmp = uuid;
|
|
let mut vect: Vec<u8> = Vec::new();
|
|
uuidtmp.time_low.reverse();
|
|
uuidtmp.time_mid.reverse();
|
|
uuidtmp.time_hi_and_version.reverse();
|
|
vect.append(&mut uuidtmp.time_low);
|
|
vect.append(&mut uuidtmp.time_mid);
|
|
vect.append(&mut uuidtmp.time_hi_and_version);
|
|
vect.push(uuidtmp.clock_seq_hi_and_reserved);
|
|
vect.push(uuidtmp.clock_seq_low);
|
|
vect.append(&mut uuidtmp.node);
|
|
|
|
vect
|
|
}
|
|
|
|
fn parse_uuid(i: &[u8]) -> IResult<&[u8], Uuid> {
|
|
let (i, time_low) = take(4_usize).parse(i)?;
|
|
let (i, time_mid) = take(2_usize).parse(i)?;
|
|
let (i, time_hi_and_version) = take(2_usize).parse(i)?;
|
|
let (i, clock_seq_hi_and_reserved) = le_u8.parse(i)?;
|
|
let (i, clock_seq_low) = le_u8.parse(i)?;
|
|
let (i, node) = take(6_usize).parse(i)?;
|
|
let uuid = Uuid {
|
|
time_low: time_low.to_vec(),
|
|
time_mid: time_mid.to_vec(),
|
|
time_hi_and_version: time_hi_and_version.to_vec(),
|
|
clock_seq_hi_and_reserved,
|
|
clock_seq_low,
|
|
node: node.to_vec(),
|
|
};
|
|
Ok((i, uuid))
|
|
}
|
|
|
|
pub(super) fn parse_dcerpc_udp_header(i: &[u8]) -> IResult<&[u8], DCERPCHdrUdp> {
|
|
let (i, rpc_vers) = le_u8.parse(i)?;
|
|
let (i, pkt_type) = le_u8.parse(i)?;
|
|
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 (i, serial_hi) = le_u8.parse(i)?;
|
|
let (i, objectuuid) = take(16_usize).parse(i)?;
|
|
let (i, interfaceuuid) = take(16_usize).parse(i)?;
|
|
let (i, activityuuid) = take(16_usize).parse(i)?;
|
|
let (i, server_boot) = u32(endianness).parse(i)?;
|
|
let (i, if_vers) = u32(endianness).parse(i)?;
|
|
let (i, seqnum) = u32(endianness).parse(i)?;
|
|
let (i, opnum) = u16(endianness).parse(i)?;
|
|
let (i, ihint) = u16(endianness).parse(i)?;
|
|
let (i, ahint) = u16(endianness).parse(i)?;
|
|
let (i, fraglen) = u16(endianness).parse(i)?;
|
|
let (i, fragnum) = u16(endianness).parse(i)?;
|
|
let (i, auth_proto) = le_u8.parse(i)?;
|
|
let (i, serial_lo) = le_u8.parse(i)?;
|
|
let header = DCERPCHdrUdp {
|
|
rpc_vers,
|
|
pkt_type,
|
|
flags1,
|
|
flags2,
|
|
drep: drep.to_vec(),
|
|
serial_hi,
|
|
objectuuid: match parse_uuid(objectuuid) {
|
|
Ok((_, vect)) => assemble_uuid(vect),
|
|
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) {
|
|
Ok((_, vect)) => assemble_uuid(vect),
|
|
Err(_e) => {
|
|
SCLogDebug!("{}", _e);
|
|
vec![0]
|
|
}
|
|
},
|
|
server_boot,
|
|
if_vers,
|
|
seqnum,
|
|
opnum,
|
|
ihint,
|
|
ahint,
|
|
fraglen,
|
|
fragnum,
|
|
auth_proto,
|
|
serial_lo,
|
|
};
|
|
Ok((i, header))
|
|
}
|
|
|
|
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 result = DCERPCBindAckResult {
|
|
ack_result,
|
|
ack_reason,
|
|
transfer_syntax: transfer_syntax.to_vec(),
|
|
syntax_version,
|
|
};
|
|
Ok((i, result))
|
|
}
|
|
|
|
pub(super) fn parse_dcerpc_bindack(i: &[u8]) -> IResult<&[u8], DCERPCBindAck> {
|
|
let (i, _max_xmit_frag) = le_u16.parse(i)?;
|
|
let (i, _max_recv_frag) = le_u16.parse(i)?;
|
|
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, 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)?;
|
|
let result = DCERPCBindAck {
|
|
accepted_uuid_list: Vec::new(),
|
|
sec_addr_len,
|
|
numctxitems,
|
|
ctxitems,
|
|
};
|
|
Ok((i, result))
|
|
}
|
|
|
|
pub(super) fn parse_bindctx_item(i: &[u8], endianness: Endianness) -> IResult<&[u8], BindCtxItem> {
|
|
let (i, ctxid) = u16(endianness).parse(i)?;
|
|
let (i, _num_trans_items) = le_u8.parse(i)?;
|
|
let (i, _) = take(1_usize).parse(i)?; // Reserved bit
|
|
let (i, uuid) = take(16_usize).parse(i)?;
|
|
let (i, version) = u16(endianness).parse(i)?;
|
|
let (i, versionminor) = u16(endianness).parse(i)?;
|
|
let (i, _) = take(20_usize).parse(i)?;
|
|
let result = BindCtxItem {
|
|
ctxid,
|
|
// UUID parsing for TCP seems to change as per endianness
|
|
uuid: match parse_uuid(uuid) {
|
|
Ok((_, vect)) => match endianness {
|
|
Endianness::Little => assemble_uuid(vect),
|
|
_ => uuid_to_vec(vect),
|
|
},
|
|
// Shouldn't happen
|
|
Err(_e) => {
|
|
vec![0]
|
|
}
|
|
},
|
|
version,
|
|
versionminor,
|
|
};
|
|
Ok((i, result))
|
|
}
|
|
|
|
pub(super) fn parse_dcerpc_bind(i: &[u8]) -> IResult<&[u8], DCERPCBind> {
|
|
let (i, _max_xmit_frag) = le_u16.parse(i)?;
|
|
let (i, _max_recv_frag) = le_u16.parse(i)?;
|
|
let (i, _assoc_group_id) = le_u32.parse(i)?;
|
|
let (i, numctxitems) = le_u8.parse(i)?;
|
|
let (i, _) = take(3_usize).parse(i)?;
|
|
let result = DCERPCBind {
|
|
numctxitems,
|
|
uuid_list: Vec::new(),
|
|
};
|
|
Ok((i, result))
|
|
}
|
|
|
|
pub(super) fn parse_dcerpc_header(i: &[u8]) -> IResult<&[u8], DCERPCHdr> {
|
|
let (i, rpc_vers) = le_u8.parse(i)?;
|
|
let (i, rpc_vers_minor) = le_u8.parse(i)?;
|
|
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 (i, frag_length) = u16(endianness).parse(i)?;
|
|
let (i, auth_length) = u16(endianness).parse(i)?;
|
|
let (i, call_id) = u32(endianness).parse(i)?;
|
|
let header = DCERPCHdr {
|
|
rpc_vers,
|
|
rpc_vers_minor,
|
|
hdrtype,
|
|
pfc_flags,
|
|
packed_drep: [
|
|
packed_drep[0],
|
|
packed_drep[1],
|
|
packed_drep[2],
|
|
packed_drep[3],
|
|
],
|
|
frag_length,
|
|
auth_length,
|
|
call_id,
|
|
};
|
|
Ok((i, header))
|
|
}
|
|
|
|
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)?;
|
|
let req = DCERPCRequest {
|
|
ctxid,
|
|
opnum,
|
|
first_request_seen: 1,
|
|
};
|
|
Ok((i, req))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_parse_uuid() {
|
|
let uuid: &[u8] = &[
|
|
0xb8, 0x4a, 0x9f, 0x4d, 0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e,
|
|
0x7c, 0x57,
|
|
];
|
|
let expected_uuid = Uuid {
|
|
time_low: vec![0xb8, 0x4a, 0x9f, 0x4d],
|
|
time_mid: vec![0x1c, 0x7d],
|
|
time_hi_and_version: vec![0xcf, 0x11],
|
|
clock_seq_hi_and_reserved: 0x86,
|
|
clock_seq_low: 0x1e,
|
|
node: vec![0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57],
|
|
};
|
|
let (_remainder, parsed_uuid) = parse_uuid(uuid).unwrap();
|
|
assert_eq!(expected_uuid, parsed_uuid);
|
|
}
|
|
|
|
#[test]
|
|
fn test_assemble_uuid() {
|
|
let uuid = Uuid {
|
|
time_low: vec![0xb8, 0x4a, 0x9f, 0x4d],
|
|
time_mid: vec![0x1c, 0x7d],
|
|
time_hi_and_version: vec![0xcf, 0x11],
|
|
clock_seq_hi_and_reserved: 0x86,
|
|
clock_seq_low: 0x1e,
|
|
node: vec![0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57],
|
|
};
|
|
let expected_val = vec![
|
|
0x4d, 0x9f, 0x4a, 0xb8, 0x7d, 0x1c, 0x11, 0xcf, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e,
|
|
0x7c, 0x57,
|
|
];
|
|
assert_eq!(expected_val, assemble_uuid(uuid));
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_dcerpc_udp_header() {
|
|
let dcerpcheader: &[u8] = &[
|
|
0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x4a, 0x9f, 0x4d,
|
|
0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57, 0x86, 0xc2,
|
|
0x37, 0x67, 0xf7, 0x1e, 0xd1, 0x11, 0xbc, 0xd9, 0x00, 0x60, 0x97, 0x92, 0xd2, 0x6c,
|
|
0x79, 0xbe, 0x01, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xff, 0xff, 0xff, 0xff, 0x68, 0x00, 0x00, 0x00, 0x0a, 0x00,
|
|
];
|
|
let (_remainder, header) = parse_dcerpc_udp_header(dcerpcheader).unwrap();
|
|
let expected_activityuuid = vec![
|
|
0x67, 0x37, 0xc2, 0x86, 0x1e, 0xf7, 0x11, 0xd1, 0xbc, 0xd9, 0x00, 0x60, 0x97, 0x92,
|
|
0xd2, 0x6c,
|
|
];
|
|
assert_eq!(0x04, header.rpc_vers);
|
|
assert_eq!(0x00, header.pkt_type);
|
|
assert_eq!(0x08, header.flags1);
|
|
assert_eq!(0x00, header.flags2);
|
|
assert_eq!(vec!(0x10, 0x00, 0x00), header.drep);
|
|
assert_eq!(0x00, header.serial_hi);
|
|
assert_eq!(expected_activityuuid, header.activityuuid);
|
|
assert_eq!(0x3401be79, header.server_boot);
|
|
assert_eq!(0x00000000, header.seqnum);
|
|
assert_eq!(0xffff, header.ihint);
|
|
assert_eq!(0x0068, header.fraglen);
|
|
assert_eq!(0x0a, header.auth_proto);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_dcerpc_header() {
|
|
let dcerpcheader: &[u8] = &[
|
|
0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00,
|
|
];
|
|
let (_remainder, header) = parse_dcerpc_header(dcerpcheader).unwrap();
|
|
assert_eq!(5, header.rpc_vers);
|
|
assert_eq!(0, header.rpc_vers_minor);
|
|
assert_eq!(0, header.hdrtype);
|
|
assert_eq!(1024, header.frag_length);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_dcerpc_bind() {
|
|
let dcerpcbind: &[u8] = &[
|
|
0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
|
|
];
|
|
let (_remainder, bind) = parse_dcerpc_bind(dcerpcbind).unwrap();
|
|
assert_eq!(24, bind.numctxitems);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_bindctx_item() {
|
|
let dcerpcbind: &[u8] = &[
|
|
0x00, 0x00, 0x01, 0x00, 0x2c, 0xd0, 0x28, 0xda, 0x76, 0x91, 0xf6, 0x6e, 0xcb, 0x0f,
|
|
0xbf, 0x85, 0xcd, 0x9b, 0xf6, 0x39, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a,
|
|
0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00,
|
|
0x00, 0x00,
|
|
];
|
|
let (_remainder, ctxitem) = parse_bindctx_item(dcerpcbind, Endianness::Little).unwrap();
|
|
assert_eq!(0, ctxitem.ctxid);
|
|
assert_eq!(1, ctxitem.version);
|
|
assert_eq!(3, ctxitem.versionminor);
|
|
}
|
|
}
|