From 80008544beed59ef82387b902e0b3c52f261afef Mon Sep 17 00:00:00 2001 From: YuG0rd Date: Wed, 21 May 2025 06:06:21 -0700 Subject: [PATCH 1/2] Add support for dMSA KEY_LIST_REP parsing with multiple EncryptionKeys --- Rubeus/lib/Ask.cs | 12 ++++----- Rubeus/lib/LSA.cs | 26 ++++++++++++++++---- Rubeus/lib/krb_structures/EncryptionKey.cs | 13 +++++++++- Rubeus/lib/krb_structures/PA_KEY_LIST_REP.cs | 26 ++++++++++++++------ 4 files changed, 58 insertions(+), 19 deletions(-) diff --git a/Rubeus/lib/Ask.cs b/Rubeus/lib/Ask.cs index f9408eb6..3316f263 100644 --- a/Rubeus/lib/Ask.cs +++ b/Rubeus/lib/Ask.cs @@ -470,14 +470,14 @@ public static byte[] TGS(string userName, string domain, Ticket providedTicket, string keyListHash = null; if (keyList) { - keyListHash = Helpers.ByteArrayToString(encRepPart.encryptedPaData.PA_KEY_LIST_REP.encryptionKey.keyvalue); + keyListHash = Helpers.ByteArrayToString(encRepPart.encryptedPaData.PA_KEY_LIST_REP.EncryptionKeys[0].keyvalue); } // extract DMSA_KEY_PACKAGE for parsing to displayTicket. - PA_DMSA_KEY_PACKAGE dmsaCurrentKeys = null; + PA_DMSA_KEY_PACKAGE dmsaKeyPackage = null; if (dmsa) { - dmsaCurrentKeys = encRepPart.encryptedPaData.PA_DMSA_KEY_PACKAGE; + dmsaKeyPackage = encRepPart.encryptedPaData.PA_DMSA_KEY_PACKAGE; } // if using /opsec and the ticket is for a server configuration for unconstrained delegation, request a forwardable TGT @@ -548,7 +548,7 @@ public static byte[] TGS(string userName, string domain, Ticket providedTicket, string kirbiString = Convert.ToBase64String(kirbiBytes); return ProcessTicketResponse(kirbiBytes, kirbiString, cred, ptt, servicekey, u2u, clientKey, display, - asrepkey, keyListHash, outfile, printargs, dmsaCurrentKeys); + asrepkey, keyListHash, outfile, printargs, dmsaKeyPackage); } else if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR) @@ -564,7 +564,7 @@ public static byte[] TGS(string userName, string domain, Ticket providedTicket, return null; } - static public byte[] ProcessTicketResponse(byte[] kirbiBytes, string kirbiString, KRB_CRED cred, bool ptt, string servicekey, bool u2u, byte[] clientKey, bool display, string asrepkey, string keyListHash, string outfile, bool printargs, PA_DMSA_KEY_PACKAGE dmsaCurrentKeys) { + static public byte[] ProcessTicketResponse(byte[] kirbiBytes, string kirbiString, KRB_CRED cred, bool ptt, string servicekey, bool u2u, byte[] clientKey, bool display, string asrepkey, string keyListHash, string outfile, bool printargs, PA_DMSA_KEY_PACKAGE dmsaKeyPackage) { if (ptt) { // pass-the-ticket -> import into LSASS @@ -590,7 +590,7 @@ static public byte[] ProcessTicketResponse(byte[] kirbiBytes, string kirbiString LSA.DisplayTicket(kirbi, 2, false, false, false, false, string.IsNullOrEmpty(servicekey) ? null : Helpers.StringToByteArray(servicekey), string.IsNullOrEmpty(asrepkey) ? null : Helpers.StringToByteArray(asrepkey), - null, null, null, string.IsNullOrEmpty(keyListHash) ? null : Helpers.StringToByteArray(keyListHash), null, dmsaCurrentKeys); + null, null, null, string.IsNullOrEmpty(keyListHash) ? null : Helpers.StringToByteArray(keyListHash), null, dmsaKeyPackage); } if (!String.IsNullOrEmpty(outfile)) { diff --git a/Rubeus/lib/LSA.cs b/Rubeus/lib/LSA.cs index 96b1f90b..d68739e1 100755 --- a/Rubeus/lib/LSA.cs +++ b/Rubeus/lib/LSA.cs @@ -488,7 +488,7 @@ public static void DisplaySessionCreds(List sessionCreds, TicketDi } } - public static void DisplayTicket(KRB_CRED cred, int indentLevel = 2, bool displayTGT = false, bool displayB64ticket = false, bool extractKerberoastHash = true, bool nowrap = false, byte[] serviceKey = null, byte[] asrepKey = null, string serviceUser = "", string serviceDomain = "", byte[] krbKey = null, byte[] keyList = null, string desPlainText = "", PA_DMSA_KEY_PACKAGE dmsaCurrentKeys = null) + public static void DisplayTicket(KRB_CRED cred, int indentLevel = 2, bool displayTGT = false, bool displayB64ticket = false, bool extractKerberoastHash = true, bool nowrap = false, byte[] serviceKey = null, byte[] asrepKey = null, string serviceUser = "", string serviceDomain = "", byte[] krbKey = null, byte[] keyList = null, string desPlainText = "", PA_DMSA_KEY_PACKAGE dmsaKeyPackage = null) { // displays a given .kirbi (KRB_CRED) object, with display options @@ -552,13 +552,29 @@ public static void DisplayTicket(KRB_CRED cred, int indentLevel = 2, bool displa Console.WriteLine("{0}Password Hash : {2}", indent, userName, Helpers.ByteArrayToString(keyList)); } - if(dmsaCurrentKeys != null) + if (dmsaKeyPackage != null) { - string etypeName = Enum.GetName(typeof(Interop.KERB_ETYPE), dmsaCurrentKeys.currentKeys.encryptionKey.keytype); - string cKeyValue = Helpers.ByteArrayToString(dmsaCurrentKeys.currentKeys.encryptionKey.keyvalue); + string etypeName, cKeyValue; + foreach (var encryptionKey in dmsaKeyPackage.currentKeys.EncryptionKeys) + { + etypeName = Enum.GetName(typeof(Interop.KERB_ETYPE), encryptionKey.keytype); + cKeyValue = Helpers.ByteArrayToString(encryptionKey.keyvalue); + + Console.WriteLine("{0}Current Keys for {1}: ({2}) {3}", indent, userName, etypeName, cKeyValue); + } - Console.WriteLine("{0}Current Keys for {1}: ({2}) {3}", indent, userName, etypeName, cKeyValue); + if (dmsaKeyPackage.previousKeys != null) + { + foreach (var encryptionKey in dmsaKeyPackage.previousKeys.EncryptionKeys) + { + etypeName = Enum.GetName(typeof(Interop.KERB_ETYPE), encryptionKey.keytype); + cKeyValue = Helpers.ByteArrayToString(encryptionKey.keyvalue); + + + Console.WriteLine("{0}Previous Keys for {1}: ({2}) {3}", indent, userName, etypeName, cKeyValue); + } + } } diff --git a/Rubeus/lib/krb_structures/EncryptionKey.cs b/Rubeus/lib/krb_structures/EncryptionKey.cs index 9cf9dd93..2b3bdb48 100755 --- a/Rubeus/lib/krb_structures/EncryptionKey.cs +++ b/Rubeus/lib/krb_structures/EncryptionKey.cs @@ -21,7 +21,18 @@ public EncryptionKey() public EncryptionKey(AsnElt body) { - foreach (AsnElt s in body.Sub[0].Sub) + // Unwrap a wrapper if present, or use body directly if it's already a SEQUENCE + AsnElt seq; + if (body.TagValue == AsnElt.SEQUENCE) + { + seq = body; + } + else + { + seq = body.Sub[0]; + } + + foreach (AsnElt s in seq.Sub) { switch (s.TagValue) { diff --git a/Rubeus/lib/krb_structures/PA_KEY_LIST_REP.cs b/Rubeus/lib/krb_structures/PA_KEY_LIST_REP.cs index 0ac8ea96..e4c4de70 100644 --- a/Rubeus/lib/krb_structures/PA_KEY_LIST_REP.cs +++ b/Rubeus/lib/krb_structures/PA_KEY_LIST_REP.cs @@ -1,5 +1,7 @@ using Asn1; using System; +using System.Collections.Generic; +using System.Linq; using System.Text; namespace Rubeus @@ -7,23 +9,33 @@ namespace Rubeus public class PA_KEY_LIST_REP { // KERB-KEY-LIST-REP ::= SEQUENCE OF EncryptionKey + public PA_KEY_LIST_REP() { - encryptionKey = new EncryptionKey(); + EncryptionKeys = new List(); } + public PA_KEY_LIST_REP(AsnElt body) { - encryptionKey = new EncryptionKey(body); + if (body.TagValue != AsnElt.SEQUENCE) + throw new ArgumentException("KERB-KEY-LIST-REP must be a SEQUENCE", nameof(body)); + + EncryptionKeys = new List(body.Sub.Length); + foreach (var child in body.Sub) + { + EncryptionKeys.Add(new EncryptionKey(child)); + } } public AsnElt Encode() { - AsnElt encryptionKeyAsn = encryptionKey.Encode(); - AsnElt encryptionKeySeq = AsnElt.Make(AsnElt.SEQUENCE, new[] { encryptionKeyAsn }); - return encryptionKeySeq; - } + var encodedKeys = EncryptionKeys + .Select(key => key.Encode()) + .ToArray(); - public EncryptionKey encryptionKey { get; set; } + return AsnElt.Make(AsnElt.SEQUENCE, encodedKeys); + } + public List EncryptionKeys { get; set; } } } \ No newline at end of file From 5f7a36b6616fc8c3b9c52109cad9f1919e38659a Mon Sep 17 00:00:00 2001 From: YuG0rd Date: Wed, 21 May 2025 06:06:56 -0700 Subject: [PATCH 2/2] Add support for standalone dMSAs which don't have previous-keys --- .../lib/krb_structures/PA_DMSA_KEY_PACKAGE.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Rubeus/lib/krb_structures/PA_DMSA_KEY_PACKAGE.cs b/Rubeus/lib/krb_structures/PA_DMSA_KEY_PACKAGE.cs index 6e28e42b..5496b366 100644 --- a/Rubeus/lib/krb_structures/PA_DMSA_KEY_PACKAGE.cs +++ b/Rubeus/lib/krb_structures/PA_DMSA_KEY_PACKAGE.cs @@ -26,11 +26,21 @@ public PA_DMSA_KEY_PACKAGE() public PA_DMSA_KEY_PACKAGE(AsnElt body) { - currentKeys = new PA_KEY_LIST_REP(body.Sub[0].Sub[0]); - previousKeys = new PA_KEY_LIST_REP(body.Sub[1].Sub[0]); - expirationInterval = body.Sub[2].Sub[0].GetTime(); - fetchInterval = body.Sub[3].Sub[0].GetTime(); - } + currentKeys = new PA_KEY_LIST_REP(body.Sub[0].Sub[0]); + + // previous-keys is OPTIONAL + if (body.Sub.Length == 4) + { + previousKeys = new PA_KEY_LIST_REP(body.Sub[1].Sub[0]); + expirationInterval = body.Sub[2].Sub[0].GetTime(); + fetchInterval = body.Sub[3].Sub[0].GetTime(); + } + else + { + expirationInterval = body.Sub[1].Sub[0].GetTime(); + fetchInterval = body.Sub[2].Sub[0].GetTime(); + } + } public AsnElt Encode() {