DSInternals
DSInternals copied to clipboard
Online SIDHistory synchronization
It would be very helpful to have ability of online SIDHistory synchronization. At least via legitimate "DsAddSidHistory" API.
Below is a simple concept code in PowerShell that makes it:
Add-Type -Language "CSharp" -TypeDefinition @"
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace PInvoke
{
public class ntdsapi
{
[DllImport("ntdsapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern UInt32 DsMakePasswordCredentials(
[MarshalAs(UnmanagedType.LPWStr)] String User,
[MarshalAs(UnmanagedType.LPWStr)] String Domain,
[MarshalAs(UnmanagedType.LPWStr)] String Password,
out IntPtr pAuthIdentity
);
[DllImport("ntdsapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern void DsFreePasswordCredentials(
IntPtr AuthIdentity
);
[DllImport("ntdsapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern UInt32 DsBindWithCred(
[MarshalAs(UnmanagedType.LPWStr)] String DomainControllerName,
[MarshalAs(UnmanagedType.LPWStr)] String DnsDomainName,
IntPtr AuthIdentity,
out IntPtr phDS
);
[DllImport("ntdsapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern UInt32 DsUnBind(
IntPtr phDS
);
[DllImport("ntdsapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern UInt32 DsAddSidHistory(
IntPtr hDS,
UInt32 Flags,
[MarshalAs(UnmanagedType.LPWStr)] String SrcDomain,
[MarshalAs(UnmanagedType.LPWStr)] String SrcPrincipal,
[MarshalAs(UnmanagedType.LPWStr)] String SrcDomainController,
IntPtr SrcDomainCreds,
[MarshalAs(UnmanagedType.LPWStr)] String DstDomain,
[MarshalAs(UnmanagedType.LPWStr)] String DstPrincipal
);
}
}
"@
[System.UInt32] $uiErrorCode = 0
[System.ComponentModel.Win32Exception] $objException = $null
[System.String] $strSourceUserName = "AdministratorUserName"
[System.String] $strSourceUserPassword = "AdministratorPassword"
[System.String] $strSourceUserDomainName = "DOMAIN"
[System.IntPtr] $hSourceAuthenticationIdentity = 0
[System.String] $strTargetUserName = $null
[System.String] $strTargetUserPassword = $null
[System.String] $strTargetUserDomainName = $null
[System.IntPtr] $hTargetAuthenticationIdentity = 0
[System.String] $strSourceDomainControllerFQDN = "PDC.source.com"
[System.String] $strSourceDomainFQDN = "source.com"
[System.IntPtr] $hSourceDirectoryService = 0
[System.String] $strTargetDomainControllerFQDN = $null
[System.String] $strTargetDomainFQDN = "target.com"
[System.IntPtr] $hTargetDirectoryService = 0
[System.String] $strSourcePrincipalUserName = "SAMAccountName"
[System.String] $strTargetPrincipalUserName = "SAMAccountName"
if ($strSourceUserName.Length) {
$uiErrorCode = [PInvoke.ntdsapi]::DsMakePasswordCredentials(
$strSourceUserName,
$strSourceUserDomainName,
$strSourceUserPassword,
[ref] $hSourceAuthenticationIdentity
)
} else {
$hSourceAuthenticationIdentity = 0
}
if ($strTargetUserName.Length) {
$uiErrorCode = [PInvoke.ntdsapi]::DsMakePasswordCredentials(
$strTargetUserName,
$strTargetUserDomainName,
$strTargetUserPassword,
[ref] $hTargetAuthenticationIdentity
)
} else {
$hTargetAuthenticationIdentity = 0
}
$uiErrorCode = [PInvoke.ntdsapi]::DsBindWithCred(
$strTargetDomainControllerFQDN,
$strTargetDomainFQDN,
$hTargetAuthenticationIdentity,
[ref] $hTargetDirectoryService
)
$uiErrorCode = [PInvoke.ntdsapi]::DsAddSidHistory(
$hTargetDirectoryService,
0,
$strSourceDomainFQDN,
$strSourcePrincipalUserName,
$strSourceDomainControllerFQDN,
$hSourceAuthenticationIdentity,
$strTargetDomainFQDN,
$strTargetPrincipalUserName
)
$objException = New-Object -TypeName System.ComponentModel.Win32Exception([System.Int32] $uiErrorCode)
$objException.Message
$uiErrorCode = [PInvoke.ntdsapi]::DsUnBind($hSourceDirectoryService)
[PInvoke.ntdsapi]::DsFreePasswordCredentials($hSourceAuthenticationIdentity)
$uiErrorCode = [PInvoke.ntdsapi]::DsUnBind($hTargetDirectoryService)
[PInvoke.ntdsapi]::DsFreePasswordCredentials($hTargetAuthenticationIdentity)
Thanks. DSInternals actually uses direct MS-DRSR RPC calls instead of utilizing ntdsapi.dll. The code would thus need to be implemented in C++ in the DRSConnection class and by calling IDL_DRSAddSidHistory.
Initial point of this issue was to write values into "sIDHistory" attribute of target objects without taking AD database offline, like "Add-ADDBSidHistory" requires. Replication protocol allows to read everything, including password hashes, but it doesn't allow to perform writes. Am I wrong about it?