1#[cfg(windows)]
104mod encoding_windows;
105
106#[cfg(not(windows))]
107mod encoding_utf8;
108
109
110use std::fmt;
111
112use bitflags::bitflags;
113use chrono::{NaiveDate, Utc};
114use cipher::{BlockEncrypt, KeyInit};
115use cipher::generic_array::GenericArray;
116use cipher::generic_array::typenum::U8;
117use des::Des;
118use digest::Digest;
119use hmac::{Hmac, Mac};
120use md4::Md4;
121use md5::Md5;
122use rand::Rng;
123use rand::rngs::OsRng;
124
125#[cfg(windows)]
126use crate::encoding_windows::{ansi_string_to_rust, rust_string_to_ansi};
127
128#[cfg(not(windows))]
129use crate::encoding_utf8::{ansi_string_to_rust, rust_string_to_ansi};
130
131
132const NTLMSSP_MAGIC: [u8; 8] = *b"NTLMSSP\0";
134
135
136#[derive(Clone, Debug, Eq, Hash, PartialEq)]
138pub struct Credentials {
139 pub username: String,
141
142 pub password: String,
144
145 pub domain: String,
150}
151
152#[derive(Clone, Debug, Eq, Hash, PartialEq)]
154pub struct ChallengeResponse {
155 pub lm_response: Vec<u8>,
157
158 pub ntlm_response: Vec<u8>,
160
161 pub session_key: Vec<u8>,
163}
164
165
166bitflags! {
167 #[derive(Clone, Copy, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)]
169 pub struct Flags: u32 {
170 const NEGOTIATE_UNICODE = 0x0000_0001;
171 const NEGOTIATE_OEM = 0x0000_0002;
172 const REQUEST_TARGET = 0x0000_0004;
173 const UNKNOWN_8 = 0x0000_0008;
174 const NEGOTIATE_SIGN = 0x0000_0010;
175 const NEGOTIATE_SEAL = 0x0000_0020;
176 const NEGOTIATE_DATAGRAM = 0x0000_0040;
177 const NEGOTIATE_LANMAN_KEY = 0x0000_0080;
178 const NEGOTIATE_NETWARE = 0x0000_0100;
179 const NEGOTIATE_NTLM = 0x0000_0200;
180 const UNKNOWN_400 = 0x0000_0400;
181 const NEGOTIATE_ANONYMOUS = 0x0000_0800;
182 const NEGOTIATE_DOMAIN_SUPPLIED = 0x0000_1000;
183 const NEGOTIATE_WORKSTATION_SUPPLIED = 0x0000_2000;
184 const NEGOTIATE_LOCAL_CALL = 0x0000_4000;
185 const NEGOTIATE_ALWAYS_SIGN = 0x0000_8000;
186 const TARGET_TYPE_DOMAIN = 0x0001_0000;
187 const TARGET_TYPE_SERVER = 0x0002_0000;
188 const TARGET_TYPE_SHARE = 0x0004_0000;
189 const NEGOTIATE_NTLM2_KEY = 0x0008_0000;
190 const REQUEST_INIT_RESPONSE = 0x0010_0000;
191 const REQUEST_ACCEPT_RESPONSE = 0x0020_0000;
192 const REQUEST_NON_NT_SESSION_KEY = 0x0040_0000;
193 const NEGOTIATE_TARGET_INFO = 0x0080_0000;
194 const UNKNOWN_1000000 = 0x0100_0000;
195 const NEGOTIATE_VERSION = 0x0200_0000;
196 const UNKNOWN_4000000 = 0x0400_0000;
197 const UNKNOWN_8000000 = 0x0800_0000;
198 const UNKNOWN_10000000 = 0x1000_0000;
199 const NEGOTIATE_128BIT = 0x2000_0000;
200 const NEGOTIATE_KEY_EXCHANGE = 0x4000_0000;
201 const NEGOTIATE_56BIT = 0x8000_0000;
202 }
203}
204
205
206#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
208pub enum ParsingError {
209 ShortHeader { expected_min_len: usize, obtained_len: usize },
211
212 MagicMismatch { expected: [u8; 8], obtained: Vec<u8> },
214
215 ItemLengthMismatch { expected: usize, obtained: usize },
217
218 ItemMinLengthMismatch { expected_at_least: usize, obtained: usize },
220
221 ItemLengthNotDivisible { expected_divisor: usize, obtained_length: usize },
223
224 InvalidOemEncoding { value: Vec<u8> },
226
227 InvalidUtf16 { value: Vec<u16> },
229
230 OffsetTooLargeIsize,
232
233 LengthTooLargeIsize,
235
236 StartOutOfRange { start: isize, length: usize },
238
239 EndOutOfRange { end: isize, length: usize },
241
242 NeitherUnicodeNorOem,
244}
245impl fmt::Display for ParsingError {
246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247 match self {
248 Self::ShortHeader { expected_min_len, obtained_len }
249 => write!(f, "header too short (expected at least {} bytes, obtained {})", expected_min_len, obtained_len),
250 Self::MagicMismatch { expected, obtained }
251 => write!(f, "mismatched magic (expected {:?}, obtained {:?})", expected, obtained),
252 Self::ItemLengthMismatch { expected, obtained }
253 => write!(f, "insufficient length for an internal item (expected {:?}, obtained {:?})", expected, obtained),
254 Self::ItemMinLengthMismatch { expected_at_least, obtained }
255 => write!(f, "insufficient minimum length for an internal item (expected at least {:?}, obtained {:?})", expected_at_least, obtained),
256 Self::ItemLengthNotDivisible { expected_divisor, obtained_length }
257 => write!(f, "item length {} not divisible by {}", obtained_length, expected_divisor),
258 Self::InvalidOemEncoding { value }
259 => write!(f, "failed to decode value with the current OEM encoding: {:?}", value),
260 Self::InvalidUtf16{ value }
261 => write!(f, "failed to decode value as UTF-16: {:?}", value),
262 Self::OffsetTooLargeIsize
263 => write!(f, "the offset value is too large for the isize type"),
264 Self::LengthTooLargeIsize
265 => write!(f, "the length value is too large for the isize type"),
266 Self::StartOutOfRange { start, length }
267 => write!(f, "start ({}) out of range (slice has {} items)", start, length),
268 Self::EndOutOfRange { end, length }
269 => write!(f, "end ({}) out of range (slice has {} items)", end, length),
270 Self::NeitherUnicodeNorOem
271 => write!(f, "neither Unicode nor OEM encoding was selected"),
272 }
273 }
274}
275impl std::error::Error for ParsingError {
276}
277
278#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
280pub enum StoringError {
281 NonOemEncodable { string: String },
283
284 NeitherUnicodeNorOem,
286}
287impl fmt::Display for StoringError {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 match self {
290 Self::NonOemEncodable { string }
291 => write!(f, "failed to encode {:?} using OEM encoding", string),
292 Self::NeitherUnicodeNorOem
293 => write!(f, "neither Unicode nor OEM encoding was selected"),
294 }
295 }
296}
297impl std::error::Error for StoringError {
298}
299
300#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
302pub enum Message {
303 Negotiate(NegotiateMessage),
304 Challenge(ChallengeMessage),
305 Authenticate(AuthenticateMessage),
306 Other(u32, Vec<u8>),
307}
308impl Message {
309 pub fn message_number(&self) -> u32 {
311 match self {
312 Self::Negotiate(_) => 0x0000_0001,
313 Self::Challenge(_) => 0x0000_0002,
314 Self::Authenticate(_) => 0x0000_0003,
315 Self::Other(t, _data) => *t,
316 }
317 }
318}
319
320#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
322pub struct OsVersion {
323 pub major_version: u8,
324 pub minor_version: u8,
325 pub build_number: u16,
326 pub reserved: [u8; 3],
327 pub ntlm_revision: u8,
328}
329impl Default for OsVersion {
330 fn default() -> Self {
331 Self {
332 major_version: 0,
333 minor_version: 0,
334 build_number: 0,
335 reserved: [0, 0, 0],
336 ntlm_revision: 0,
337 }
338 }
339}
340
341#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
346pub struct NegotiateMessage {
347 pub flags: Flags,
349
350 pub supplied_domain: String,
352
353 pub supplied_workstation: String,
355
356 pub os_version: OsVersion,
358}
359
360#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
365pub struct ChallengeMessage {
366 pub target_name: String,
368
369 pub flags: Flags,
371
372 pub challenge: [u8; 8],
374
375 pub context: (u32, u32),
377
378 pub target_information: Vec<TargetInfoEntry>,
380
381 pub os_version: OsVersion,
383}
384
385#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
390pub struct AuthenticateMessage {
391 pub lm_response: Vec<u8>,
392 pub ntlm_response: Vec<u8>,
393 pub domain_name: String,
394 pub user_name: String,
395 pub workstation_name: String,
396 pub session_key: Vec<u8>,
397 pub flags: Flags,
398 pub os_version: OsVersion,
399}
400
401#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
403pub struct SecurityBuffer {
404 pub length: u16,
405 pub capacity: u16,
406 pub offset: u32,
407}
408
409#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
411pub enum TargetInfoType {
412 Terminator,
413 NtServer,
414 NtDomain,
415 DnsDomain,
416 DnsServer,
417 DnsForest,
418 Flags,
419 Timestamp,
420 SingleHost,
421 TargetName,
422 ChannelBindings,
423 Unknown(u16),
424}
425impl From<TargetInfoType> for u16 {
426 fn from(t: TargetInfoType) -> Self {
427 match t {
428 TargetInfoType::Terminator => 0x0000,
429 TargetInfoType::NtServer => 0x0001,
430 TargetInfoType::NtDomain => 0x0002,
431 TargetInfoType::DnsServer => 0x0003,
432 TargetInfoType::DnsDomain => 0x0004,
433 TargetInfoType::DnsForest => 0x0005,
434 TargetInfoType::Flags => 0x0006,
435 TargetInfoType::Timestamp => 0x0007,
436 TargetInfoType::SingleHost => 0x0008,
437 TargetInfoType::TargetName => 0x0009,
438 TargetInfoType::ChannelBindings => 0x000A,
439 TargetInfoType::Unknown(w) => w,
440 }
441 }
442}
443impl From<u16> for TargetInfoType {
444 fn from(w: u16) -> Self {
445 match w {
446 0x0000 => TargetInfoType::Terminator,
447 0x0001 => TargetInfoType::NtServer,
448 0x0002 => TargetInfoType::NtDomain,
449 0x0003 => TargetInfoType::DnsServer,
450 0x0004 => TargetInfoType::DnsDomain,
451 0x0005 => TargetInfoType::DnsForest,
452 0x0006 => TargetInfoType::Flags,
453 0x0007 => TargetInfoType::Timestamp,
454 0x0008 => TargetInfoType::SingleHost,
455 0x0009 => TargetInfoType::TargetName,
456 0x000A => TargetInfoType::ChannelBindings,
457 other => TargetInfoType::Unknown(other),
458 }
459 }
460}
461
462#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
464pub struct TargetInfoEntry {
465 pub entry_type: TargetInfoType,
466 pub data: Vec<u8>,
467}
468
469
470fn append_sec_buffer(message_bytes: &mut Vec<u8>, data_block: &mut Vec<u8>, sec_buffer_offset: &mut u32, data: &[u8]) {
480 data_block.extend_from_slice(data);
482
483 let mut sb = SecurityBuffer::for_slice(data);
485 sb.offset = *sec_buffer_offset;
486
487 message_bytes.extend_from_slice(&sb.to_bytes());
489
490 *sec_buffer_offset += u32::from(sb.length);
492}
493
494fn append_sec_buffer_string(packet_bytes: &mut Vec<u8>, data_block: &mut Vec<u8>, sec_buffer_offset: &mut u32, flags: Flags, data: &str) -> Result<(), StoringError> {
499 let bs = if flags.contains(Flags::NEGOTIATE_UNICODE) {
500 data.encode_utf16()
501 .flat_map(|w| w.to_le_bytes())
502 .collect()
503 } else if flags.contains(Flags::NEGOTIATE_OEM) {
504 rust_string_to_ansi(data)
505 .ok_or_else(|| StoringError::NonOemEncodable { string: data.to_owned() })?
506 } else {
507 return Err(StoringError::NeitherUnicodeNorOem);
508 };
509
510 append_sec_buffer(packet_bytes, data_block, sec_buffer_offset, &bs);
511
512 Ok(())
513}
514
515fn utf16_le_bytes_to_string(bytes: &[u8]) -> Result<String, ParsingError> {
517 if bytes.len() % 2 != 0 {
518 return Err(ParsingError::ItemLengthNotDivisible { expected_divisor: 2, obtained_length: bytes.len() });
519 }
520 let u16s: Vec<u16> = bytes.chunks_exact(2)
521 .map(|chk| u16::from_le_bytes(chk.try_into().unwrap()))
522 .collect();
523 String::from_utf16(&u16s)
524 .or(Err(ParsingError::InvalidUtf16{ value: u16s }))
525}
526
527fn oem_bytes_to_string(bytes: &[u8]) -> Result<String, ParsingError> {
529 ansi_string_to_rust(bytes)
530 .ok_or_else(|| ParsingError::InvalidOemEncoding { value: Vec::from(bytes) })
531}
532
533fn ntlm_bytes_to_string(flags: Flags, bytes: &[u8]) -> Result<String, ParsingError> {
535 if flags.contains(Flags::NEGOTIATE_UNICODE) {
536 utf16_le_bytes_to_string(bytes)
537 } else if flags.contains(Flags::NEGOTIATE_OEM) {
538 oem_bytes_to_string(bytes)
539 } else {
540 Err(ParsingError::NeitherUnicodeNorOem)
541 }
542}
543
544impl Message {
545 pub fn to_bytes(&self) -> Result<Vec<u8>, StoringError> {
547 let mut buf = Vec::new();
548 buf.extend_from_slice(&NTLMSSP_MAGIC);
549 buf.extend_from_slice(&self.message_number().to_le_bytes());
550 match self {
551 Message::Negotiate(t1m) => {
552 buf.extend_from_slice(&t1m.to_bytes()?);
553 },
554 Message::Challenge(t2m) => {
555 buf.extend_from_slice(&t2m.to_bytes()?);
556 },
557 Message::Authenticate(t3m) => {
558 buf.extend_from_slice(&t3m.to_bytes()?);
559 },
560 Message::Other(_msg_num, data) => {
561 buf.extend_from_slice(data);
562 }
563 }
564 Ok(buf)
565 }
566}
567impl TryFrom<&[u8]> for Message {
568 type Error = ParsingError;
569
570 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
571 if value.len() < 12 {
572 return Err(ParsingError::ShortHeader { expected_min_len: 12, obtained_len: value.len() });
574 }
575 let obtained_magic: [u8; 8] = value[0..8].try_into().unwrap();
576 if obtained_magic != NTLMSSP_MAGIC {
577 return Err(ParsingError::MagicMismatch { expected: NTLMSSP_MAGIC, obtained: Vec::from(obtained_magic) });
578 }
579 let message_type = u32::from_le_bytes(value[8..12].try_into().unwrap());
580 match message_type {
581 0x0000_0001 => NegotiateMessage::try_from(&value[12..])
582 .map(|t1m| Message::Negotiate(t1m)),
583 0x0000_0002 => ChallengeMessage::try_from(&value[12..])
584 .map(|t2m| Message::Challenge(t2m)),
585 0x0000_0003 => AuthenticateMessage::try_from(&value[12..])
586 .map(|t3m| Message::Authenticate(t3m)),
587 other_type => Ok(Message::Other(other_type, Vec::from(&value[12..]))),
588 }
589 }
590}
591
592impl OsVersion {
593 pub fn to_bytes(&self) -> Vec<u8> {
595 let mut ret = Vec::with_capacity(8);
596 ret.push(self.major_version);
597 ret.push(self.minor_version);
598 ret.extend_from_slice(&self.build_number.to_le_bytes());
599 ret.extend_from_slice(&self.reserved);
600 ret.push(self.ntlm_revision);
601 ret
602 }
603}
604impl TryFrom<&[u8]> for OsVersion {
605 type Error = ParsingError;
606
607 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
608 if value.len() != 8 {
609 return Err(ParsingError::ItemLengthMismatch { expected: 8, obtained: value.len() });
610 }
611
612 let major_version = value[0];
613 let minor_version = value[1];
614 let build_number = u16::from_le_bytes(value[2..4].try_into().unwrap());
615 let reserved = value[4..7].try_into().unwrap();
616 let ntlm_revision = value[7];
617
618 Ok(OsVersion {
619 major_version,
620 minor_version,
621 build_number,
622 reserved,
623 ntlm_revision,
624 })
625 }
626}
627
628impl NegotiateMessage {
629 pub fn to_bytes(&self) -> Result<Vec<u8>, StoringError> {
631 let mut sec_buffer_offset: u32
632 = 8 + 4 + 4 + 8 + 8 + 8 ;
639
640 let mut ret = Vec::new();
641 let mut data_block = Vec::new();
642
643 ret.extend_from_slice(&self.flags.bits().to_le_bytes());
644 append_sec_buffer_string(&mut ret, &mut data_block, &mut sec_buffer_offset, self.flags, &self.supplied_domain)?;
645 append_sec_buffer_string(&mut ret, &mut data_block, &mut sec_buffer_offset, self.flags, &self.supplied_workstation)?;
646 ret.extend_from_slice(&self.os_version.to_bytes());
647 ret.append(&mut data_block);
648 Ok(ret)
649 }
650}
651impl TryFrom<&[u8]> for NegotiateMessage {
652 type Error = ParsingError;
653
654 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
655 if value.len() < 32 {
658 return Err(ParsingError::ItemMinLengthMismatch { expected_at_least: 32, obtained: value.len() });
659 }
660 let flags_u32 = u32::from_le_bytes(value[0..4].try_into().unwrap());
661 let flags = Flags::from_bits(flags_u32).unwrap();
662
663 let supplied_domain_secbuf = SecurityBuffer::try_from(&value[4..12]).unwrap();
664 let supplied_workstation_secbuf = SecurityBuffer::try_from(&value[12..20]).unwrap();
665 let os_version = if flags.contains(Flags::NEGOTIATE_VERSION) {
666 OsVersion::try_from(&value[20..28]).unwrap()
667 } else {
668 OsVersion::default()
669 };
670
671 let supplied_domain_bytes = supplied_domain_secbuf.apply_to_slice(&value, -(8 + 4))?;
675 let supplied_workstation_bytes = supplied_workstation_secbuf.apply_to_slice(&value, -(8 + 4))?;
676
677 let supplied_domain = ntlm_bytes_to_string(flags, supplied_domain_bytes)?;
678 let supplied_workstation = ntlm_bytes_to_string(flags, supplied_workstation_bytes)?;
679
680 Ok(Self {
681 flags,
682 supplied_domain,
683 supplied_workstation,
684 os_version,
685 })
686 }
687}
688
689impl ChallengeMessage {
690 pub fn to_bytes(&self) -> Result<Vec<u8>, StoringError> {
692 let mut sec_buffer_offset: u32
693 = 8 + 4 + 8 + 4 + 8 + 8 + 8 + 8 ;
702
703 let mut ret = Vec::new();
704 let mut data_block = Vec::new();
705
706 append_sec_buffer_string(&mut ret, &mut data_block, &mut sec_buffer_offset, self.flags, &self.target_name)?;
707 ret.extend_from_slice(&self.flags.bits().to_le_bytes());
708 ret.extend_from_slice(&self.challenge);
709 data_block.extend_from_slice(&self.context.0.to_le_bytes());
710 data_block.extend_from_slice(&self.context.1.to_le_bytes());
711 {
712 let target_info_bytes: Vec<u8> = self.target_information.iter()
713 .flat_map(|ti| ti.to_bytes())
714 .collect();
715 append_sec_buffer(&mut ret, &mut data_block, &mut sec_buffer_offset, &target_info_bytes);
716 }
717 ret.extend_from_slice(&self.os_version.to_bytes());
718 ret.append(&mut data_block);
719 Ok(ret)
720 }
721}
722impl TryFrom<&[u8]> for ChallengeMessage {
723 type Error = ParsingError;
724
725 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
726 if value.len() < 44 {
729 return Err(ParsingError::ItemMinLengthMismatch { expected_at_least: 44, obtained: value.len() });
730 }
731 let target_name_secbuf = SecurityBuffer::try_from(&value[0..8]).unwrap();
732 let flags_u32 = u32::from_le_bytes(value[8..12].try_into().unwrap());
733 let flags = Flags::from_bits(flags_u32).unwrap();
734 let challenge = value[12..20].try_into().unwrap();
735 let context = {
736 let context_0 = u32::from_le_bytes(value[20..24].try_into().unwrap());
737 let context_1 = u32::from_le_bytes(value[24..28].try_into().unwrap());
738 (context_0, context_1)
739 };
740 let target_info_secbuf = SecurityBuffer::try_from(&value[28..36]).unwrap();
741 let os_version = if flags.contains(Flags::NEGOTIATE_VERSION) {
742 OsVersion::try_from(&value[36..44]).unwrap()
743 } else {
744 OsVersion::default()
745 };
746
747 let target_name_bytes = target_name_secbuf.apply_to_slice(&value, -(8 + 4))?;
751 let mut target_info_bytes = target_info_secbuf.apply_to_slice(&value, -(8 + 4))?;
752
753 let target_name = ntlm_bytes_to_string(flags, target_name_bytes)?;
754
755 let mut target_information = Vec::new();
756 while target_info_bytes.len() > 0 {
757 let (tie, next) = TargetInfoEntry::try_from_bytes(&target_info_bytes)?;
758 target_information.push(tie);
759 target_info_bytes = next;
760 }
761
762 Ok(Self {
763 target_name,
764 flags,
765 challenge,
766 context,
767 target_information,
768 os_version,
769 })
770 }
771}
772
773impl AuthenticateMessage {
774 pub fn to_bytes(&self) -> Result<Vec<u8>, StoringError> {
776 let mut sec_buffer_offset: u32
777 = 8 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 8 ;
788
789 let mut ret = Vec::new();
790 let mut data_block = Vec::new();
791
792 append_sec_buffer(&mut ret, &mut data_block, &mut sec_buffer_offset, &self.lm_response);
793 append_sec_buffer(&mut ret, &mut data_block, &mut sec_buffer_offset, &self.ntlm_response);
794 append_sec_buffer_string(&mut ret, &mut data_block, &mut sec_buffer_offset, self.flags, &self.domain_name)?;
795 append_sec_buffer_string(&mut ret, &mut data_block, &mut sec_buffer_offset, self.flags, &self.user_name)?;
796 append_sec_buffer_string(&mut ret, &mut data_block, &mut sec_buffer_offset, self.flags, &self.workstation_name)?;
797 append_sec_buffer(&mut ret, &mut data_block, &mut sec_buffer_offset, &self.session_key);
798 ret.extend_from_slice(&self.flags.bits().to_le_bytes());
799 ret.extend_from_slice(&self.os_version.to_bytes());
800 ret.append(&mut data_block);
801 Ok(ret)
802 }
803}
804impl TryFrom<&[u8]> for AuthenticateMessage {
805 type Error = ParsingError;
806
807 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
808 if value.len() < 60 {
811 return Err(ParsingError::ItemMinLengthMismatch { expected_at_least: 60, obtained: value.len() });
812 }
813 let lm_response_secbuf = SecurityBuffer::try_from(&value[0..8]).unwrap();
814 let ntlm_response_secbuf = SecurityBuffer::try_from(&value[8..16]).unwrap();
815 let domain_name_secbuf = SecurityBuffer::try_from(&value[16..24]).unwrap();
816 let user_name_secbuf = SecurityBuffer::try_from(&value[24..32]).unwrap();
817 let workstation_name_secbuf = SecurityBuffer::try_from(&value[32..40]).unwrap();
818 let session_key_secbuf = SecurityBuffer::try_from(&value[40..48]).unwrap();
819 let flags_u32 = u32::from_le_bytes(value[48..52].try_into().unwrap());
820 let flags = Flags::from_bits(flags_u32).unwrap();
821 let os_version = if flags.contains(Flags::NEGOTIATE_VERSION) {
822 OsVersion::try_from(&value[52..60]).unwrap()
823 } else {
824 OsVersion::default()
825 };
826
827 let lm_response_bytes = lm_response_secbuf.apply_to_slice(&value, -(8 + 4))?;
831 let ntlm_response_bytes = ntlm_response_secbuf.apply_to_slice(&value, -(8 + 4))?;
832 let domain_name_bytes = domain_name_secbuf.apply_to_slice(&value, -(8 + 4))?;
833 let user_name_bytes = user_name_secbuf.apply_to_slice(&value, -(8 + 4))?;
834 let workstation_name_bytes = workstation_name_secbuf.apply_to_slice(&value, -(8 + 4))?;
835 let session_key_bytes = session_key_secbuf.apply_to_slice(&value, -(8 + 4))?;
836
837 let lm_response = Vec::from(lm_response_bytes);
838 let ntlm_response = Vec::from(ntlm_response_bytes);
839 let domain_name = ntlm_bytes_to_string(flags, domain_name_bytes)?;
840 let user_name = ntlm_bytes_to_string(flags, user_name_bytes)?;
841 let workstation_name = ntlm_bytes_to_string(flags, workstation_name_bytes)?;
842 let session_key = Vec::from(session_key_bytes);
843
844 Ok(Self {
845 lm_response,
846 ntlm_response,
847 domain_name,
848 user_name,
849 workstation_name,
850 session_key,
851 flags,
852 os_version,
853 })
854 }
855}
856
857impl SecurityBuffer {
858 pub fn for_slice(slice: &[u8]) -> Self {
862 let len_u16: u16 = slice.len()
863 .try_into().expect("buffer too long for u16 length");
864 Self {
865 length: len_u16,
866 capacity: len_u16,
867 offset: 0,
868 }
869 }
870
871 pub fn to_bytes(&self) -> Vec<u8> {
873 let mut ret = Vec::with_capacity(8);
874 ret.extend_from_slice(&self.length.to_le_bytes());
875 ret.extend_from_slice(&self.capacity.to_le_bytes());
876 ret.extend_from_slice(&self.offset.to_le_bytes());
877 ret
878 }
879
880 pub fn apply_to_slice<'a>(&self, slice: &'a [u8], adjust: isize) -> Result<&'a [u8], ParsingError> {
885 if self.length == 0 {
886 return Ok(&slice[0..0]);
888 }
889
890 let offset_isize: isize = self.offset.try_into()
891 .or(Err(ParsingError::OffsetTooLargeIsize))?;
892 let length_isize: isize = self.length.try_into()
893 .or(Err(ParsingError::LengthTooLargeIsize))?;
894
895 if offset_isize + adjust < 0 {
896 return Err(ParsingError::StartOutOfRange { start: offset_isize + adjust, length: slice.len() });
897 }
898 if offset_isize + length_isize + adjust < 0 {
899 return Err(ParsingError::EndOutOfRange { end: offset_isize + length_isize + adjust, length: slice.len() });
900 }
901
902 let start: usize = (offset_isize + adjust).try_into().unwrap();
903 let end: usize = (offset_isize + length_isize + adjust).try_into().unwrap();
904
905 if start >= slice.len() {
906 return Err(ParsingError::StartOutOfRange { start: offset_isize + adjust, length: slice.len() });
907 }
908 if end > slice.len() {
909 return Err(ParsingError::EndOutOfRange { end: offset_isize + length_isize + adjust, length: slice.len() });
910 }
911
912 Ok(&slice[start..end])
913 }
914}
915impl TryFrom<&[u8]> for SecurityBuffer {
916 type Error = ParsingError;
917
918 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
919 if value.len() != 8 {
920 return Err(ParsingError::ItemLengthMismatch { expected: 8, obtained: value.len() });
921 }
922
923 let length = u16::from_le_bytes(value[0..2].try_into().unwrap());
924 let capacity = u16::from_le_bytes(value[2..4].try_into().unwrap());
925 let offset = u32::from_le_bytes(value[4..8].try_into().unwrap());
926
927 Ok(Self {
928 length,
929 capacity,
930 offset,
931 })
932 }
933}
934
935impl TargetInfoEntry {
936 pub fn to_bytes(&self) -> Vec<u8> {
938 let mut ret = Vec::new();
939
940 let entry_type_u16: u16 = self.entry_type.into();
942 let bytes_len: u16 = self.data.len().try_into().expect("length of bytes does not fit into u16");
943
944 ret.extend_from_slice(&entry_type_u16.to_le_bytes());
945 ret.extend_from_slice(&bytes_len.to_le_bytes());
946 ret.extend_from_slice(&self.data);
947 ret
948 }
949
950 pub fn try_from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), ParsingError> {
954 if bytes.len() < 4 {
955 return Err(ParsingError::ItemMinLengthMismatch { expected_at_least: 4, obtained: bytes.len() });
956 }
957
958 let entry_type_u16 = u16::from_le_bytes(bytes[0..2].try_into().unwrap());
959 let entry_type: TargetInfoType = entry_type_u16.into();
960 let length_u16 = u16::from_le_bytes(bytes[2..4].try_into().unwrap());
961 let length: usize = length_u16.into();
962
963 if length + 4 > bytes.len() {
964 return Err(ParsingError::ItemMinLengthMismatch { expected_at_least: length + 4, obtained: bytes.len() });
965 }
966 if length % 2 != 0 {
967 return Err(ParsingError::ItemLengthNotDivisible { expected_divisor: 2, obtained_length: bytes.len() });
968 }
969
970 let data = Vec::from(&bytes[4..4+length]);
971
972 let entry = Self {
973 entry_type,
974 data,
975 };
976 let rest = &bytes[4+length..];
977 Ok((entry, rest))
978 }
979
980 pub fn to_string(&self) -> Result<String, ParsingError> {
982 utf16_le_bytes_to_string(&self.data)
983 }
984
985 pub fn from_string(entry_type: TargetInfoType, string: &str) -> Self {
987 let data: Vec<u8> = string.encode_utf16()
989 .flat_map(|b| b.to_le_bytes())
990 .collect();
991 Self {
992 entry_type,
993 data,
994 }
995 }
996}
997
998impl ChallengeResponse {
999 pub fn to_message(&self, creds: &Credentials, workstation_name: &str, flags: Flags) -> Message {
1001 Message::Authenticate(AuthenticateMessage {
1002 lm_response: self.lm_response.clone(),
1003 ntlm_response: self.ntlm_response.clone(),
1004 domain_name: creds.domain.clone(),
1005 user_name: creds.username.clone(),
1006 workstation_name: workstation_name.to_owned(),
1007 session_key: self.session_key.clone(),
1008 flags,
1009 os_version: Default::default(),
1010 })
1011 }
1012}
1013
1014
1015pub fn get_ntlm_time() -> i64 {
1020 let windows_epoch = NaiveDate::from_ymd_opt(1601, 1, 1)
1021 .expect("1601-01-01 is not a valid date?!")
1022 .and_hms_opt(0, 0, 0).expect("1601-01-01T00:00:00 is not a valid date-time?!")
1023 .and_utc();
1024 let now = Utc::now();
1025 let delta = (now - windows_epoch) * 10_000_000;
1027 delta.num_seconds()
1028}
1029
1030
1031pub fn des_long(key: [u8; 16], data: [u8; 8]) -> [u8; 24] {
1033 let key0: [u8; 7] = key[0..7].try_into().unwrap();
1034 let key1: [u8; 7] = key[7..14].try_into().unwrap();
1035 let key2: [u8; 7] = [key[14], key[15], 0, 0, 0, 0, 0];
1036
1037 let des0 = Des::new_from_slice(&key0).unwrap();
1038 let des1 = Des::new_from_slice(&key1).unwrap();
1039 let des2 = Des::new_from_slice(&key2).unwrap();
1040
1041 let mut res0: GenericArray<u8, U8> = data.try_into().unwrap();
1042 let mut res1 = res0.clone();
1043 let mut res2 = res0.clone();
1044
1045 des0.encrypt_block(&mut res0);
1046 des1.encrypt_block(&mut res1);
1047 des2.encrypt_block(&mut res2);
1048
1049 let mut ret = [0u8; 24];
1050 let (slice0, ret2) = ret.split_at_mut(8);
1051 let (slice1, slice2) = ret2.split_at_mut(8);
1052 slice0.copy_from_slice(res0.as_slice());
1053 slice1.copy_from_slice(res1.as_slice());
1054 slice2.copy_from_slice(res2.as_slice());
1055
1056 ret
1057}
1058
1059
1060pub fn lm_v1_password_func(password: &str) -> [u8; 16] {
1084 let des_plaintext_fixed: GenericArray<u8, U8> = GenericArray::from(*b"KGS!@#$%");
1085
1086 let uppercase_password = password.to_uppercase();
1087 let mut password_bytes = match rust_string_to_ansi(&uppercase_password) {
1088 Some(bs) => bs,
1089 None => return [0; 16],
1090 };
1091 while password_bytes.len() < 14 {
1092 password_bytes.push(0x00);
1093 }
1094
1095 let mut output = [0; 16];
1096 let (half0, half1) = output.split_at_mut(8);
1097
1098 {
1099 {
1100 let des_state = Des::new_from_slice(&password_bytes[0..7]).unwrap();
1101 let mut buf = des_plaintext_fixed.clone();
1102 des_state.encrypt_block(&mut buf);
1103 half0.copy_from_slice(buf.as_slice());
1104 }
1105 {
1106 let des_state = Des::new_from_slice(&password_bytes[7..14]).unwrap();
1107 let mut buf = des_plaintext_fixed.clone();
1108 des_state.encrypt_block(&mut buf);
1109 half1.copy_from_slice(buf.as_slice());
1110 }
1111 }
1112
1113 output
1114}
1115
1116
1117pub fn ntlm_v1_password_func(password: &str) -> [u8; 16] {
1122 let password_bytes: Vec<u8> = password.encode_utf16()
1123 .flat_map(|p| p.to_le_bytes())
1124 .collect();
1125 let mut md4_state = <Md4 as Digest>::new();
1126 md4_state.update(&password_bytes);
1127 md4_state.finalize().as_slice().try_into().unwrap()
1128}
1129
1130pub fn ntlm_v2_password_func(creds: &Credentials) -> [u8; 16] {
1137 let hmac_key = ntlm_v1_password_func(&creds.password);
1139 let mut hmac_md5: Hmac<Md5> = <Hmac<Md5> as Mac>::new_from_slice(&hmac_key).unwrap();
1140
1141 let upper_user_bytes: Vec<u8> = creds.username
1142 .to_uppercase()
1143 .encode_utf16()
1144 .flat_map(|p| p.to_le_bytes())
1145 .collect();
1146 hmac_md5.update(&upper_user_bytes);
1147 let dom_bytes: Vec<u8> = creds.domain
1148 .encode_utf16()
1149 .flat_map(|p| p.to_le_bytes())
1150 .collect();
1151 hmac_md5.update(&dom_bytes);
1152
1153 let mut ret = [0; 16];
1154 ret.copy_from_slice(hmac_md5.finalize().into_bytes().as_slice());
1155 ret
1156}
1157
1158pub fn respond_challenge_ntlm_v1(server_challenge: [u8; 8], creds: &Credentials) -> ChallengeResponse {
1162 let ntlm_key = ntlm_v1_password_func(&creds.password);
1163 let ntlm_response = Vec::from(des_long(ntlm_key, server_challenge));
1164
1165 let lm_key = lm_v1_password_func(&creds.password);
1166 let lm_response = Vec::from(des_long(lm_key, server_challenge));
1167
1168 let session_key = {
1169 let mut md4 = <Md4 as Digest>::new();
1170 md4.update(&ntlm_key);
1171 Vec::from(md4.finalize().as_slice())
1172 };
1173
1174 ChallengeResponse {
1175 lm_response,
1176 ntlm_response,
1177 session_key,
1178 }
1179}
1180
1181pub fn respond_challenge_ntlm_v1_no_lm(server_challenge: [u8; 8], creds: &Credentials) -> ChallengeResponse {
1185 let ntlm_key = ntlm_v1_password_func(&creds.password);
1186 let ntlm_response = Vec::from(des_long(ntlm_key, server_challenge));
1187
1188 let lm_response = ntlm_response.clone();
1189
1190 let session_key = {
1191 let mut md4 = <Md4 as Digest>::new();
1192 md4.update(&ntlm_key);
1193 Vec::from(md4.finalize().as_slice())
1194 };
1195
1196 ChallengeResponse {
1197 lm_response,
1198 ntlm_response,
1199 session_key,
1200 }
1201}
1202
1203pub fn respond_challenge_ntlm_v1_extended(server_challenge: [u8; 8], creds: &Credentials) -> ChallengeResponse {
1208 let mut client_challenge: [u8; 8] = [0; 8];
1209 OsRng.fill(&mut client_challenge);
1210
1211 let ntlm_key = ntlm_v1_password_func(&creds.password);
1212
1213 let desl_plaintext: [u8; 8] = {
1214 let mut md5 = <Md5 as Digest>::new();
1215 md5.update(server_challenge);
1216 md5.update(client_challenge);
1217 let digest = md5.finalize();
1218
1219 let mut dk = [0u8; 8];
1220 dk.copy_from_slice(&digest.as_slice()[0..8]);
1221 dk
1222 };
1223
1224 let ntlm_response = Vec::from(des_long(ntlm_key, desl_plaintext));
1225 let mut lm_response = Vec::with_capacity(24);
1226 lm_response.extend_from_slice(&client_challenge);
1227 while lm_response.len() < 24 {
1228 lm_response.push(0);
1229 }
1230
1231 let session_key = {
1232 let mut md4 = <Md4 as Digest>::new();
1233 md4.update(&ntlm_key);
1234 Vec::from(md4.finalize().as_slice())
1235 };
1236
1237 ChallengeResponse {
1238 lm_response,
1239 ntlm_response,
1240 session_key,
1241 }
1242}
1243
1244pub fn respond_challenge_ntlm_v2(server_challenge: [u8; 8], target_info: &[u8], time: i64, creds: &Credentials) -> ChallengeResponse {
1247 let mut client_challenge: [u8; 8] = [0; 8];
1248 OsRng.fill(&mut client_challenge);
1249
1250 let mut temp = Vec::new();
1251 temp.push(0x01); temp.push(0x01); for _ in 0..6 { temp.push(0x00); }
1254 temp.extend_from_slice(&time.to_le_bytes());
1255 temp.extend_from_slice(&client_challenge);
1256 for _ in 0..4 { temp.push(0x00); }
1257 temp.extend_from_slice(&target_info);
1258 for _ in 0..4 { temp.push(0x00); }
1259
1260 let ntlm_key = ntlm_v2_password_func(&creds);
1261
1262 let nt_proof_string = {
1263 let mut hmac_md5: Hmac<Md5> = <Hmac<Md5> as Mac>::new_from_slice(&ntlm_key).unwrap();
1264 hmac_md5.update(&server_challenge);
1265 hmac_md5.update(&temp);
1266
1267 let mut ps = [0u8; 16];
1268 ps.copy_from_slice(hmac_md5.finalize().into_bytes().as_slice());
1269 ps
1270 };
1271
1272 let mut ntlm_response = Vec::with_capacity(16 + temp.len());
1273 ntlm_response.extend_from_slice(&nt_proof_string);
1274 ntlm_response.extend_from_slice(&temp);
1275
1276 let mut lm_response = Vec::with_capacity(16 + 8);
1277 {
1278 let mut hmac_md5: Hmac<Md5> = <Hmac<Md5> as Mac>::new_from_slice(&ntlm_key).unwrap();
1279 hmac_md5.update(&server_challenge);
1280 hmac_md5.update(&client_challenge);
1281 lm_response.extend_from_slice(hmac_md5.finalize().into_bytes().as_slice());
1282 }
1283 lm_response.extend_from_slice(&client_challenge);
1284
1285 let session_key = {
1286 let mut hmac_md5: Hmac<Md5> = <Hmac<Md5> as Mac>::new_from_slice(&ntlm_key).unwrap();
1287 hmac_md5.update(&nt_proof_string);
1288 Vec::from(hmac_md5.finalize().into_bytes().as_slice())
1289 };
1290
1291 ChallengeResponse {
1292 lm_response,
1293 ntlm_response,
1294 session_key,
1295 }
1296}