Skip to content

Commit

Permalink
Merge pull request GhostPack#165 from GhostPack/principal_types
Browse files Browse the repository at this point in the history
Added support for requesting a TGT with a specific principal name type
  • Loading branch information
0xe7 authored Aug 8, 2023
2 parents 659d98d + 6411444 commit 9241312
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 25 deletions.
11 changes: 8 additions & 3 deletions Rubeus/Commands/Asktgt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public void Execute(Dictionary<string, string> arguments)
string outfile = "";
string certificate = "";
string servicekey = "";
string principalType = "principal";

bool ptt = false;
bool opsec = false;
Expand Down Expand Up @@ -185,6 +186,10 @@ public void Execute(Dictionary<string, string> arguments)
}
}

if (arguments.ContainsKey("/principaltype")) {
principalType = arguments["/principaltype"];
}

if (arguments.ContainsKey("/createnetonly"))
{
// if we're starting a hidden process to apply the ticket to
Expand Down Expand Up @@ -237,7 +242,7 @@ public void Execute(Dictionary<string, string> arguments)
{
try
{
Ask.NoPreAuthTGT(user, domain, hash, encType, dc, outfile, ptt, luid, true, true, proxyUrl, service);
Ask.NoPreAuthTGT(user, domain, hash, encType, dc, outfile, ptt, luid, true, true, proxyUrl, service, principalType);
}
catch (KerberosErrorException ex)
{
Expand All @@ -253,9 +258,9 @@ public void Execute(Dictionary<string, string> arguments)
}
}
else if (String.IsNullOrEmpty(certificate))
Ask.TGT(user, domain, hash, encType, outfile, ptt, dc, luid, true, opsec, servicekey, changepw, pac, proxyUrl, service);
Ask.TGT(user, domain, hash, encType, outfile, ptt, dc, luid, true, opsec, servicekey, changepw, pac, proxyUrl, service, principalType);
else
Ask.TGT(user, domain, certificate, password, encType, outfile, ptt, dc, luid, true, verifyCerts, servicekey, getCredentials, proxyUrl, service, changepw);
Ask.TGT(user, domain, certificate, password, encType, outfile, ptt, dc, luid, true, verifyCerts, servicekey, getCredentials, proxyUrl, service, changepw, principalType);

return;
}
Expand Down
12 changes: 6 additions & 6 deletions Rubeus/Domain/Info.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@ public static void ShowLogo()

public static void ShowUsage()
{
string usage = @"
string usage = @"
Ticket requests and renewals:
Retrieve a TGT based on a user password/hash, optionally saving to a file or applying to the current logon session or a specific LUID:
Rubeus.exe asktgt /user:USER </password:PASSWORD [/enctype:DES|RC4|AES128|AES256] | /des:HASH | /rc4:HASH | /aes128:HASH | /aes256:HASH> [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/outfile:FILENAME] [/ptt] [/luid] [/nowrap] [/opsec] [/nopac] [/oldsam] [/proxyurl:https://KDC_PROXY/kdcproxy]
Rubeus.exe asktgt /user:USER </password:PASSWORD [/enctype:DES|RC4|AES128|AES256] | /des:HASH | /rc4:HASH | /aes128:HASH | /aes256:HASH> [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/outfile:FILENAME] [/ptt] [/luid] [/nowrap] [/opsec] [/nopac] [/oldsam] [/proxyurl:https://KDC_PROXY/kdcproxy] [/principaltype:principal|enterprise|x500|srv_xhost|srv_host|srv_inst]
Retrieve a TGT based on a user password/hash, start a /netonly process, and to apply the ticket to the new process/logon session:
Rubeus.exe asktgt /user:USER </password:PASSWORD [/enctype:DES|RC4|AES128|AES256] | /des:HASH | /rc4:HASH | /aes128:HASH | /aes256:HASH> /createnetonly:C:\Windows\System32\cmd.exe [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/nowrap] [/opsec] [/nopac] [/oldsam] [/proxyurl:https://KDC_PROXY/kdcproxy]
Rubeus.exe asktgt /user:USER </password:PASSWORD [/enctype:DES|RC4|AES128|AES256] | /des:HASH | /rc4:HASH | /aes128:HASH | /aes256:HASH> /createnetonly:C:\Windows\System32\cmd.exe [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/nowrap] [/opsec] [/nopac] [/oldsam] [/proxyurl:https://KDC_PROXY/kdcproxy] [/principaltype:principal|enterprise|x500|srv_xhost|srv_host|srv_inst]
Retrieve a TGT using a PCKS12 certificate, start a /netonly process, and to apply the ticket to the new process/logon session:
Rubeus.exe asktgt /user:USER /certificate:C:\temp\leaked.pfx </password:STOREPASSWORD> /createnetonly:C:\Windows\System32\cmd.exe [/getcredentials] [/servicekey:KRBTGTKEY] [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/nowrap] [/nopac] [/proxyurl:https://KDC_PROXY/kdcproxy]
Rubeus.exe asktgt /user:USER /certificate:C:\temp\leaked.pfx </password:STOREPASSWORD> /createnetonly:C:\Windows\System32\cmd.exe [/getcredentials] [/servicekey:KRBTGTKEY] [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/nowrap] [/nopac] [/proxyurl:https://KDC_PROXY/kdcproxy] [/principaltype:principal|enterprise|x500|srv_xhost|srv_host|srv_inst]
Retrieve a TGT using a certificate from the users keystore (Smartcard) specifying certificate thumbprint or subject, start a /netonly process, and to apply the ticket to the new process/logon session:
Rubeus.exe asktgt /user:USER /certificate:f063e6f4798af085946be6cd9d82ba3999c7ebac /createnetonly:C:\Windows\System32\cmd.exe [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/nowrap]
Rubeus.exe asktgt /user:USER /certificate:f063e6f4798af085946be6cd9d82ba3999c7ebac /createnetonly:C:\Windows\System32\cmd.exe [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/nowrap] [/principaltype:principal|enterprise|x500|srv_xhost|srv_host|srv_inst]
Request a TGT without sending pre-auth data:
Rubeus.exe asktgt /user:USER [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/outfile:FILENAME] [/ptt] [/luid] [/nowrap] [/nopac] [/proxyurl:https://KDC_PROXY/kdcproxy]
Rubeus.exe asktgt /user:USER [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/outfile:FILENAME] [/ptt] [/luid] [/nowrap] [/nopac] [/proxyurl:https://KDC_PROXY/kdcproxy] [/principaltype:principal|enterprise|x500|srv_xhost|srv_host|srv_inst]
Request a service ticket using an AS-REQ:
Rubeus.exe asktgt /user:USER /service:SPN </password:PASSWORD [/enctype:DES|RC4|AES128|AES256] | /des:HASH | /rc4:HASH | /aes128:HASH | /aes256:HASH> [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/outfile:FILENAME] [/ptt] [/luid] [/nowrap] [/opsec] [/nopac] [/oldsam] [/proxyurl:https://KDC_PROXY/kdcproxy]
Expand Down
15 changes: 8 additions & 7 deletions Rubeus/lib/Ask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ public KerberosErrorException(string message, KRB_ERROR krbError)

public class Ask
{
public static byte[] TGT(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool opsec = false, string servicekey = "", bool changepw = false, bool pac = true, string proxyUrl = null, string service = null)
public static byte[] TGT(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool opsec = false, string servicekey = "", bool changepw = false, bool pac = true, string proxyUrl = null, string service = null, string principalType="principal")
{
// send request without Pre-Auth to emulate genuine traffic
bool preauth = false;
if (opsec)
{
try
{
preauth = NoPreAuthTGT(userName, domain, keyString, etype, domainController, outfile, ptt, luid, describe, true, proxyUrl);
preauth = NoPreAuthTGT(userName, domain, keyString, etype, domainController, outfile, ptt, luid, describe, true, proxyUrl, "", principalType);
}
catch (KerberosErrorException) { }
}
Expand All @@ -52,7 +52,7 @@ public class Ask
{
Console.WriteLine("[*] Using {0} hash: {1}", etype, keyString);
Console.WriteLine("[*] Building AS-REQ (w/ preauth) for: '{0}\\{1}'", domain, userName);
AS_REQ userHashASREQ = AS_REQ.NewASReq(userName, domain, keyString, etype, opsec, changepw, pac, service);
AS_REQ userHashASREQ = AS_REQ.NewASReq(userName, domain, keyString, etype, opsec, changepw, pac, service, principalType);
return InnerTGT(userHashASREQ, etype, outfile, ptt, domainController, luid, describe, true, opsec, servicekey, false, proxyUrl);
}
}
Expand All @@ -76,10 +76,11 @@ public class Ask
return null;
}

public static bool NoPreAuthTGT(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, string domainController, string outfile, bool ptt, LUID luid = new LUID(), bool describe = false, bool verbose = false, string proxyUrl = null, string service = "")
public static bool NoPreAuthTGT(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, string domainController, string outfile, bool ptt, LUID luid = new LUID(), bool describe = false, bool verbose = false, string proxyUrl = null, string service = "", string principalType="principal")
{
byte[] response = null;
AS_REQ NoPreAuthASREQ = AS_REQ.NewASReq(userName, domain, etype, true);
AS_REQ NoPreAuthASREQ = AS_REQ.NewASReq(userName, domain, etype, true, null, principalType);

byte[] reqBytes = NoPreAuthASREQ.Encode().Encode();

if (String.IsNullOrEmpty(proxyUrl))
Expand Down Expand Up @@ -186,7 +187,7 @@ public static X509Certificate2 FindCertificate(string certificate, string storeP
}
}

public static byte[] TGT(string userName, string domain, string certFile, string certPass, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool verifyCerts = false, string servicekey = "", bool getCredentials = false, string proxyUrl = null, string service = null, bool changepw = false) {
public static byte[] TGT(string userName, string domain, string certFile, string certPass, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool verifyCerts = false, string servicekey = "", bool getCredentials = false, string proxyUrl = null, string service = null, bool changepw = false, string principalType="principal") {
try {
X509Certificate2 cert = FindCertificate(certFile, certPass);

Expand All @@ -206,7 +207,7 @@ public static X509Certificate2 FindCertificate(string certificate, string storeP
Console.WriteLine("[*] Using PKINIT with etype {0} and subject: {1} ", etype, cert.Subject);
Console.WriteLine("[*] Building AS-REQ (w/ PKINIT preauth) for: '{0}\\{1}'", domain, userName);

AS_REQ pkinitASREQ = AS_REQ.NewASReq(userName, domain, cert, agreement, etype, verifyCerts, service, changepw);
AS_REQ pkinitASREQ = AS_REQ.NewASReq(userName, domain, cert, agreement, etype, verifyCerts, service, changepw, principalType);
return InnerTGT(pkinitASREQ, etype, outfile, ptt, domainController, luid, describe, true, false, servicekey, getCredentials, proxyUrl);

} catch (KerberosErrorException ex) {
Expand Down
20 changes: 20 additions & 0 deletions Rubeus/lib/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,26 @@ public static string ByteArrayToString(byte[] bytes) {
return returnDate;
}

public static Interop.PRINCIPAL_TYPE StringToPrincipalType(string name) {

switch (name) {
case "principal":
return Interop.PRINCIPAL_TYPE.NT_PRINCIPAL;
case "x500":
return Interop.PRINCIPAL_TYPE.NT_X500_PRINCIPAL;
case "enterprise":
return Interop.PRINCIPAL_TYPE.NT_ENTERPRISE;
case "srv_xhost":
return Interop.PRINCIPAL_TYPE.NT_SRV_XHST;
case "srv_host":
return Interop.PRINCIPAL_TYPE.NT_SRV_HST;
case "srv_inst":
return Interop.PRINCIPAL_TYPE.NT_SRV_INST;
default:
throw new ArgumentException($"name argument with value {name} is not supported");
}
}

#endregion


Expand Down
3 changes: 2 additions & 1 deletion Rubeus/lib/LSA.cs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ public static void DisplayTicket(KRB_CRED cred, int indentLevel = 2, bool displa
// nowrap - don't wrap base64 ticket output

var userName = string.Join("@", cred.enc_part.ticket_info[0].pname.name_string.ToArray());
var principalType = cred.enc_part.ticket_info[0].pname.name_type.ToString();
var sname = string.Join("/", cred.enc_part.ticket_info[0].sname.name_string.ToArray());
var keyType = String.Format("{0}", (Interop.KERB_ETYPE)cred.enc_part.ticket_info[0].key.keytype);
var b64Key = Convert.ToBase64String(cred.enc_part.ticket_info[0].key.keyvalue);
Expand Down Expand Up @@ -567,7 +568,7 @@ public static void DisplayTicket(KRB_CRED cred, int indentLevel = 2, bool displa
// full display with session key
Console.WriteLine("\r\n{0}ServiceName : {1}", indent, sname);
Console.WriteLine("{0}ServiceRealm : {1}", indent, cred.enc_part.ticket_info[0].srealm);
Console.WriteLine("{0}UserName : {1}", indent, userName);
Console.WriteLine("{0}UserName : {1}", indent, $"{userName} ({principalType})");
Console.WriteLine("{0}UserRealm : {1}", indent, cred.enc_part.ticket_info[0].prealm);
Console.WriteLine("{0}StartTime : {1}", indent, cred.enc_part.ticket_info[0].starttime.ToLocalTime());
Console.WriteLine("{0}EndTime : {1}", indent, cred.enc_part.ticket_info[0].endtime.ToLocalTime());
Expand Down
17 changes: 9 additions & 8 deletions Rubeus/lib/krb_structures/AS_REQ.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ namespace Rubeus

public class AS_REQ
{
public static AS_REQ NewASReq(string userName, string domain, Interop.KERB_ETYPE etype, bool opsec = false, string service = null)
public static AS_REQ NewASReq(string userName, string domain, Interop.KERB_ETYPE etype, bool opsec = false, string service = null, string principalType = "principal")
{
// build a new AS-REQ for the given userName, domain, and etype, but no PA-ENC-TIMESTAMP
// used for AS-REP-roasting

AS_REQ req = new AS_REQ(opsec);

// set the username to roast
req.req_body.cname.name_string.Add(userName);
req.req_body.cname.name_string.AddRange(userName.Split('/'));
req.req_body.cname.name_type = Helpers.StringToPrincipalType(principalType);

// the realm (domain) the user exists in
req.req_body.realm = domain;
Expand Down Expand Up @@ -87,7 +88,7 @@ public static AS_REQ NewASReq(string userName, string domain, Interop.KERB_ETYPE
return req;
}

public static AS_REQ NewASReq(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, bool opsec = false, bool changepw = false, bool pac = true, string service = null)
public static AS_REQ NewASReq(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, bool opsec = false, bool changepw = false, bool pac = true, string service = null, string principalType = "principal")
{
// build a new AS-REQ for the given userName, domain, and etype, w/ PA-ENC-TIMESTAMP
// used for "legit" AS-REQs w/ pre-auth
Expand All @@ -98,7 +99,8 @@ public static AS_REQ NewASReq(string userName, string domain, string keyString,
// req.padata.Add()

// set the username to request a TGT for
req.req_body.cname.name_string.Add(userName);
req.req_body.cname.name_string.AddRange(userName.Split('/'));
req.req_body.cname.name_type = Helpers.StringToPrincipalType(principalType);

// the realm (domain) the user exists in
req.req_body.realm = domain;
Expand Down Expand Up @@ -159,18 +161,17 @@ public static AS_REQ NewASReq(string userName, string domain, string keyString,
}

//TODO: Insert DHKeyPair parameter also.
public static AS_REQ NewASReq(string userName, string domain, X509Certificate2 cert, KDCKeyAgreement agreement, Interop.KERB_ETYPE etype, bool verifyCerts = false, string service = null, bool changepw = false) {
public static AS_REQ NewASReq(string userName, string domain, X509Certificate2 cert, KDCKeyAgreement agreement, Interop.KERB_ETYPE etype, bool verifyCerts = false, string service = null, bool changepw = false, string principalType = "principal") {

// build a new AS-REQ for the given userName, domain, and etype, w/ PA-ENC-TIMESTAMP
// used for "legit" AS-REQs w/ pre-auth

// set pre-auth
AS_REQ req = new AS_REQ(cert, agreement, verifyCerts);

// req.padata.Add()

// set the username to request a TGT for
req.req_body.cname.name_string.Add(userName);
req.req_body.cname.name_string.AddRange(userName.Split('/'));
req.req_body.cname.name_type = Helpers.StringToPrincipalType(principalType);

// the realm (domain) the user exists in
req.req_body.realm = domain;
Expand Down

0 comments on commit 9241312

Please sign in to comment.