|
|
|
@ -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<String> = 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, &[]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|