/src/suricata7/rust/src/smb/dcerpc.rs
Line | Count | Source |
1 | | /* Copyright (C) 2017 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 | | // written by Victor Julien |
19 | | |
20 | | use uuid; |
21 | | use crate::smb::smb::*; |
22 | | use crate::smb::smb2::*; |
23 | | use crate::smb::dcerpc_records::*; |
24 | | use crate::smb::events::*; |
25 | | use crate::dcerpc::dcerpc::*; |
26 | | use crate::smb::smb_status::*; |
27 | | |
28 | | impl SMBCommonHdr { |
29 | | /// helper for DCERPC tx tracking. Check if we need |
30 | | /// to use the msg_id/multiplex_id in TX tracking. |
31 | | /// |
32 | 453k | pub fn to_dcerpc(&self, vercmd: &SMBVerCmdStat) -> SMBCommonHdr { |
33 | | // only use the msg id for IOCTL, not for READ/WRITE |
34 | | // as there request/response are different transactions |
35 | 453k | let mut use_msg_id = self.msg_id; |
36 | 453k | match vercmd.get_version() { |
37 | | 2 => { |
38 | 291k | let (_, cmd2) = vercmd.get_smb2_cmd(); |
39 | 291k | let x = match cmd2 { |
40 | 95.6k | SMB2_COMMAND_READ => { 0 }, |
41 | 188k | SMB2_COMMAND_WRITE => { 0 }, |
42 | 7.00k | SMB2_COMMAND_IOCTL => { self.msg_id }, |
43 | 0 | _ => { self.msg_id }, |
44 | | }; |
45 | 291k | use_msg_id = x; |
46 | | }, |
47 | 162k | 1 => { |
48 | 162k | SCLogDebug!("FIXME TODO"); |
49 | 162k | //let (_, cmd1) = vercmd.get_smb1_cmd(); |
50 | 162k | //if cmd1 != SMB1_COMMAND_IOCTL { |
51 | 162k | use_msg_id = 0; |
52 | 162k | //} |
53 | 162k | }, |
54 | 0 | _ => { }, |
55 | | } |
56 | 453k | SMBCommonHdr { |
57 | 453k | ssn_id: self.ssn_id, |
58 | 453k | tree_id: self.tree_id, |
59 | 453k | msg_id: use_msg_id, |
60 | 453k | rec_type: SMBHDR_TYPE_DCERPCTX, |
61 | 453k | } |
62 | 453k | } |
63 | | } |
64 | | |
65 | | #[derive(Default, Debug)] |
66 | | pub struct DCERPCIface { |
67 | | pub uuid: Vec<u8>, |
68 | | pub ver: u16, |
69 | | pub ver_min: u16, |
70 | | pub ack_result: u16, |
71 | | pub ack_reason: u16, |
72 | | pub acked: bool, |
73 | | pub context_id: u16, |
74 | | } |
75 | | |
76 | | impl DCERPCIface { |
77 | 15.5k | pub fn new(uuid: Vec<u8>, ver: u16, ver_min: u16) -> Self { |
78 | 15.5k | Self { |
79 | 15.5k | uuid, |
80 | 15.5k | ver, |
81 | 15.5k | ver_min, |
82 | 15.5k | ..Default::default() |
83 | 15.5k | } |
84 | 15.5k | } |
85 | | } |
86 | | |
87 | | #[derive(Default, Debug)] |
88 | | pub struct SMBTransactionDCERPC { |
89 | | pub opnum: u16, |
90 | | pub context_id: u16, |
91 | | pub req_cmd: u8, |
92 | | pub req_set: bool, |
93 | | pub res_cmd: u8, |
94 | | pub res_set: bool, |
95 | | pub call_id: u32, |
96 | | pub frag_cnt_ts: u16, |
97 | | pub frag_cnt_tc: u16, |
98 | | pub stub_data_ts: Vec<u8>, |
99 | | pub stub_data_tc: Vec<u8>, |
100 | | } |
101 | | |
102 | | impl SMBTransactionDCERPC { |
103 | 45.6k | fn new_request(req: u8, call_id: u32) -> Self { |
104 | 45.6k | return Self { |
105 | 45.6k | opnum: 0, |
106 | 45.6k | context_id: 0, |
107 | 45.6k | req_cmd: req, |
108 | 45.6k | req_set: true, |
109 | 45.6k | call_id, |
110 | 45.6k | ..Default::default() |
111 | 45.6k | } |
112 | 45.6k | } |
113 | 4.00k | fn new_response(call_id: u32) -> Self { |
114 | 4.00k | return Self { |
115 | 4.00k | call_id, |
116 | 4.00k | ..Default::default() |
117 | 4.00k | }; |
118 | 4.00k | } |
119 | 7.61k | pub fn set_result(&mut self, res: u8) { |
120 | 7.61k | self.res_set = true; |
121 | 7.61k | self.res_cmd = res; |
122 | 7.61k | } |
123 | | } |
124 | | |
125 | | impl SMBState { |
126 | 45.6k | fn new_dcerpc_tx(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, cmd: u8, call_id: u32) |
127 | 45.6k | -> &mut SMBTransaction |
128 | | { |
129 | 45.6k | let mut tx = self.new_tx(); |
130 | 45.6k | tx.hdr = hdr; |
131 | 45.6k | tx.vercmd = vercmd; |
132 | 45.6k | tx.type_data = Some(SMBTransactionTypeData::DCERPC( |
133 | 45.6k | SMBTransactionDCERPC::new_request(cmd, call_id))); |
134 | | |
135 | | SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr); |
136 | 45.6k | self.transactions.push_back(tx); |
137 | 45.6k | let tx_ref = self.transactions.back_mut(); |
138 | 45.6k | return tx_ref.unwrap(); |
139 | 45.6k | } |
140 | | |
141 | 4.00k | fn new_dcerpc_tx_for_response(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, call_id: u32) |
142 | 4.00k | -> &mut SMBTransaction |
143 | | { |
144 | 4.00k | let mut tx = self.new_tx(); |
145 | 4.00k | tx.hdr = hdr; |
146 | 4.00k | tx.vercmd = vercmd; |
147 | 4.00k | tx.type_data = Some(SMBTransactionTypeData::DCERPC( |
148 | 4.00k | SMBTransactionDCERPC::new_response(call_id))); |
149 | | |
150 | | SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr); |
151 | 4.00k | self.transactions.push_back(tx); |
152 | 4.00k | let tx_ref = self.transactions.back_mut(); |
153 | 4.00k | return tx_ref.unwrap(); |
154 | 4.00k | } |
155 | | |
156 | 21.6k | fn get_dcerpc_tx(&mut self, hdr: &SMBCommonHdr, vercmd: &SMBVerCmdStat, call_id: u32) |
157 | 21.6k | -> Option<&mut SMBTransaction> |
158 | | { |
159 | 21.6k | let dce_hdr = hdr.to_dcerpc(vercmd); |
160 | | |
161 | | SCLogDebug!("looking for {:?}", dce_hdr); |
162 | 439k | for tx in &mut self.transactions { |
163 | 431k | let found = dce_hdr.compare(&tx.hdr.to_dcerpc(vercmd)) && |
164 | 44.2k | match tx.type_data { |
165 | 41.3k | Some(SMBTransactionTypeData::DCERPC(ref x)) => { |
166 | 41.3k | x.call_id == call_id |
167 | | }, |
168 | 107k | _ => { false }, |
169 | | }; |
170 | 431k | if found { |
171 | 13.4k | tx.tx_data.updated_tc = true; |
172 | 13.4k | tx.tx_data.updated_ts = true; |
173 | 13.4k | return Some(tx); |
174 | 418k | } |
175 | | } |
176 | 8.26k | return None; |
177 | 21.6k | } |
178 | | } |
179 | | |
180 | | /// Handle DCERPC request data from a WRITE, IOCTL or TRANS record. |
181 | | /// return bool indicating whether an tx has been created/updated. |
182 | | /// |
183 | 70.0k | pub fn smb_write_dcerpc_record(state: &mut SMBState, |
184 | 70.0k | vercmd: SMBVerCmdStat, |
185 | 70.0k | hdr: SMBCommonHdr, |
186 | 70.0k | data: &[u8]) -> bool |
187 | | { |
188 | 70.0k | let mut bind_ifaces : Option<Vec<DCERPCIface>> = None; |
189 | 70.0k | let mut is_bind = false; |
190 | | |
191 | | SCLogDebug!("called for {} bytes of data", data.len()); |
192 | 70.0k | match parse_dcerpc_record(data) { |
193 | 64.9k | Ok((_, dcer)) => { |
194 | | SCLogDebug!("DCERPC: version {}.{} write data {} => {:?}", |
195 | | dcer.version_major, dcer.version_minor, dcer.data.len(), dcer); |
196 | | |
197 | | /* if this isn't the first frag, simply update the existing |
198 | | * tx with the additional stub data */ |
199 | 64.9k | if dcer.packet_type == DCERPC_TYPE_REQUEST && !dcer.first_frag { |
200 | | SCLogDebug!("NOT the first frag. Need to find an existing TX"); |
201 | 19.2k | match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) { |
202 | 8.56k | Ok((_, recr)) => { |
203 | 8.56k | let found = match state.get_dcerpc_tx(&hdr, &vercmd, dcer.call_id) { |
204 | 5.47k | Some(tx) => { |
205 | | SCLogDebug!("previous CMD {} found at tx {} => {:?}", |
206 | | dcer.packet_type, tx.id, tx); |
207 | 5.47k | if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { |
208 | 5.47k | SCLogDebug!("additional frag of size {}", recr.data.len()); |
209 | 5.47k | tdn.stub_data_ts.extend_from_slice(recr.data); |
210 | 5.47k | tdn.frag_cnt_ts += 1; |
211 | 5.47k | SCLogDebug!("stub_data now {}", tdn.stub_data_ts.len()); |
212 | 5.47k | } |
213 | 5.47k | if dcer.last_frag { |
214 | 2.52k | SCLogDebug!("last frag set, so request side of DCERPC closed"); |
215 | 2.52k | tx.request_done = true; |
216 | 2.95k | } else { |
217 | 2.95k | SCLogDebug!("NOT last frag, so request side of DCERPC remains open"); |
218 | 2.95k | } |
219 | 5.47k | true |
220 | | }, |
221 | | None => { |
222 | | SCLogDebug!("NO previous CMD {} found", dcer.packet_type); |
223 | 3.09k | false |
224 | | }, |
225 | | }; |
226 | 8.56k | return found; |
227 | | }, |
228 | | _ => { |
229 | 10.7k | state.set_event(SMBEvent::MalformedData); |
230 | 10.7k | return false; |
231 | | }, |
232 | | } |
233 | 45.6k | } |
234 | | |
235 | 45.6k | let tx = state.new_dcerpc_tx(hdr, vercmd, dcer.packet_type, dcer.call_id); |
236 | 45.6k | match dcer.packet_type { |
237 | | DCERPC_TYPE_REQUEST => { |
238 | 11.5k | match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) { |
239 | 7.08k | Ok((_, recr)) => { |
240 | | SCLogDebug!("DCERPC: REQUEST {:?}", recr); |
241 | 7.08k | if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { |
242 | 7.08k | SCLogDebug!("first frag size {}", recr.data.len()); |
243 | 7.08k | tdn.stub_data_ts.extend_from_slice(recr.data); |
244 | 7.08k | tdn.opnum = recr.opnum; |
245 | 7.08k | tdn.context_id = recr.context_id; |
246 | 7.08k | tdn.frag_cnt_ts += 1; |
247 | 7.08k | SCLogDebug!("DCERPC: REQUEST opnum {} stub data len {}", |
248 | 7.08k | tdn.opnum, tdn.stub_data_ts.len()); |
249 | 7.08k | } |
250 | 7.08k | if dcer.last_frag { |
251 | 2.07k | tx.request_done = true; |
252 | 5.01k | } else { |
253 | 5.01k | SCLogDebug!("NOT last frag, so request side of DCERPC remains open"); |
254 | 5.01k | } |
255 | | }, |
256 | 4.50k | _ => { |
257 | 4.50k | tx.set_event(SMBEvent::MalformedData); |
258 | 4.50k | tx.request_done = true; |
259 | 4.50k | }, |
260 | | } |
261 | | }, |
262 | | DCERPC_TYPE_BIND => { |
263 | 30.3k | let brec = if dcer.little_endian { |
264 | 18.7k | parse_dcerpc_bind_record(dcer.data) |
265 | | } else { |
266 | 11.5k | parse_dcerpc_bind_record_big(dcer.data) |
267 | | }; |
268 | 30.3k | match brec { |
269 | 3.02k | Ok((_, bindr)) => { |
270 | 3.02k | is_bind = true; |
271 | | SCLogDebug!("SMB DCERPC {:?} BIND {:?}", dcer, bindr); |
272 | | |
273 | 3.02k | if !bindr.ifaces.is_empty() { |
274 | 1.49k | let mut ifaces: Vec<DCERPCIface> = Vec::new(); |
275 | 17.0k | for i in bindr.ifaces { |
276 | 15.5k | let x = if dcer.little_endian { |
277 | 11.4k | vec![i.iface[3], i.iface[2], i.iface[1], i.iface[0], |
278 | 11.4k | i.iface[5], i.iface[4], i.iface[7], i.iface[6], |
279 | 11.4k | i.iface[8], i.iface[9], i.iface[10], i.iface[11], |
280 | 11.4k | i.iface[12], i.iface[13], i.iface[14], i.iface[15]] |
281 | | } else { |
282 | 4.12k | i.iface.to_vec() |
283 | | }; |
284 | 15.5k | let uuid_str = uuid::Uuid::from_slice(&x.clone()); |
285 | 15.5k | let _uuid_str = uuid_str.map(|uuid_str| uuid_str.to_hyphenated().to_string()).unwrap(); |
286 | 15.5k | let d = DCERPCIface::new(x,i.ver,i.ver_min); |
287 | | SCLogDebug!("UUID {} version {}/{} bytes {:?}", |
288 | | _uuid_str, |
289 | | i.ver, i.ver_min,i.iface); |
290 | 15.5k | ifaces.push(d); |
291 | | } |
292 | 1.49k | bind_ifaces = Some(ifaces); |
293 | 1.53k | } |
294 | | }, |
295 | 27.2k | _ => { |
296 | 27.2k | tx.set_event(SMBEvent::MalformedData); |
297 | 27.2k | }, |
298 | | } |
299 | 30.3k | tx.request_done = true; |
300 | | } |
301 | 2.42k | 21..=255 => { |
302 | 2.42k | tx.set_event(SMBEvent::MalformedData); |
303 | 2.42k | tx.request_done = true; |
304 | 2.42k | }, |
305 | 1.31k | _ => { |
306 | 1.31k | // valid type w/o special processing |
307 | 1.31k | tx.request_done = true; |
308 | 1.31k | }, |
309 | | } |
310 | | }, |
311 | 5.09k | _ => { |
312 | 5.09k | state.set_event(SMBEvent::MalformedData); |
313 | 5.09k | }, |
314 | | } |
315 | | |
316 | 50.7k | if is_bind { |
317 | 3.02k | // We have to write here the interfaces |
318 | 3.02k | // rather than in the BIND block |
319 | 3.02k | // due to borrow issues with the tx mutable reference |
320 | 3.02k | // that is part of the state |
321 | 3.02k | state.dcerpc_ifaces = bind_ifaces; // TODO store per ssn |
322 | 47.6k | } |
323 | 50.7k | return true; |
324 | 70.0k | } |
325 | | |
326 | | /// Update TX for bind ack. Needs to update both tx and state. |
327 | | /// |
328 | 5.78k | fn smb_dcerpc_response_bindack( |
329 | 5.78k | state: &mut SMBState, |
330 | 5.78k | vercmd: SMBVerCmdStat, |
331 | 5.78k | hdr: SMBCommonHdr, |
332 | 5.78k | dcer: &DceRpcRecord, |
333 | 5.78k | ntstatus: u32) |
334 | | { |
335 | 5.78k | match parse_dcerpc_bindack_record(dcer.data) { |
336 | 2.24k | Ok((_, bindackr)) => { |
337 | | SCLogDebug!("SMB READ BINDACK {:?}", bindackr); |
338 | | |
339 | 2.24k | let found = match state.get_dcerpc_tx(&hdr, &vercmd, dcer.call_id) { |
340 | 1.08k | Some(tx) => { |
341 | 1.08k | if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { |
342 | 1.08k | tdn.set_result(DCERPC_TYPE_BINDACK); |
343 | 1.08k | } |
344 | 1.08k | tx.vercmd.set_ntstatus(ntstatus); |
345 | 1.08k | tx.response_done = true; |
346 | 1.08k | true |
347 | | }, |
348 | 1.15k | None => false, |
349 | | }; |
350 | 2.24k | if found { |
351 | 1.08k | if let Some(ref mut ifaces) = state.dcerpc_ifaces { |
352 | 2.84k | for (i, r) in bindackr.results.into_iter().enumerate() { |
353 | 2.84k | if i >= ifaces.len() { |
354 | | // TODO set event: more acks that requests |
355 | 199 | break; |
356 | 2.64k | } |
357 | 2.64k | ifaces[i].ack_result = r.ack_result; |
358 | 2.64k | ifaces[i].acked = true; |
359 | | } |
360 | 220 | } |
361 | 1.15k | } |
362 | | }, |
363 | 3.53k | _ => { |
364 | 3.53k | state.set_event(SMBEvent::MalformedData); |
365 | 3.53k | }, |
366 | | } |
367 | 5.78k | } |
368 | | |
369 | 2.48k | fn smb_read_dcerpc_record_error(state: &mut SMBState, |
370 | 2.48k | hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, ntstatus: u32) |
371 | 2.48k | -> bool |
372 | | { |
373 | 2.48k | let ver = vercmd.get_version(); |
374 | 2.48k | let cmd = if ver == 2 { |
375 | 2.06k | let (_, c) = vercmd.get_smb2_cmd(); |
376 | 2.06k | c |
377 | | } else { |
378 | 423 | let (_, c) = vercmd.get_smb1_cmd(); |
379 | 423 | c as u16 |
380 | | }; |
381 | | |
382 | 2.48k | let found = match state.get_generic_tx(ver, cmd, &hdr) { |
383 | 950 | Some(tx) => { |
384 | | SCLogDebug!("found"); |
385 | 950 | tx.set_status(ntstatus, false); |
386 | 950 | tx.response_done = true; |
387 | 950 | true |
388 | | }, |
389 | | None => { |
390 | | SCLogDebug!("NOT found"); |
391 | 1.53k | false |
392 | | }, |
393 | | }; |
394 | 2.48k | return found; |
395 | 2.48k | } |
396 | | |
397 | 10.8k | fn dcerpc_response_handle(tx: &mut SMBTransaction, |
398 | 10.8k | vercmd: SMBVerCmdStat, |
399 | 10.8k | dcer: &DceRpcRecord) |
400 | | { |
401 | 10.8k | let (_, ntstatus) = vercmd.get_ntstatus(); |
402 | 10.8k | match dcer.packet_type { |
403 | | DCERPC_TYPE_RESPONSE => { |
404 | 6.02k | match parse_dcerpc_response_record(dcer.data, dcer.frag_len) { |
405 | 1.68k | Ok((_, respr)) => { |
406 | | SCLogDebug!("SMBv1 READ RESPONSE {:?}", respr); |
407 | 1.68k | if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { |
408 | 1.68k | SCLogDebug!("CMD 11 found at tx {}", tx.id); |
409 | 1.68k | tdn.set_result(DCERPC_TYPE_RESPONSE); |
410 | 1.68k | tdn.stub_data_tc.extend_from_slice(respr.data); |
411 | 1.68k | tdn.frag_cnt_tc += 1; |
412 | 1.68k | } |
413 | 1.68k | tx.vercmd.set_ntstatus(ntstatus); |
414 | 1.68k | tx.response_done = dcer.last_frag; |
415 | | }, |
416 | 4.33k | _ => { |
417 | 4.33k | tx.set_event(SMBEvent::MalformedData); |
418 | 4.33k | }, |
419 | | } |
420 | | }, |
421 | 0 | DCERPC_TYPE_BINDACK => { |
422 | 0 | // handled elsewhere |
423 | 0 | }, |
424 | 2.13k | 21..=255 => { |
425 | 2.13k | if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { |
426 | 2.13k | tdn.set_result(dcer.packet_type); |
427 | 2.13k | } |
428 | 2.13k | tx.vercmd.set_ntstatus(ntstatus); |
429 | 2.13k | tx.response_done = true; |
430 | 2.13k | tx.set_event(SMBEvent::MalformedData); |
431 | | } |
432 | | _ => { // valid type w/o special processing |
433 | 2.70k | if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { |
434 | 2.70k | tdn.set_result(dcer.packet_type); |
435 | 2.70k | } |
436 | 2.70k | tx.vercmd.set_ntstatus(ntstatus); |
437 | 2.70k | tx.response_done = true; |
438 | | }, |
439 | | } |
440 | 10.8k | } |
441 | | |
442 | | /// Handle DCERPC reply record. Called for READ, TRANS, IOCTL |
443 | | /// |
444 | 23.9k | pub fn smb_read_dcerpc_record(state: &mut SMBState, |
445 | 23.9k | vercmd: SMBVerCmdStat, |
446 | 23.9k | hdr: SMBCommonHdr, |
447 | 23.9k | guid: &[u8], |
448 | 23.9k | indata: &[u8]) -> bool |
449 | | { |
450 | 23.9k | let (_, ntstatus) = vercmd.get_ntstatus(); |
451 | | |
452 | 23.9k | if ntstatus != SMB_NTSTATUS_SUCCESS && ntstatus != SMB_NTSTATUS_BUFFER_OVERFLOW { |
453 | 2.48k | return smb_read_dcerpc_record_error(state, hdr, vercmd, ntstatus); |
454 | 21.4k | } |
455 | | |
456 | | SCLogDebug!("lets first see if we have prior data"); |
457 | | // msg_id 0 as this data crosses cmd/reply pairs |
458 | 21.4k | let ehdr = SMBHashKeyHdrGuid::new(SMBCommonHdr::new(SMBHDR_TYPE_TRANS_FRAG, |
459 | 21.4k | hdr.ssn_id, hdr.tree_id, 0_u64), guid.to_vec()); |
460 | 21.4k | let mut prevdata = state.ssnguid2vec_map.remove(&ehdr).unwrap_or_default(); |
461 | | SCLogDebug!("indata {} prevdata {}", indata.len(), prevdata.len()); |
462 | 21.4k | prevdata.extend_from_slice(indata); |
463 | 21.4k | let data = prevdata; |
464 | | |
465 | 21.4k | let mut malformed = false; |
466 | | |
467 | 21.4k | if data.is_empty() { |
468 | | SCLogDebug!("weird: no DCERPC data"); // TODO |
469 | | // TODO set event? |
470 | 464 | return false; |
471 | | |
472 | | } else { |
473 | 20.9k | match parse_dcerpc_record(&data) { |
474 | 19.8k | Ok((_, dcer)) => { |
475 | | SCLogDebug!("DCERPC: version {}.{} read data {} => {:?}", |
476 | | dcer.version_major, dcer.version_minor, dcer.data.len(), dcer); |
477 | | |
478 | 19.8k | if ntstatus == SMB_NTSTATUS_BUFFER_OVERFLOW && data.len() < dcer.frag_len as usize { |
479 | | SCLogDebug!("short record {} < {}: storing partial data in state", |
480 | | data.len(), dcer.frag_len); |
481 | 3.18k | state.ssnguid2vec_map.insert(ehdr, data.to_vec()); |
482 | 3.18k | return true; // TODO review |
483 | 16.6k | } |
484 | | |
485 | 16.6k | if dcer.packet_type == DCERPC_TYPE_BINDACK { |
486 | 5.78k | smb_dcerpc_response_bindack(state, vercmd, hdr, &dcer, ntstatus); |
487 | 5.78k | return true; |
488 | 10.8k | } |
489 | | |
490 | 10.8k | let found = match state.get_dcerpc_tx(&hdr, &vercmd, dcer.call_id) { |
491 | 6.86k | Some(tx) => { |
492 | 6.86k | dcerpc_response_handle(tx, vercmd.clone(), &dcer); |
493 | 6.86k | true |
494 | | }, |
495 | | None => { |
496 | | SCLogDebug!("no tx"); |
497 | 4.00k | false |
498 | | }, |
499 | | }; |
500 | 10.8k | if !found { |
501 | 4.00k | // pick up DCERPC tx even if we missed the request |
502 | 4.00k | let tx = state.new_dcerpc_tx_for_response(hdr, vercmd.clone(), dcer.call_id); |
503 | 4.00k | dcerpc_response_handle(tx, vercmd, &dcer); |
504 | 6.86k | } |
505 | | }, |
506 | 1.14k | _ => { |
507 | 1.14k | malformed = true; |
508 | 1.14k | }, |
509 | | } |
510 | | } |
511 | | |
512 | 12.0k | if malformed { |
513 | 1.14k | state.set_event(SMBEvent::MalformedData); |
514 | 10.8k | } |
515 | | |
516 | 12.0k | return true; |
517 | 23.9k | } |
518 | | |
519 | | /// Try to find out if the input data looks like DCERPC |
520 | 27.5k | pub fn smb_dcerpc_probe(data: &[u8]) -> bool |
521 | | { |
522 | 27.5k | if let Ok((_, recr)) = parse_dcerpc_record(data) { |
523 | | SCLogDebug!("SMB: could be DCERPC {:?}", recr); |
524 | 18.8k | if recr.version_major == 5 && recr.version_minor < 3 && |
525 | 14.3k | recr.frag_len > 0 && recr.packet_type <= 20 |
526 | | { |
527 | | SCLogDebug!("SMB: looks like we have dcerpc"); |
528 | 14.2k | return true; |
529 | 4.60k | } |
530 | 8.77k | } |
531 | 13.3k | return false; |
532 | 27.5k | } |