use crate::{
GROUP_MEMBERSHIP, KERB_SID_AND_ATTRIBUTES, PISID, USER_SESSION_KEY,
};
use ms_dtyp::{FILETIME, RPC_UNICODE_STRING, ULONG, USHORT};
pub const NOT_EXPIRE_TIME: u64 = 0x7fffffffffffffff;
pub const NOT_SET_TIME: u64 = 0x0;
const RPC_LITTLE_ENDIAN: u8 = 0x10;
const RPC_VERSION: u8 = 0x1;
macro_rules! align {
($data:expr, $alignment:expr) => {
while ($data.len() % $alignment) != 0 {
$data.push(00);
}
};
}
macro_rules! build_le_bytes {
($data:expr, $int:expr) => {{
let mut bs = $int.to_le_bytes().to_vec();
align!($data, bs.len());
$data.append(&mut bs);
}};
}
macro_rules! build_filetime {
($data:expr, $time:expr) => {
build_le_bytes!($data, $time.dwLowDateTime);
build_le_bytes!($data, $time.dwHighDateTime);
};
}
macro_rules! build_unistr {
($data:expr, $str:expr, $ref_data:expr, $ref_id:expr) => {
build_le_bytes!($data, $str.Length);
build_le_bytes!($data, $str.MaximumLength);
$ref_id += 1;
build_le_bytes!($data, $ref_id);
build_le_bytes!($ref_data, ($str.Length / 2) as u32);
build_le_bytes!($ref_data, 0u32);
build_le_bytes!($ref_data, ($str.Length / 2) as u32);
$ref_data.append(&mut u16_array_to_le_bytes(&$str.Buffer));
};
}
macro_rules! build_group_membership {
($data:expr, $group:expr) => {
build_le_bytes!($data, $group.RelativeId);
build_le_bytes!($data, $group.Attributes);
};
}
macro_rules! build_sid {
($data:expr, $sid:expr) => {
build_le_bytes!($data, $sid.SubAuthority.len() as u32);
$data.push($sid.Revision);
$data.push($sid.SubAuthority.len() as u8);
$data.append(&mut $sid.IdentifierAuthority.to_vec());
for sub_auth in $sid.SubAuthority.iter() {
$data.append(&mut sub_auth.to_le_bytes().to_vec());
}
};
}
#[derive(Clone, Debug, PartialEq, Default)]
pub struct KERB_VALIDATION_INFO {
pub LogonTime: FILETIME,
pub LogoffTime: FILETIME,
pub KickOffTime: FILETIME,
pub PasswordLastSet: FILETIME,
pub PasswordCanChange: FILETIME,
pub PasswordMustChange: FILETIME,
pub EfectiveName: RPC_UNICODE_STRING,
pub FullName: RPC_UNICODE_STRING,
pub LogonScript: RPC_UNICODE_STRING,
pub ProfilePath: RPC_UNICODE_STRING,
pub HomeDirectory: RPC_UNICODE_STRING,
pub HomeDirectoryDrive: RPC_UNICODE_STRING,
pub LogonCount: USHORT,
pub BadPasswordCount: USHORT,
pub UserId: ULONG,
pub PrimaryGroupId: ULONG,
pub GroupIds: Vec<GROUP_MEMBERSHIP>,
pub UserFlags: ULONG,
pub UserSessionKey: USER_SESSION_KEY,
pub LogonServer: RPC_UNICODE_STRING,
pub LogonDomainName: RPC_UNICODE_STRING,
pub LogonDomainId: PISID,
pub Reserved1: [u8; 8],
pub UserAccountControl: ULONG,
pub SubAuthStatus: ULONG,
pub LastSuccessfulILogon: FILETIME,
pub LastFailedILogon: FILETIME,
pub FailedILogonCount: ULONG,
pub Reserved3: ULONG,
pub ExtraSids: Vec<KERB_SID_AND_ATTRIBUTES>,
pub ResourceGroupDomainSid: Option<PISID>,
pub ResourceGroupIds: Vec<GROUP_MEMBERSHIP>,
}
impl KERB_VALIDATION_INFO {
pub fn build_data(&self) -> Vec<u8> {
let mut ref_id: u32 = 0x1110;
let mut data = Vec::new();
let mut ref_data = Vec::new();
build_filetime!(data, self.LogonTime);
build_filetime!(data, self.LogoffTime);
build_filetime!(data, self.KickOffTime);
build_filetime!(data, self.PasswordLastSet);
build_filetime!(data, self.PasswordCanChange);
build_filetime!(data, self.PasswordMustChange);
build_unistr!(data, self.EfectiveName, ref_data, ref_id);
build_unistr!(data, self.FullName, ref_data, ref_id);
build_unistr!(data, self.LogonScript, ref_data, ref_id);
build_unistr!(data, self.ProfilePath, ref_data, ref_id);
build_unistr!(data, self.HomeDirectory, ref_data, ref_id);
build_unistr!(data, self.HomeDirectoryDrive, ref_data, ref_id);
build_le_bytes!(data, self.LogonCount);
build_le_bytes!(data, self.BadPasswordCount);
build_le_bytes!(data, self.UserId);
build_le_bytes!(data, self.PrimaryGroupId);
let GroupCount = self.GroupIds.len() as ULONG;
build_le_bytes!(data, GroupCount);
ref_id += 1;
build_le_bytes!(data, ref_id);
build_le_bytes!(ref_data, GroupCount);
for group_id in self.GroupIds.iter() {
build_group_membership!(ref_data, group_id);
}
build_le_bytes!(data, self.UserFlags);
data.append(&mut self.UserSessionKey.to_bytes().to_vec());
build_unistr!(data, self.LogonServer, ref_data, ref_id);
build_unistr!(data, self.LogonDomainName, ref_data, ref_id);
ref_id += 1;
build_le_bytes!(data, ref_id);
build_sid!(ref_data, self.LogonDomainId);
data.append(&mut self.Reserved1.to_vec());
build_le_bytes!(data, self.UserAccountControl);
build_le_bytes!(data, self.SubAuthStatus);
build_filetime!(data, self.LastSuccessfulILogon);
build_filetime!(data, self.LastFailedILogon);
build_le_bytes!(data, self.FailedILogonCount);
build_le_bytes!(data, self.Reserved3);
let SidCount = self.ExtraSids.len() as ULONG;
build_le_bytes!(data, SidCount);
if SidCount != 0 {
ref_id += 1;
build_le_bytes!(data, ref_id);
build_le_bytes!(ref_data, SidCount);
for kerb_sid in self.ExtraSids.iter() {
build_sid!(ref_data, kerb_sid.Sid);
build_le_bytes!(ref_data, kerb_sid.Attributes);
}
} else {
build_le_bytes!(data, 0u32);
}
if let Some(ResourceGroupDomainSid) = &self.ResourceGroupDomainSid {
ref_id += 1;
build_le_bytes!(data, ref_id);
build_sid!(ref_data, ResourceGroupDomainSid);
} else {
build_le_bytes!(data, 0u32);
}
let ResourceGroupDomainCount = self.ResourceGroupIds.len() as ULONG;
build_le_bytes!(data, ResourceGroupDomainCount);
if ResourceGroupDomainCount != 0 {
ref_id += 1;
build_le_bytes!(data, ref_id);
build_le_bytes!(ref_data, ResourceGroupDomainCount);
for group_id in self.ResourceGroupIds.iter() {
build_group_membership!(ref_data, group_id);
}
} else {
build_le_bytes!(data, 0u32);
}
data.append(&mut ref_data);
return data;
}
fn build_rpc_header(&self, body_length: u32) -> Vec<u8> {
let header_len: u16 = 0x8;
let filler: &[u8] = &[0xcc, 0xcc, 0xcc, 0xcc];
let mut data = Vec::new();
data.push(RPC_VERSION);
data.push(RPC_LITTLE_ENDIAN);
data.append(&mut header_len.to_le_bytes().to_vec());
data.append(&mut filler.to_vec());
let body_plus_ref_size = body_length + 4;
data.append(&mut body_plus_ref_size.to_le_bytes().to_vec());
data.append(&mut filler.to_vec());
return data;
}
pub fn build(&self) -> Vec<u8> {
let ref_id: u32 = 0x2122;
let mut body_data = self.build_data();
let mut data = self.build_rpc_header(body_data.len() as u32);
data.append(&mut ref_id.to_le_bytes().to_vec());
data.append(&mut body_data);
return data;
}
}
fn u16_array_to_le_bytes(u16_array: &[u16]) -> Vec<u8> {
let mut u8_vec: Vec<u8> = Vec::with_capacity(u16_array.len() * 2);
for u16_item in u16_array.iter() {
let u8_min = *u16_item as u8;
let u8_max = (*u16_item >> 8) as u8;
u8_vec.push(u8_min);
u8_vec.push(u8_max);
}
return u8_vec;
}
#[cfg(test)]
mod test {
use super::*;
use ms_samr::{
SE_GROUP_ENABLED, SE_GROUP_ENABLED_BY_DEFAULT, SE_GROUP_MANDATORY,
USER_DONT_EXPIRE_PASSWORD, USER_NORMAL_ACCOUNT,
};
use std::convert::TryFrom;
#[test]
fn test_build_kerb_validation_info() {
let timestamp = 0x01d63110a3b82380u64;
let name = "stegosaurus";
let user_id = 500;
let groups = vec![513, 512, 520, 518, 519];
let domain = "jurassic.park";
let domain_sid = "S-1-5-21-1339291983-1349129144-367733775";
let mut kvi = KERB_VALIDATION_INFO::default();
kvi.LogonTime = timestamp.into();
kvi.LogoffTime = NOT_EXPIRE_TIME.into();
kvi.KickOffTime = NOT_EXPIRE_TIME.into();
kvi.PasswordLastSet = timestamp.into();
kvi.PasswordCanChange = 0.into();
kvi.PasswordMustChange = NOT_EXPIRE_TIME.into();
kvi.EfectiveName = name.into();
kvi.LogonCount = 500;
kvi.BadPasswordCount = 0;
kvi.UserId = user_id;
kvi.PrimaryGroupId = 513;
for group_id in groups.iter() {
kvi.GroupIds.push(GROUP_MEMBERSHIP::new(
*group_id,
SE_GROUP_MANDATORY
| SE_GROUP_ENABLED
| SE_GROUP_ENABLED_BY_DEFAULT,
));
}
kvi.LogonDomainName = domain.to_uppercase().as_str().into();
kvi.LogonDomainId = PISID::try_from(domain_sid).unwrap();
kvi.UserAccountControl =
USER_NORMAL_ACCOUNT | USER_DONT_EXPIRE_PASSWORD;
let raw = vec![
0x01, 0x10, 0x08, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xB8, 0x01, 0x00,
0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x22, 0x21, 0x00, 0x00, 0x80, 0x23,
0xB8, 0xA3, 0x10, 0x31, 0xD6, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
0x80, 0x23, 0xB8, 0xA3, 0x10, 0x31, 0xD6, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x7F, 0x16, 0x00, 0x16, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x12, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x13, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x16, 0x11, 0x00, 0x00, 0xF4, 0x01, 0x00, 0x00, 0xF4,
0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x17, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x11, 0x00, 0x00, 0x1A,
0x00, 0x1A, 0x00, 0x19, 0x11, 0x00, 0x00, 0x1A, 0x11, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65,
0x00, 0x67, 0x00, 0x6F, 0x00, 0x73, 0x00, 0x61, 0x00, 0x75, 0x00,
0x72, 0x00, 0x75, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x07,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x08, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00,
0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x55, 0x00, 0x52, 0x00, 0x41,
0x00, 0x53, 0x00, 0x53, 0x00, 0x49, 0x00, 0x43, 0x00, 0x2E, 0x00,
0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
0x15, 0x00, 0x00, 0x00, 0x4F, 0xF9, 0xD3, 0x4F, 0xB8, 0x13, 0x6A,
0x50, 0x0F, 0x2C, 0xEB, 0x15,
];
println!("{:02X?}", kvi.build());
assert_eq!(raw, kvi.build());
}
}