1mod negotiate;
2mod sessionsetup1;
3mod sessionsetup2;
4mod error;
5
6use std::io::Cursor;
7use std::str::{FromStr};
8
9use asn1_rs::nom::number::complete::{u32};
10use asn1_rs::{Enumerated, FromDer, Oid, OctetString, OidParseError, ToDer};
11use asn1_rs::nom::AsBytes;
12
13use anyhow::{anyhow, Result};
14use binrw::{BinRead, BinReaderExt, BinWrite};
15use serde::{Deserialize, Serialize, };
16use tokio::io::{AsyncReadExt, AsyncWriteExt};
17use tokio::net::TcpStream;
18use ntlmclient;
19use ntlmclient::{Flags, Message, TargetInfoType};
20use rasn::{AsnType, Decode, Encode};
21use crate::error::{SmbError, SmbResult};
22use crate::negotiate::{NegotiateProtoResponse, NegotiateProtoRequset};
23
24pub struct SmbOptions<'a> {
27 pub Host : &'a str,
28 pub Port : &'a str,
29 pub User: &'a str,
30 pub Domain: &'a str,
31 pub Workstation: &'a str,
32 pub Password: &'a str,
33 pub timeout: u16,
34 sesionSetup1RespHeader: Header,
35 sessionSetup1RespSecProvider: Vec<u8>,
36
37
38}
39pub struct SmbInfo {
41 pub isAuthenticated: bool,
42 pub StatusCode: String
43}
44
45
46
47
48
49
50
51
52
53
54impl SmbOptions<'_> {
55 pub fn new() -> Self {
56 let s = SmbOptions {
57 Host: "",
58 Port: "",
59 User: "",
60 Domain: "",
61 Workstation: "",
62 Password: "",
63 timeout: 0,
64 sesionSetup1RespHeader: Header::new(),
65 sessionSetup1RespSecProvider: vec![],
66 };
67 s
68 }
69}
70
71
72
73
74
75
76impl SmbOptions<'_> {
78 pub async fn Conn(&mut self) -> SmbResult<SmbInfo> {
79
80
81 let target = format!("{}:{}", self.Host, self.Port);
82 let t = tokio::time::Duration::from_secs(self.timeout as u64);
83
84 let mut stream = match tokio::time::timeout(t, TcpStream::connect(target.clone())).await {
86 Ok(r) => {
87 match r {
88 Ok(r) => r,
89 Err(e) => return Err(SmbError::from(anyhow!(e))),
90 }
91 },
92 Err(e) => return Err(SmbError::from(anyhow!(e))),
93
94 };
95 NegotiateProtoRequset(&mut stream).await?;
97 let negoprotoResp = NegotiateProtoResponse(&mut stream).await?;
99
100
101 self.SessionSetupRequset1(&mut stream, negoprotoResp).await?;
103
104
105 self.SessionSetUpResponse1(&mut stream).await?;
107
108 self.SessionSetupRequset2(&mut stream).await?;
110
111 let mut buffer:Vec<u8> = vec![0;68];
116 let _ = stream.read_exact(&mut buffer).await?;
117 let mut cur = Cursor::new(buffer[4..].to_vec());
118
119 let f:Header = cur.read_le()?;
120 let login_result = u32::from_le_bytes(f.status.to_ne_bytes());
121
122 stream.shutdown().await?;
123
124 let r = SmbInfo{
125 isAuthenticated: IsAuthenticated(login_result),
126 StatusCode: format!("{:#010x}", login_result),
127 };
128
129
130 Ok(r)
131 }
132}
133
134
135
136
137
138
139
140
141
142const DIALECT_SMB_2_1: i32 = 0x0210;
143
144#[derive(BinRead, BinWrite, Debug)]
145#[derive(Serialize, Deserialize, Copy, Clone)]
146struct Header {
147 protocol_id: [u8; 4],
148 structure_size: u16,
149 credit_charge: u16,
150 status: u32,
151 command: u16,
152 credits: u16,
153 flags: u32,
154 next_command: u32,
155 message_id: u64,
156 reserved: u32,
157 tree_id: u32,
158 session_id: u64,
159 signature: [u8; 16],
160}
161
162#[derive(BinRead, BinWrite, Debug)]
163struct NegotiateReq {
164 header: Header,
165 StructureSize:u16,
166 DialectCount:u16,
167 SecurityMode:u16,
168 Reserved:u16,
169 Capabilities: u32,
170 ClientGuid:[u8; 16],
171 ClientStartTime:u64,
172 Dialects:[u16;1],
173}
174
175
176
177#[derive(Copy, Clone)]
178enum command {
179 CommandNegotiate = 0,
180 CommandSessionSetup = 1,
181 CommandLogoff = 2,
182 CommandTreeConnect = 3,
183 CommandTreeDisconnect = 4,
184 CommandCreate = 5,
185 CommandClose = 6,
186 CommandFlush = 7,
187 CommandRead = 8,
188 CommandWrite = 9,
189 CommandLock = 10,
190 CommandIOCtl = 11,
191 CommandCancel = 12,
192 CommandEcho = 13,
193 CommandQueryDirectory = 14,
194 CommandChangeNotify = 15,
195 CommandQueryInfo = 16,
196 CommandSetInfo = 17,
197 CommandOplockBreak = 18
198}
199
200#[derive(Copy, Clone)]
201enum SecMode {
202 SecurityModeSigningEnabled = 1,
203 SecurityModeSigningRequired = 2
204}
205
206#[derive(Copy, Clone)]
207enum NegotiateFlags {
208 FlgNegUnicode = 1 << 0 as u32,
209 FlgNegOEM = 1 << 1,
210 FlgNegRequestTarget = 1 << 2,
211 FlgNegReserved10 = 1 << 3,
212 FlgNegSign = 1 << 4,
213 FlgNegSeal = 1 << 5,
214 FlgNegDatagram = 1 << 6,
215 FlgNegLmKey = 1 << 7,
216 FlgNegReserved9 = 1 << 8,
217 FlgNegNtLm = 1 << 9,
218 FlgNegReserved8 = 1 << 10,
219 FlgNegAnonymous = 1 << 11,
220 FlgNegOEMDomainSupplied = 1 << 12,
221 FlgNegOEMWorkstationSupplied = 1 << 13,
222 FlgNegReserved7 = 1 << 14,
223 FlgNegAlwaysSign = 1 << 15,
224 FlgNegTargetTypeDomain = 1 << 16,
225 FlgNegTargetTypeServer = 1 << 17,
226 FlgNegReserved6 = 1 << 18,
227 FlgNegExtendedSessionSecurity = 1 << 19,
228 FlgNegIdentify = 1 << 20,
229 FlgNegReserved5 = 1 << 21,
230 FlgNegRequestNonNtSessionKey = 1 << 22,
231 FlgNegTargetInfo = 1 << 23,
232 FlgNegReserved4 = 1 << 24,
233 FlgNegVersion = 1 << 25,
234 FlgNegReserved3 = 1 << 26,
235 FlgNegReserved2 = 1 << 27,
236 FlgNegReserved1 = 1 << 28,
237 FlgNeg128 = 1 << 29,
238 FlgNegKeyExch = 1 << 30,
239 FlgNeg56 = 1 << 31,
240}
241enum TagEnum {
242 TypeEnum = 0x0a,
243 TypeBitStr = 0x03,
244 TypeOctStr = 0x04,
245 TypeSeq = 0x30,
246 TypeOid = 0x06,
247}
248
249enum NT_STATUS_Enum {
250 STATUS_SUCCESS = 0,
251 STATUS_LOGON_FAILURE = 3221225581
252
253}
254
255
256
257
258
259struct AuthMsg {
261 header: [u8; 8],
262 _type: [u8; 4],
263 lmResp: Vec<u8>,
264 ntlmResp: Vec<u8>,
265 domain: String,
266 user: String,
267 workstation: String,
268 flags: u32,
269 lmRespLen: [u8; 2],
270 lmRespMaxLen: [u8; 2],
271 lmRespOffset: [u8; 4],
272
273
274
275
276}
277
278
279
280
281
282
283fn string_to_utf16_bytes(input: &str) -> Vec<u8> {
284 let utf16_encoded: Vec<u16> = input.encode_utf16().collect();
285 let mut utf16_bytes = Vec::new();
286 for &code_unit in &utf16_encoded {
287 utf16_bytes.push((code_unit & 0xFF) as u8);
288 utf16_bytes.push((code_unit >> 8) as u8);
289 }
290
291 utf16_bytes
292}
293
294
295#[derive(Serialize, Deserialize, Debug)]
298struct negotiate_Header {
299 signature: [u8;8],
300 message_type: u32
301}
302#[derive(Serialize, Deserialize, Debug)]
303struct Negotiate {
304 negotiate_header: negotiate_Header,
305 NegotiateFlags: u32,
306 DomainNameLen : u16,
307 DomainNameMaxLen: u16,
308 DomainNameBufferOffset: u32,
309 WorkstationLen: u16,
310 WorkstationMaxLen: u16,
311 WorkstationBufferOffset: u32,
312 DomainName: Vec<u8>,
313 Workstation : Vec<u8>
314}
315
316
317#[derive(Serialize, Deserialize, Debug)]
318struct NegTokenInit {
319 Oid: Box<[u8]>,
320 Data: Negotiate_init_data
321}
322
323
324#[derive(Serialize, Deserialize, Debug)]
325struct Negotiate_init_data {
326 MechTypes: Vec<u8>,
327 MechToken: Vec<u8>
328}
329
330
331#[derive(BinRead, BinWrite, Debug)]
332#[derive(Serialize, Deserialize)]
333struct SessionSetup1Req {
334 Header: Header,
335 StructureSize : u16,
336 Flags : u8,
337 SecurityMode : u8,
338 Capabilities : u32,
339 Channel : u32,
340 SecurityBufferOffset : u16,
341 SecurityBufferLength : u16,
342 PreviousSessionID : u64,
343}
344
345
346
347
348
349
350
351impl Header {
352 pub fn new() -> Header {
353 let protocol_smb2: [u8; 4] = [0xFE, 0x53, 0x4D, 0x42];
354 let arr: [u8; 16] = [0; 16];
355 let qq = Header {
356 protocol_id: protocol_smb2,
357 structure_size: 64,
358 credit_charge: 0,
359 status: 0,
360 command: 0,
361 credits: 0,
362 flags: 0,
363 next_command: 0,
364 message_id: 0,
365 reserved: 0,
366 tree_id: 0,
367 session_id: 0,
368 signature: arr,
369 };
370 qq
371 }
372}
373
374
375
376pub fn IsAuthenticated(code: u32) -> bool {
378 match code {
379 0 => {
380 true
382 },
383 3221225581 => {
384 false
386 },
387 _ => {
388 false
390 },
391 }
392}
393