use std::io::Cursor;
use anyhow::anyhow;
use binrw::BinWrite;
use ntlmclient::{Message, TargetInfoType};
use rasn::{AsnType, Decode, Encode, Decoder, Encoder, der};
use rasn::prelude::OctetString;
use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;
use crate::{string_to_utf16_bytes, Header, SessionSetup1Req, SmbOptions};
impl SmbOptions<'_> {
pub async fn SessionSetupRequset2(&mut self, mut stream: &mut TcpStream) -> anyhow::Result<()> {
let credss = ntlmclient::Credentials {
username: self.User.to_string(),
password: self.Password.to_string(),
domain: self.Domain.to_string(),
};
let slice: &[u8] = self.sessionSetup1RespSecProvider.as_slice();
let challenge = ntlmclient::Message::try_from(slice)?;
let challenge_content = match challenge {
Message::Challenge(ref c) => c,
_ => return Err(anyhow!("Invalid challenge message"))
};
let mut timestamp:[u8;8] = [0;8];
for entry in &challenge_content.target_information {
match entry.entry_type {
TargetInfoType::Terminator => {}
TargetInfoType::NtServer => {}
TargetInfoType::NtDomain => {}
TargetInfoType::DnsDomain => {}
TargetInfoType::DnsServer => {}
TargetInfoType::DnsForest => {}
TargetInfoType::Flags => {}
TargetInfoType::Timestamp => {
timestamp.copy_from_slice(&(entry.data.clone()));
}
TargetInfoType::SingleHost => {}
TargetInfoType::TargetName => {}
TargetInfoType::ChannelBindings => {}
TargetInfoType::Unknown(_) => {}
}
}
let target_info_bytes: Vec<u8> = challenge_content.target_information
.iter()
.flat_map(|ie| ie.to_bytes())
.collect();
let creds = credss;
let mut challenge_response = ntlmclient::respond_challenge_ntlm_v2(
challenge_content.challenge,
&target_info_bytes,
ntlmclient::get_ntlm_time(),
&creds,
);
challenge_response.session_key = vec![];
let auth_flags
= ntlmclient::Flags::NEGOTIATE_56BIT
| ntlmclient::Flags::NEGOTIATE_128BIT
| ntlmclient::Flags::NEGOTIATE_TARGET_INFO
| ntlmclient::Flags::NEGOTIATE_NTLM2_KEY
| ntlmclient::Flags::NEGOTIATE_DOMAIN_SUPPLIED
| ntlmclient::Flags::NEGOTIATE_NTLM
| ntlmclient::Flags::REQUEST_TARGET
| ntlmclient::Flags::NEGOTIATE_UNICODE
;
let auth_msg = challenge_response.to_message(
&creds,
self.Workstation.clone(),
auth_flags,
);
let new_auth_msg_bytes = manual_auth_msg(auth_msg.clone());
let mut newheader = Header::new();
newheader.credit_charge = 1;
newheader.command = 1;
newheader.credits = 127u16;
newheader.message_id = 2;
newheader.session_id = self.sesionSetup1RespHeader.session_id;
let mut req2 = SessionSetup1Req {
Header: newheader,
StructureSize: 25,
Flags: 0x00,
SecurityMode: 1,
Capabilities: 0,
Channel: 0,
SecurityBufferOffset: 0,
SecurityBufferLength: 0,
PreviousSessionID: 0,
};
req2.SecurityBufferLength = (new_auth_msg_bytes.len() + 16 ) as u16;
req2.SecurityBufferOffset = 0x58;
let mut cur = Cursor::new(Vec::<u8>::new());
req2.write_le(&mut cur)?;
let mut data = cur.into_inner();
data.extend_from_slice(generateSecBlob(new_auth_msg_bytes)?.as_slice());
let mut metadata = (data.len() as u32).to_be_bytes().to_vec();
metadata.extend_from_slice(&data);
stream.write_all(&metadata.clone()).await?;
stream.flush().await?;
Ok(())
}
}
fn manual_auth_msg(m:Message) -> Vec<u8>{
match m {
Message::Authenticate(a) => {
let lm_resp = a.lm_response.clone();
let ntlm_resp = a.ntlm_response.clone();
let hexntlm = hex::encode(&ntlm_resp);
let mut domain_resp = a.domain_name;
let user_resp = a.user_name;
let host_resp = a.workstation_name;
let flags_resp = a.flags;
let NTLMSSP_header: [u8; 8] = [
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00
];
let NTMLSSP_type: [u8; 4] = [
0x03, 0x00, 0x00, 0x00
];
let lm_resp_len = lm_resp.len() as u16;
let lm_resp_max_len = lm_resp.len() as u16;
let ntlm_resp_len = ntlm_resp.len() as u16;
let ntlm_resp_max_len = ntlm_resp.len() as u16;
let doamin_resp_len = (domain_resp.len()* 2) as u16;
let doamin_resp_max_len = (domain_resp.len()* 2) as u16;
let user_resp_len = (user_resp.len()* 2) as u16;
let user_resp_max_len = (user_resp.len() *2) as u16;
let host_resp_len = (host_resp.len()* 2) as u16;
let host_resp_max_len = (host_resp.len() * 2) as u16;
let session_key:[u8;8] = [0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00];
let flags_resp = a.flags.bits().to_ne_bytes();
let all_length1:usize = 8 + 4 + 8 + 8 + 8 + 8 + 8 + 8 +4 ; let all_length2:usize = doamin_resp_len as usize + user_resp_len as usize +
host_resp_len as usize + lm_resp_len as usize + ntlm_resp_len as usize;
let all_length = all_length1 + all_length2;
let ntlm_resp_offsec = (all_length as u16 - ntlm_resp_len) as u32;
let lm_resp_offsec = ntlm_resp_offsec - 24u32;
let host_resp_offsec = lm_resp_offsec - (host_resp_len as u32);
let user_resp_offsec = host_resp_offsec - (user_resp_len as u32);
let doamin_resp_offsec =user_resp_offsec - (doamin_resp_len as u32);
let mut final_resp = Vec::new();
final_resp.extend_from_slice(&NTLMSSP_header);
final_resp.extend_from_slice(&NTMLSSP_type);
final_resp.extend_from_slice(&lm_resp_len.to_le_bytes());
final_resp.extend_from_slice(&lm_resp_max_len.to_le_bytes());
final_resp.extend_from_slice(&lm_resp_offsec.to_le_bytes());
final_resp.extend_from_slice(&ntlm_resp_len.to_le_bytes());
final_resp.extend_from_slice(&ntlm_resp_max_len.to_le_bytes());
final_resp.extend_from_slice(&ntlm_resp_offsec.to_ne_bytes());
final_resp.extend_from_slice(&doamin_resp_len.to_le_bytes());
final_resp.extend_from_slice(&doamin_resp_max_len.to_le_bytes());
final_resp.extend_from_slice(&doamin_resp_offsec.to_ne_bytes());
final_resp.extend_from_slice(&user_resp_len.to_le_bytes());
final_resp.extend_from_slice(&user_resp_max_len.to_le_bytes());
final_resp.extend_from_slice(&user_resp_offsec.to_ne_bytes());
final_resp.extend_from_slice(&host_resp_len.to_le_bytes());
final_resp.extend_from_slice(&host_resp_max_len.to_le_bytes());
final_resp.extend_from_slice(&host_resp_offsec.to_le_bytes());
final_resp.extend_from_slice(&session_key);
final_resp.extend_from_slice(&flags_resp);
final_resp.extend_from_slice(&string_to_utf16_bytes(domain_resp.as_str()));
final_resp.extend_from_slice(&string_to_utf16_bytes(user_resp.as_str()));
final_resp.extend_from_slice(&string_to_utf16_bytes(host_resp.as_str()));
final_resp.extend_from_slice(&lm_resp);
final_resp.extend_from_slice(&ntlm_resp);
final_resp
}
_ => {
vec![]
}
}
}
fn generateSecBlob(d: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let s = SecBlob {
secPro: SecProvider {
data: Some(OctetString::from(d))
},
};
let data = der::encode(&s)?;
Ok(data)
}
#[derive(AsnType, Encode, Decode, Debug, PartialEq)]
#[rasn(tag(explicit(1)))]
struct SecBlob {
#[rasn(tag(context, 2))]
pub secPro: SecProvider,
}
#[derive(AsnType, Encode, Decode, Debug, PartialEq)]
struct SecProvider {
pub data: Option<OctetString>,
}