diff --git a/src/proto/dissector.rs b/src/proto/dissector.rs new file mode 100644 index 0000000..a370e12 --- /dev/null +++ b/src/proto/dissector.rs @@ -0,0 +1,92 @@ +// This file is part of masscanned. +// Copyright 2021 - The IVRE project +// +// Masscanned is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Masscanned 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 +// along with Masscanned. If not, see . + +use crate::proto::ClientInfo; +use crate::proto::TCPControlBlock; +use crate::Masscanned; + +//////////// +// Common // +//////////// + +/// ### PacketDissector +/// A util class used to dissect fields. +#[derive(Debug, Clone)] +pub struct PacketDissector { + pub i: usize, + pub state: T, +} + +impl PacketDissector { + pub fn new(initial_state: T) -> PacketDissector { + return PacketDissector { + i: 0, + state: initial_state, + }; + } + pub fn next_state(&mut self, state: T) { + self.state = state; + self.i = 0; + } + pub fn next_state_when_i_reaches(&mut self, state: T, i: usize) { + if self.i == i { + self.next_state(state); + } + } + fn _read_usize(&mut self, byte: &u8, value: usize, next_state: T, size: usize) -> usize { + self.i += 1; + self.next_state_when_i_reaches(next_state, size); + (value << 8) + *byte as usize + } + fn _read_ulesize(&mut self, byte: &u8, value: usize, next_state: T, size: usize) -> usize { + let ret = value + ((*byte as usize) << (8 * self.i)); + self.i += 1; + self.next_state_when_i_reaches(next_state, size); + ret + } + pub fn read_u16(&mut self, byte: &u8, value: u16, next_state: T) -> u16 { + self._read_usize(byte, value as usize, next_state, 2) as u16 + } + pub fn read_ule16(&mut self, byte: &u8, value: u16, next_state: T) -> u16 { + self._read_ulesize(byte, value as usize, next_state, 2) as u16 + } + pub fn read_u32(&mut self, byte: &u8, value: u32, next_state: T) -> u32 { + self._read_usize(byte, value as usize, next_state, 4) as u32 + } + pub fn read_ule32(&mut self, byte: &u8, value: u32, next_state: T) -> u32 { + self._read_ulesize(byte, value as usize, next_state, 4) as u32 + } + pub fn read_ule64(&mut self, byte: &u8, value: u64, next_state: T) -> u64 { + self._read_ulesize(byte, value as usize, next_state, 8) as u64 + } +} + +pub trait MPacket { + fn new() -> Self; + fn repl( + &self, + _masscanned: &Masscanned, + _client_info: &ClientInfo, + _tcb: Option<&mut TCPControlBlock>, + ) -> Option>; + fn parse(&mut self, byte: &u8); + + fn parse_all(&mut self, bytes: &[u8]) { + for byte in bytes { + self.parse(byte); + } + } +} diff --git a/src/proto/smb.rs b/src/proto/smb.rs index 1d17a3b..2356eb8 100644 --- a/src/proto/smb.rs +++ b/src/proto/smb.rs @@ -23,6 +23,8 @@ use crate::client::ClientInfo; use crate::proto::TCPControlBlock; use crate::Masscanned; +use crate::proto::dissector::{MPacket, PacketDissector}; + // NBTSession + SMB Header // netbios type (1 byte) + reserved (1 byte) + length (2 bytes) + SMB MAGIC (4 bytes) // @@ -33,70 +35,6 @@ pub const SMB2_PATTERN_MAGIC: &[u8; 8] = b"\x00\x00**\xfeSMB"; const SECURITY_BLOB_NEG_PROTO: &[u8] = b"`\x82\x01<\x06\x06+\x06\x01\x05\x05\x02\xa0\x82\x0100\x82\x01,\xa0\x1a0\x18\x06\n+\x06\x01\x04\x01\x827\x02\x02\x1e\x06\n+\x06\x01\x04\x01\x827\x02\x02\n\xa2\x82\x01\x0c\x04\x82\x01\x08NEGOEXTS\x01\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00p\x00\x00\x001<*:\xc7+<\xa9m\xac8t\xa7\xdd\x1d[\xf4Rk\x17\x03\x8aK\x91\xc2\t}\x9a\x8f\xe6,\x96\\Q$/\x90MG\xc7\xad\x8f\x87k\"\x02\xbf\xc6\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\\3S\r\xea\xf9\rM\xb2\xecJ\xe3xn\xc3\x08NEGOEXTS\x03\x00\x00\x00\x01\x00\x00\x00@\x00\x00\x00\x98\x00\x00\x001<*:\xc7+<\xa9m\xac8t\xa7\xdd\x1d[\\3S\r\xea\xf9\rM\xb2\xecJ\xe3xn\xc3\x08@\x00\x00\x00X\x00\x00\x000V\xa0T0R0'\x80%0#1!0\x1f\x06\x03U\x04\x03\x13\x18Token Signing Public Key0'\x80%0#1!0\x1f\x06\x03U\x04\x03\x13\x18Token Signing Public Key"; const SECURITY_BLOB_CHALLENGE: &[u8] = b"\xa1\x81\x9c0\x81\x99\xa0\x03\n\x01\x01\xa1\x0c\x06\n+\x06\x01\x04\x01\x827\x02\x02\n\xa2\x81\x83\x04\x81\x80NTLMSSP\x00\x02\x00\x00\x00\x08\x00\x08\x008\x00\x00\x00\x15\x82\x8a\xe2$\x91\xa8\xf6\xf3\x89-4\x00\x00\x00\x00\x00\x00\x00\x00@\x00@\x00@\x00\x00\x00\n\x00aJ\x00\x00\x00\x0fW\x00I\x00N\x001\x00\x02\x00\x08\x00W\x00I\x00N\x001\x00\x01\x00\x08\x00W\x00I\x00N\x001\x00\x04\x00\x08\x00W\x00I\x00N\x001\x00\x03\x00\x08\x00W\x00I\x00N\x001\x00\x07\x00\x08\x00\xff&9\xf5B\x1d\xd8\x01\x00\x00\x00\x00"; -//////////// -// Common // -//////////// - -/// ### PacketDissector -/// A util class used to dissect fields. -#[derive(Debug, Clone)] -struct PacketDissector { - i: usize, - state: T, -} -impl PacketDissector { - fn new(initial_state: T) -> PacketDissector { - return PacketDissector { - i: 0, - state: initial_state, - }; - } - fn next_state(&mut self, state: T) { - self.state = state; - self.i = 0; - } - fn next_state_when_i_reaches(&mut self, state: T, i: usize) { - if self.i == i { - self.next_state(state); - } - } - fn _read_usize(&mut self, byte: &u8, value: usize, next_state: T, size: usize) -> usize { - self.i += 1; - self.next_state_when_i_reaches(next_state, size); - (value << 8) + *byte as usize - } - fn _read_ulesize(&mut self, byte: &u8, value: usize, next_state: T, size: usize) -> usize { - let ret = value + ((*byte as usize) << (8 * self.i)); - self.i += 1; - self.next_state_when_i_reaches(next_state, size); - ret - } - fn read_u16(&mut self, byte: &u8, value: u16, next_state: T) -> u16 { - self._read_usize(byte, value as usize, next_state, 2) as u16 - } - fn read_ule16(&mut self, byte: &u8, value: u16, next_state: T) -> u16 { - self._read_ulesize(byte, value as usize, next_state, 2) as u16 - } - fn read_ule32(&mut self, byte: &u8, value: u32, next_state: T) -> u32 { - self._read_ulesize(byte, value as usize, next_state, 4) as u32 - } - fn read_ule64(&mut self, byte: &u8, value: u64, next_state: T) -> u64 { - self._read_ulesize(byte, value as usize, next_state, 8) as u64 - } -} - -pub trait MPacket { - fn new() -> Self; - fn repl(&self) -> Option>; - fn parse(&mut self, byte: &u8); - - fn parse_all(&mut self, bytes: &[u8]) { - for byte in bytes { - self.parse(byte); - } - } -} - ///////////// // Netbios // ///////////// @@ -148,8 +86,13 @@ impl MPacket for NBTSession { } } - fn repl(&self) -> Option> { - let payload_resp = self.payload.as_ref()?.repl()?; + fn repl( + &self, + masscanned: &Masscanned, + client_info: &ClientInfo, + tcb: Option<&mut TCPControlBlock>, + ) -> Option> { + let payload_resp = self.payload.as_ref()?.repl(masscanned, client_info, tcb)?; let mut resp: Vec = Vec::new(); let size = payload_resp.len() & 0x1ffff; // 7 first bits are 0 resp.push(0x0); @@ -288,8 +231,13 @@ impl MPacket for SMB1Header { } } - fn repl(&self) -> Option> { - let payload_resp = self.payload.as_ref()?.repl()?; + fn repl( + &self, + masscanned: &Masscanned, + client_info: &ClientInfo, + tcb: Option<&mut TCPControlBlock>, + ) -> Option> { + let payload_resp = self.payload.as_ref()?.repl(masscanned, client_info, tcb)?; let mut resp: Vec = Vec::new(); resp.extend_from_slice(b"\xffSMB"); // Start resp.push(self.command); // Command @@ -407,7 +355,12 @@ impl MPacket for SMB1NegotiateRequest { } } - fn repl(&self) -> Option> { + fn repl( + &self, + _masscanned: &Masscanned, + _client_info: &ClientInfo, + _tcb: Option<&mut TCPControlBlock>, + ) -> Option> { if !matches!(self.d.state, SMB1NegotiateRequestState::End) { return None; } @@ -592,7 +545,12 @@ impl MPacket for SMB1SessionSetupRequest { SMB1SessionSetupRequestState::End => {} } } - fn repl(&self) -> Option> { + fn repl( + &self, + _masscanned: &Masscanned, + _client_info: &ClientInfo, + _tcb: Option<&mut TCPControlBlock>, + ) -> Option> { if !matches!(self.d.state, SMB1SessionSetupRequestState::End) { return None; } @@ -625,10 +583,15 @@ enum SMB1Payload { } impl SMB1Payload { - fn repl(&self) -> Option> { + fn repl( + &self, + masscanned: &Masscanned, + client_info: &ClientInfo, + tcb: Option<&mut TCPControlBlock>, + ) -> Option> { match self { - SMB1Payload::NegotiateRequest(x) => x.repl(), - SMB1Payload::SessionSetupRequest(x) => x.repl(), + SMB1Payload::NegotiateRequest(x) => x.repl(masscanned, client_info, tcb), + SMB1Payload::SessionSetupRequest(x) => x.repl(masscanned, client_info, tcb), } } fn parse(&mut self, byte: &u8) { @@ -771,8 +734,13 @@ impl MPacket for SMB2Header { } } - fn repl(&self) -> Option> { - let payload_resp = self.payload.as_ref()?.repl()?; + fn repl( + &self, + masscanned: &Masscanned, + client_info: &ClientInfo, + tcb: Option<&mut TCPControlBlock>, + ) -> Option> { + let payload_resp = self.payload.as_ref()?.repl(masscanned, client_info, tcb)?; let mut resp: Vec = Vec::new(); resp.extend_from_slice(b"\xfeSMB"); // Start resp.extend_from_slice(&64_u16.to_le_bytes()); // StructureSize @@ -925,7 +893,12 @@ impl MPacket for SMB2NegotiateRequest { } } } - fn repl(&self) -> Option> { + fn repl( + &self, + _masscanned: &Masscanned, + _client_info: &ClientInfo, + _tcb: Option<&mut TCPControlBlock>, + ) -> Option> { if !matches!(self.d.state, SMB2NegotiateRequestState::End) { return None; } @@ -1077,7 +1050,12 @@ impl MPacket for SMB2SessionSetupRequest { } } - fn repl(&self) -> Option> { + fn repl( + &self, + _masscanned: &Masscanned, + _client_info: &ClientInfo, + _tcb: Option<&mut TCPControlBlock>, + ) -> Option> { if !matches!(self.d.state, SMB2SetupRequestState::End) { return None; } @@ -1099,10 +1077,15 @@ enum SMB2Payload { } impl SMB2Payload { - fn repl(&self) -> Option> { + fn repl( + &self, + masscanned: &Masscanned, + client_info: &ClientInfo, + tcb: Option<&mut TCPControlBlock>, + ) -> Option> { match self { - SMB2Payload::NegotiateRequest(x) => x.repl(), - SMB2Payload::SessionSetupRequest(x) => x.repl(), + SMB2Payload::NegotiateRequest(x) => x.repl(masscanned, client_info, tcb), + SMB2Payload::SessionSetupRequest(x) => x.repl(masscanned, client_info, tcb), } } fn parse(&mut self, byte: &u8) { @@ -1119,28 +1102,28 @@ impl SMB2Payload { pub fn repl_smb1<'a>( data: &'a [u8], - _masscanned: &Masscanned, - _client_info: &ClientInfo, - _tcb: Option<&mut TCPControlBlock>, + masscanned: &Masscanned, + client_info: &ClientInfo, + tcb: Option<&mut TCPControlBlock>, ) -> Option> { let mut nbtsession: NBTSession = NBTSession::new(); for byte in data { nbtsession.parse(byte); } - nbtsession.repl() + nbtsession.repl(masscanned, client_info, tcb) } pub fn repl_smb2<'a>( data: &'a [u8], - _masscanned: &Masscanned, - _client_info: &ClientInfo, - _tcb: Option<&mut TCPControlBlock>, + masscanned: &Masscanned, + client_info: &ClientInfo, + tcb: Option<&mut TCPControlBlock>, ) -> Option> { let mut nbtsession: NBTSession = NBTSession::new(); for byte in data { nbtsession.parse(byte); } - nbtsession.repl() + nbtsession.repl(masscanned, client_info, tcb) } ///////////