Coverage Report

Created: 2026-01-16 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}