diff --git a/rust/src/smb/smb2_records.rs b/rust/src/smb/smb2_records.rs index b19379883a..2eb0050618 100644 --- a/rust/src/smb/smb2_records.rs +++ b/rust/src/smb/smb2_records.rs @@ -345,7 +345,7 @@ pub fn parse_smb2_request_close(i: &[u8]) -> IResult<&[u8], Smb2CloseRequestReco Ok((i, record)) } -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct Smb2SetInfoRequestRenameRecord<'a> { pub name: &'a[u8], } @@ -360,7 +360,7 @@ pub fn parse_smb2_request_setinfo_rename(i: &[u8]) -> IResult<&[u8], Smb2SetInfo Ok((i, record)) } -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct Smb2SetInfoRequestDispoRecord { pub delete: bool, } @@ -373,7 +373,7 @@ pub fn parse_smb2_request_setinfo_disposition(i: &[u8]) -> IResult<&[u8], Smb2Se Ok((i, record)) } -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Smb2SetInfoRequestData<'a> { DISPOSITION(Smb2SetInfoRequestDispoRecord), RENAME(Smb2SetInfoRequestRenameRecord<'a>), @@ -626,3 +626,240 @@ pub fn search_smb_record(i: &[u8]) -> IResult<&[u8], &[u8]> { } Err(Err::Incomplete(Needed::new(4_usize - d.len()))) } + + +#[cfg(test)] +mod tests { + use super::*; + use crate::smb::smb2::smb2_dialect_string; + use std::convert::TryInto; + fn guid_to_string(guid: &[u8]) -> String { + if guid.len() == 16 { + let output = format!("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", + guid[3], guid[2], guid[1], guid[0], + guid[5], guid[4], guid[7], guid[6], + guid[9], guid[8], guid[11], guid[10], + guid[15], guid[14], guid[13], guid[12]); + output + } else { + "".to_string() + } + } + #[test] + fn test_parse_smb2_request_record() { + let data = hex::decode("fe534d42400000000000000000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let result = parse_smb2_request_record(&data).unwrap(); + let record: Smb2Record = result.1; + assert_eq!(record, Smb2Record { + direction: 1, + header_len: 64, + nt_status: 0, + command: 0, + message_id: 0, + tree_id: 0, + async_id: 0, + session_id: 0, + data: &[], + }); + } + #[test] + fn test_parse_smb2_request_negotiate_protocol() { + // https://github.com/bro/bro/blob/master/testing/btest/Traces/smb/smb3_negotiate_context.pcap + // smb3_negotiate_context.pcap no.12 + let data = hex::decode("24000800010000007f00000016ab4fd9625676488cd1707d08e52b5878000000020000000202100222022402000302031003110300000000010026000000000001002000010067e5f669ff3e0ad12e89ad84ceb1d35dfee53ede3e4858a6d1a9099ac1635a9600000200060000000000020001000200").unwrap(); + let result = parse_smb2_request_negotiate_protocol(&data).unwrap(); + let record: Smb2NegotiateProtocolRequestRecord = result.1; + let dialects:Vec = record.dialects_vec.iter().map(|d|smb2_dialect_string(*d)).collect(); + assert_eq!(dialects, ["2.02", "2.10", "2.22", "2.24", "3.00", "3.02", "3.10", "3.11"]); + assert_eq!(guid_to_string(record.client_guid), "d94fab16-5662-4876-d18c-7d70582be508"); // TODO: guid order + } + + #[test] + fn test_parse_smb2_response_tree_connect() { + // https://github.com/bro/bro/blob/master/testing/btest/Traces/smb/smb2.pcap + // filter:smb2 no.11 + let data = hex::decode("100001000008000000000000ff011f00").unwrap(); + let result = parse_smb2_response_tree_connect(&data).unwrap(); + let record: Smb2TreeConnectResponseRecord = result.1; + assert_eq!(record.share_type, 1); // 1: SMB2_SHARE_TYPE_DISK + } + #[test] + fn test_parse_smb2_request_create() { + // https://raw.githubusercontent.com/bro/bro/master/testing/btest/Traces/smb/smb2.pcap + // filter:smb2 no.26 + let data = hex::decode("390000000200000000000000000000000000000000000000810010008000000003000000020000002100200078000000800000005800000000007200760073002800000010000400000018001000000044486e510000000000000000000000000000000000000000180000001000040000001800000000004d78416300000000000000001000040000001800000000005146696400000000").unwrap(); + let result = parse_smb2_request_create(&data).unwrap(); + let record: Smb2CreateRequestRecord = result.1; + assert_eq!(record.disposition, 2); // FILE_CREATE: 2 + assert_eq!(record.create_options, 0x200021); + assert_eq!(record.data, &[]); + let del = record.create_options & 0x0000_1000 != 0; + let dir = record.create_options & 0x0000_0001 != 0; + assert_eq!(del, false); + assert_eq!(dir, true); + } + #[test] + fn test_parse_smb2_request_close() { + // https://raw.githubusercontent.com/bro/bro/master/testing/btest/Traces/smb/smb2.pcap + // filter:smb2 no.24 + let data = hex::decode("1800000000000000490000000000000005000000ffffffff").unwrap(); + let result = parse_smb2_request_close(&data).unwrap(); + let record: Smb2CloseRequestRecord = result.1; + assert_eq!(guid_to_string(record.guid), "00000049-0000-0000-0005-0000ffffffff"); + } + + #[test] + fn test_parse_smb2_request_setinfo() { + // https://raw.githubusercontent.com/bro/bro/master/testing/btest/Traces/smb/smb2.pcap + // filter:tcp.stream eq 0 no.36 + let data = hex::decode("210001140800000060000000000000004d0000000000000009000000ffffffff4b06170000000000").unwrap(); + let result = parse_smb2_request_setinfo(&data).unwrap(); + let record: Smb2SetInfoRequestRecord = result.1; + assert_eq!(record.class, 1); + assert_eq!(record.infolvl, 20); + assert_eq!(record.data, Smb2SetInfoRequestData::UNHANDLED); + assert_eq!(guid_to_string(record.guid), "0000004d-0000-0000-0009-0000ffffffff"); + } + + #[test] + fn test_parse_smb2_request_read() { + // https://raw.githubusercontent.com/bro/bro/master/testing/btest/Traces/smb/smb2.pcap + // filter:smb2 no.20 + let data = hex::decode("31005000000400000000000000000000490000000000000005000000ffffffff00000000000000000000000000000000").unwrap(); + let result = parse_smb2_request_read(&data).unwrap(); + let record: Smb2ReadRequestRecord = result.1; + assert_eq!(record.rd_len, 1024); + assert_eq!(record.rd_offset, 0); + assert_eq!(guid_to_string(record.guid), "00000049-0000-0000-0005-0000ffffffff"); + } + + #[test] + fn test_parse_smb2_request_write() { + // https://raw.githubusercontent.com/bro/bro/master/testing/btest/Traces/smb/smb2.pcap + // filter:tcp.stream eq 0 no.18 + let data = hex::decode("31007000740000000000000000000000490000000000000005000000ffffffff0000000000000000000000000000000005000b03100000007400000001000000b810b810000000000200000000000100c84f324b7016d30112785a47bf6ee18803000000045d888aeb1cc9119fe808002b1048600200000001000100c84f324b7016d30112785a47bf6ee188030000002c1cb76c12984045030000000000000001000000").unwrap(); + let result = parse_smb2_request_write(&data).unwrap(); + let record: Smb2WriteRequestRecord = result.1; + assert_eq!(record.wr_len, 116); + assert_eq!(record.wr_offset, 0); + assert_eq!(guid_to_string(record.guid), "00000049-0000-0000-0005-0000ffffffff"); + assert_eq!(record.data.len(), 116); + } + + + #[test] + fn test_parse_smb2_response_read() { + // https://raw.githubusercontent.com/bro/bro/master/testing/btest/Traces/smb/smb2.pcap + // filter:tcp.stream eq 0 no.21 + let data = hex::decode("110050005c000000000000000000000005000c03100000005c00000001000000b810b810b97200000d005c504950455c73727673766300000200000000000000045d888aeb1cc9119fe808002b10486002000000030003000000000000000000000000000000000000000000").unwrap(); + let result = parse_smb2_response_read(&data).unwrap(); + let record: Smb2ReadResponseRecord = result.1; + assert_eq!(record.len, 92); + assert_eq!(record.data.len(), 92); + + } + #[test] + fn test_parse_smb2_record_direction() { + let data = hex::decode("fe534d42400000000000000000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let result = parse_smb2_record_direction(&data).unwrap(); + let record: Smb2RecordDir = result.1; + assert_eq!(record.request, false); + let data = hex::decode("fe534d4240000000000000000100080000000000000000000100000000000000fffe000000000000000000000000000000000000000000000000000000000000").unwrap(); + let result = parse_smb2_record_direction(&data).unwrap(); + let record: Smb2RecordDir = result.1; + assert_eq!(record.request, true); + } + + #[test] + fn test_parse_smb2_request_tree_connect() { + let data = hex::decode("0900000048002c005c005c003100390032002e003100360038002e003100390039002e003100330033005c004900500043002400").unwrap(); + let result = parse_smb2_request_tree_connect(&data); + assert_eq!(result.is_ok(), true); + let record = result.unwrap().1; + assert!(record.share_name.len() > 2); + let share_name_len = u16::from_le_bytes(record.share_name[0..2].try_into().unwrap()); + assert_eq!(share_name_len ,44); + assert_eq!(record.share_name.len() ,share_name_len as usize + 2); + let mut share_name = record.share_name[2..].to_vec(); + share_name.retain(|&i|i != 0x00); + assert_eq!(String::from_utf8_lossy(&share_name), "\\\\192.168.199.133\\IPC$"); + } + + #[test] + fn test_parse_smb2_response_record() { + let data = hex::decode("fe534d4240000000000000000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041000100ff020000966eafa3357f0440a5f9643e1bfa8c56070000000000800000008000000080001064882d8527d201a1f3ae878427d20180004001000000006082013c06062b0601050502a08201303082012ca01a3018060a2b06010401823702021e060a2b06010401823702020aa282010c048201084e45474f45585453010000000000000060000000700000007fb23ba7cacc4e216323ca8472061efbd2c4f6d6b3017012f0bf4f7202ec684ee801ef64e55401ab86b1c9ebde4e39ea0000000000000000600000000100000000000000000000005c33530deaf90d4db2ec4ae3786ec3084e45474f45585453030000000100000040000000980000007fb23ba7cacc4e216323ca8472061efb5c33530deaf90d4db2ec4ae3786ec30840000000580000003056a05430523027802530233121301f06035504031318546f6b656e205369676e696e67205075626c6963204b65793027802530233121301f06035504031318546f6b656e205369676e696e67205075626c6963204b6579").unwrap(); + let result = parse_smb2_response_record(&data); + assert_eq!(result.is_ok(), true); + let record = result.unwrap().1; + assert_eq!(record.direction, 1); + assert_eq!(record.header_len, 64); + assert_eq!(record.nt_status, 0); + assert_eq!(record.command, crate::smb::smb2::SMB2_COMMAND_NEGOTIATE_PROTOCOL); + assert_eq!(record.message_id, 0); + assert_eq!(record.tree_id, 0); + assert_eq!(record.async_id, 0); + assert_eq!(record.session_id, 0); + let neg_proto_result = parse_smb2_response_negotiate_protocol(record.data); + assert_eq!(neg_proto_result.is_ok(), true); + let neg_proto = neg_proto_result.unwrap().1; + assert_eq!(guid_to_string(neg_proto.server_guid), "a3af6e96-7f35-4004-f9a5-3e64568cfa1b"); + assert_eq!(neg_proto.dialect, 0x2ff); + assert_eq!(smb2_dialect_string(neg_proto.dialect), "2.??".to_string()); + assert_eq!(neg_proto.max_trans_size, 0x800000); + assert_eq!(neg_proto.max_read_size, 0x800000); + assert_eq!(neg_proto.max_write_size, 0x800000); + } + + #[test] + fn test_todo_parse_smb2_response_negotiate_protocol_error() { + // TODO: find pcap + } + + #[test] + fn test_parse_smb2_response_write() { + let data = hex::decode("11000000a00000000000000000000000").unwrap(); + let result = parse_smb2_response_write(&data); + assert_eq!(result.is_ok(), true); + let record = result.unwrap().1; + assert_eq!(record.wr_cnt, 160); + } + #[test] + fn test_parse_smb2_response_create() { + let data = hex::decode("5900000001000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000800000000000000001000000db3b5a009a29ea00000000000000000000000000").unwrap(); + let result = parse_smb2_response_create(&data); + assert_eq!(result.is_ok(), true); + let record = result.unwrap().1; + assert_eq!(guid_to_string(record.guid), "00000001-3bdb-005a-299a-00ea00000000"); + assert_eq!(record.create_ts, SMBFiletime::new(0)); + assert_eq!(record.last_access_ts, SMBFiletime::new(0)); + assert_eq!(record.last_write_ts, SMBFiletime::new(0)); + assert_eq!(record.last_change_ts, SMBFiletime::new(0)); + assert_eq!(record.size, 0); + + } + #[test] + fn test_parse_smb2_response_ioctl() { + let data = hex::decode("31000000fc011400ffffffffffffffffffffffffffffffff7000000000000000700000003001000000000000000000009800000004000000010000000000000000ca9a3b0000000002000000c0a8c7850000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000010000000000000000ca9a3b000000001700000000000000fe8000000000000065b53a9792d191990000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let result = parse_smb2_response_ioctl(&data); + assert_eq!(result.is_ok(), true); + let record = result.unwrap().1; + assert_eq!(record.indata_len, 0); + assert_eq!(guid_to_string(record.guid), "ffffffff-ffff-ffff-ffff-ffffffffffff"); + assert_eq!(record.is_pipe, false); + assert_eq!(record.outdata_len, 304); + assert_eq!(record.indata_offset, 112); + assert_eq!(record.outdata_offset, 112); + } + + #[test] + fn test_parse_smb2_request_ioctl() { + let data = hex::decode("39000000fc011400ffffffffffffffffffffffffffffffff7800000000000000000000007800000000000000000001000100000000000000").unwrap(); + let result = parse_smb2_request_ioctl(&data); + assert_eq!(result.is_ok(), true); + let record = result.unwrap().1; + assert_eq!(guid_to_string(record.guid), "ffffffff-ffff-ffff-ffff-ffffffffffff"); + assert_eq!(record.is_pipe, false); + assert_eq!(record.function, 0x1401fc); + assert_eq!(record.data, &[]); + } +} diff --git a/rust/src/smb/smb3.rs b/rust/src/smb/smb3.rs index 287a5cf4b3..07a7059955 100644 --- a/rust/src/smb/smb3.rs +++ b/rust/src/smb/smb3.rs @@ -42,3 +42,18 @@ pub fn parse_smb3_transform_record(i: &[u8]) -> IResult<&[u8], Smb3TransformReco }; Ok((i, record)) } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_parse_smb3_transform_record() { + // https://raw.githubusercontent.com/bro/bro/master/testing/btest/Traces/smb/smb3.pcap + let data = hex::decode("fd534d42188d39cea4b1e3f640aff5d0b1569852c0bd665516dbb4b499507f000000000069000000000001003d00009400480000d9f8a66572b40c621bea6f5922a412a8eb2e3cc2af9ce26a277e75898cb523b9eb49ef660a6a1a09368fadd6a58e893e08eb3b7c068bdb74b6cd38e9ed1a2559cefb2ebc2172fd86c08a1a636eb851f20bf53a242f4cfaf7ab44e77291073ad492d6297c3d3a67757c").unwrap(); + let result = parse_smb3_transform_record(&data).unwrap(); + let record: Smb3TransformRecord = result.1; + assert_eq!(record.session_id, 79167320227901); + assert_eq!(record.enc_algo, 1); + assert_eq!(record.enc_data.len(), 105); + } +}