/src/suricata7/rust/src/smb/smb1_session.rs
Line | Count | Source |
1 | | /* Copyright (C) 2018 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | use crate::smb::smb_records::*; |
19 | | use crate::smb::smb1_records::*; |
20 | | use crate::smb::smb::*; |
21 | | use crate::smb::events::*; |
22 | | use crate::smb::auth::*; |
23 | | |
24 | | #[derive(Debug)] |
25 | | pub struct SessionSetupRequest { |
26 | | pub native_os: Vec<u8>, |
27 | | pub native_lm: Vec<u8>, |
28 | | pub primary_domain: Vec<u8>, |
29 | | } |
30 | | |
31 | | #[derive(Debug)] |
32 | | pub struct SessionSetupResponse { |
33 | | pub native_os: Vec<u8>, |
34 | | pub native_lm: Vec<u8>, |
35 | | } |
36 | | |
37 | 127k | pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupRequest |
38 | | { |
39 | 127k | if blob.len() > 1 && r.has_unicode_support() { |
40 | 34.9k | let offset = r.data.len() - blob.len(); |
41 | 34.9k | let blob = if offset % 2 == 1 { &blob[1..] } else { blob }; |
42 | 34.9k | let (native_os, native_lm, primary_domain) = match smb_get_unicode_string(blob) { |
43 | 24.4k | Ok((rem, n1)) => { |
44 | 24.4k | match smb_get_unicode_string(rem) { |
45 | 16.1k | Ok((rem, n2)) => { |
46 | 16.1k | match smb_get_unicode_string(rem) { |
47 | 10.0k | Ok((_, n3)) => { (n1, n2, n3) }, |
48 | 6.12k | _ => { (n1, n2, Vec::new()) }, |
49 | | } |
50 | | }, |
51 | 8.28k | _ => { (n1, Vec::new(), Vec::new()) }, |
52 | | } |
53 | | }, |
54 | 10.5k | _ => { (Vec::new(), Vec::new(), Vec::new()) }, |
55 | | }; |
56 | | |
57 | | SCLogDebug!("name1 {:?} name2 {:?} name3 {:?}", native_os,native_lm,primary_domain); |
58 | 34.9k | SessionSetupRequest { |
59 | 34.9k | native_os, |
60 | 34.9k | native_lm, |
61 | 34.9k | primary_domain, |
62 | 34.9k | } |
63 | | } else { |
64 | 92.1k | let (native_os, native_lm, primary_domain) = match smb_get_ascii_string(blob) { |
65 | 46.5k | Ok((rem, n1)) => { |
66 | 46.5k | match smb_get_ascii_string(rem) { |
67 | 41.7k | Ok((rem, n2)) => { |
68 | 41.7k | match smb_get_ascii_string(rem) { |
69 | 36.3k | Ok((_, n3)) => { (n1, n2, n3) }, |
70 | 5.36k | _ => { (n1, n2, Vec::new()) }, |
71 | | } |
72 | | }, |
73 | 4.77k | _ => { (n1, Vec::new(), Vec::new()) }, |
74 | | } |
75 | | }, |
76 | 45.5k | _ => { (Vec::new(), Vec::new(), Vec::new()) }, |
77 | | }; |
78 | | |
79 | | SCLogDebug!("session_setup_request_host_info: not unicode"); |
80 | 92.1k | SessionSetupRequest { |
81 | 92.1k | native_os, |
82 | 92.1k | native_lm, |
83 | 92.1k | primary_domain, |
84 | 92.1k | } |
85 | | } |
86 | 127k | } |
87 | | |
88 | 12.5k | pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupResponse |
89 | | { |
90 | 12.5k | if blob.len() > 1 && r.has_unicode_support() { |
91 | 6.78k | let offset = r.data.len() - blob.len(); |
92 | 6.78k | let blob = if offset % 2 == 1 { &blob[1..] } else { blob }; |
93 | 6.78k | let (native_os, native_lm) = match smb_get_unicode_string(blob) { |
94 | 4.86k | Ok((rem, n1)) => { |
95 | 4.86k | match smb_get_unicode_string(rem) { |
96 | 3.68k | Ok((_, n2)) => (n1, n2), |
97 | 1.17k | _ => { (n1, Vec::new()) }, |
98 | | } |
99 | | }, |
100 | 1.91k | _ => { (Vec::new(), Vec::new()) }, |
101 | | }; |
102 | | |
103 | | SCLogDebug!("name1 {:?} name2 {:?}", native_os,native_lm); |
104 | 6.78k | SessionSetupResponse { |
105 | 6.78k | native_os, |
106 | 6.78k | native_lm, |
107 | 6.78k | } |
108 | | } else { |
109 | | SCLogDebug!("session_setup_response_host_info: not unicode"); |
110 | 5.75k | let (native_os, native_lm) = match smb_get_ascii_string(blob) { |
111 | 4.51k | Ok((rem, n1)) => { |
112 | 4.51k | match smb_get_ascii_string(rem) { |
113 | 3.86k | Ok((_, n2)) => (n1, n2), |
114 | 647 | _ => { (n1, Vec::new()) }, |
115 | | } |
116 | | }, |
117 | 1.24k | _ => { (Vec::new(), Vec::new()) }, |
118 | | }; |
119 | 5.75k | SessionSetupResponse { |
120 | 5.75k | native_os, |
121 | 5.75k | native_lm, |
122 | 5.75k | } |
123 | | } |
124 | 12.5k | } |
125 | | |
126 | 148k | pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) |
127 | | { |
128 | | SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id); |
129 | | #[allow(clippy::single_match)] |
130 | 148k | match parse_smb_setup_andx_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { |
131 | 127k | Ok((rem, setup)) => { |
132 | 127k | let hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, |
133 | 127k | r.ssn_id as u64, 0, r.multiplex_id as u64); |
134 | 127k | let tx = state.new_sessionsetup_tx(hdr); |
135 | 127k | tx.vercmd.set_smb1_cmd(r.command); |
136 | | |
137 | 127k | if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data { |
138 | 127k | td.request_host = Some(smb1_session_setup_request_host_info(r, rem)); |
139 | 127k | if let Some(s) = parse_secblob(setup.sec_blob) { |
140 | 2.90k | td.ntlmssp = s.ntlmssp; |
141 | 2.90k | td.krb_ticket = s.krb; |
142 | 2.90k | if let Some(ntlm) = &td.ntlmssp { |
143 | 2.78k | if ntlm.warning { |
144 | 1.99k | tx.set_event(SMBEvent::UnusualNtlmsspOrder); |
145 | 1.99k | } |
146 | 128 | } |
147 | 124k | } |
148 | 0 | } |
149 | | }, |
150 | 20.9k | _ => { |
151 | 20.9k | // events.push(SMBEvent::MalformedData); |
152 | 20.9k | }, |
153 | | } |
154 | 148k | } |
155 | | |
156 | 18.6k | fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord, andx_offset: usize) |
157 | | { |
158 | 18.6k | match parse_smb_response_setup_andx_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { |
159 | 12.5k | Ok((rem, _setup)) => { |
160 | 12.5k | if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data { |
161 | 12.5k | td.response_host = Some(smb1_session_setup_response_host_info(r, rem)); |
162 | 12.5k | } |
163 | | }, |
164 | 6.08k | _ => { |
165 | 6.08k | tx.set_event(SMBEvent::MalformedData); |
166 | 6.08k | }, |
167 | | } |
168 | | // update tx even if we can't parse the response |
169 | 18.6k | tx.hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER); // to overwrite ssn_id 0 |
170 | 18.6k | tx.set_status(r.nt_status, r.is_dos_error); |
171 | 18.6k | tx.response_done = true; |
172 | 18.6k | } |
173 | | |
174 | 30.6k | pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) |
175 | | { |
176 | | // try exact match with session id already set (e.g. NTLMSSP AUTH phase) |
177 | 30.6k | let found = r.ssn_id != 0 && match state.get_sessionsetup_tx( |
178 | 28.0k | SMBCommonHdr::new(SMBHDR_TYPE_HEADER, |
179 | 28.0k | r.ssn_id as u64, 0, r.multiplex_id as u64)) |
180 | | { |
181 | 15.4k | Some(tx) => { |
182 | 15.4k | smb1_session_setup_update_tx(tx, r, andx_offset); |
183 | | SCLogDebug!("smb1_session_setup_response: tx {:?}", tx); |
184 | 15.4k | true |
185 | | }, |
186 | 12.6k | None => { false }, |
187 | | }; |
188 | | // otherwise try match with ssn id 0 (e.g. NTLMSSP_NEGOTIATE) |
189 | 30.6k | if !found { |
190 | 15.2k | if let Some(tx) = state.get_sessionsetup_tx( |
191 | 15.2k | SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.multiplex_id as u64)) |
192 | 3.21k | { |
193 | 3.21k | smb1_session_setup_update_tx(tx, r, andx_offset); |
194 | 3.21k | SCLogDebug!("smb1_session_setup_response: tx {:?}", tx); |
195 | 12.0k | } else { |
196 | 12.0k | SCLogDebug!("smb1_session_setup_response: tx not found for {:?}", r); |
197 | 12.0k | } |
198 | 15.4k | } |
199 | 30.6k | } |