Merge pull request #15 from qlemaire/master

Add "/password" support to "asktgt" command
master
Will 2019-02-05 11:57:19 -08:00 committed by GitHub
commit 7f9d25ea8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 7 deletions

View File

@ -12,6 +12,7 @@ namespace Rubeus.Commands
{ {
string user = ""; string user = "";
string domain = ""; string domain = "";
string password = "";
string hash = ""; string hash = "";
string dc = ""; string dc = "";
bool ptt = false; bool ptt = false;
@ -39,6 +40,28 @@ namespace Rubeus.Commands
{ {
dc = arguments["/dc"]; dc = arguments["/dc"];
} }
if (arguments.ContainsKey("/password"))
{
password = arguments["/password"];
if (arguments.ContainsKey("/enctype") && arguments["/enctype"].ToUpper().Equals("AES256"))
{
encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1;
// compute AES key from pwd
byte[] password_bytes = System.Text.Encoding.UTF8.GetBytes(password);
byte[] salt = System.Text.Encoding.UTF8.GetBytes(domain.ToUpper() + user);
byte[] aes256_key = Crypto.ComputeAES256KerberosKey(password_bytes, salt);
hash = System.BitConverter.ToString(aes256_key).Replace("-", "");
}
else // default is RC4
{
// compute NTLM from pwd
encType = Interop.KERB_ETYPE.rc4_hmac;
byte[] ntlm = Crypto.ComputeRC4KerberosKey(password); // a.k.a NTLM
hash = System.BitConverter.ToString(ntlm).Replace("-", "");
}
}
if (arguments.ContainsKey("/rc4")) if (arguments.ContainsKey("/rc4"))
{ {
hash = arguments["/rc4"]; hash = arguments["/rc4"];
@ -104,7 +127,7 @@ namespace Rubeus.Commands
} }
if (String.IsNullOrEmpty(hash)) if (String.IsNullOrEmpty(hash))
{ {
Console.WriteLine("\r\n[X] You must supply a /rc4 or /aes256 hash!\r\n"); Console.WriteLine("\r\n[X] You must supply a /password or /rc4 hash or /aes256 hash!\r\n");
return; return;
} }

View File

@ -19,11 +19,11 @@ namespace Rubeus.Domain
{ {
Console.WriteLine("\r\n Rubeus usage:"); Console.WriteLine("\r\n Rubeus usage:");
Console.WriteLine("\r\n Retrieve a TGT based on a user hash, optionally applying to the current logon session or a specific LUID:"); Console.WriteLine("\r\n Retrieve a TGT based on a user password/hash, optionally applying to the current logon session or a specific LUID:");
Console.WriteLine(" Rubeus.exe asktgt /user:USER </rc4:HASH | /aes256:HASH> [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/ptt] [/luid]"); Console.WriteLine(" Rubeus.exe asktgt /user:USER </password:PASSWORD [/enctype:RC4|AES256] | /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("\r\n Retrieve a TGT based on a user password/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(" Rubeus.exe asktgt /user:USER </password:PASSWORD [/enctype:RC4|AES256] |/rc4:HASH | /aes256:HASH> /createnetonly:C:\\Windows\\System32\\cmd.exe [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER]");
Console.WriteLine("\r\n Retrieve a service ticket for one or more SPNs, optionally applying the ticket:"); 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(" Rubeus.exe asktgs </ticket:BASE64 | /ticket:FILE.KIRBI> </service:SPN1,SPN2,...> [/dc:DOMAIN_CONTROLLER] [/ptt]");

View File

@ -1,6 +1,5 @@
using System; using System;
using Asn1; using System.Linq;
using System.Text;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.ComponentModel; using System.ComponentModel;
@ -9,6 +8,81 @@ namespace Rubeus
{ {
public class Crypto public class Crypto
{ {
// Adapted from Kevin-Robertson powershell Get-KerberosAESKey: https://gist.github.com/Kevin-Robertson/9e0f8bfdbf4c1e694e6ff4197f0a4372
// References:
// * [MS-KILE] open spec' https://msdn.microsoft.com/library/cc233855.aspx?f=255&MSPPError=-2147217396
// * RFC regarding AES in Kerberos https://www.rfc-editor.org/rfc/pdfrfc/rfc3962.txt.pdf
public static byte[] ComputeAES256KerberosKey(byte[] password, byte[] salt)
{
byte[] AES256_CONSTANT = { 0x6B, 0x65, 0x72, 0x62, 0x65, 0x72, 0x6F, 0x73, 0x7B, 0x9B, 0x5B, 0x2B, 0x93, 0x13, 0x2B, 0x93, 0x5C, 0x9B, 0xDC, 0xDA, 0xD9, 0x5C, 0x98, 0x99, 0xC4, 0xCA, 0xE4, 0xDE, 0xE6, 0xD6, 0xCA, 0xE4 };
const int rounds = 4096;
var pbkdf2 = new System.Security.Cryptography.Rfc2898DeriveBytes(password, salt, rounds);
byte[] pbkdf2_aes256_key = pbkdf2.GetBytes(32);
string pbkdf2_aes256_key_string = System.BitConverter.ToString(pbkdf2_aes256_key).Replace("-", "");
var aes = new System.Security.Cryptography.AesManaged();
aes.Mode = System.Security.Cryptography.CipherMode.CBC;
aes.Padding = System.Security.Cryptography.PaddingMode.None;
aes.KeySize = 256;
aes.Key = pbkdf2_aes256_key;
aes.IV = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
var encryptor = aes.CreateEncryptor();
byte[] aes256_key_part_1 = encryptor.TransformFinalBlock(AES256_CONSTANT, 0, AES256_CONSTANT.Length);
byte[] aes256_key_part_2 = encryptor.TransformFinalBlock(aes256_key_part_1, 0, aes256_key_part_1.Length);
byte[] aes256_key = aes256_key_part_1.Take(16).Concat(aes256_key_part_2.Take(16)).ToArray();
return aes256_key;
}
public static byte[] ComputeRC4KerberosKey(string password)
{
// RC4 Kerberos Key is NTLM
byte[] password_byte = System.Text.Encoding.Unicode.GetBytes(password);
return ComputeMD4(password_byte);
}
// source: https://rosettacode.org/wiki/MD4#C.23
private static byte[] ComputeMD4(byte[] plain)
{
// get padded uints from bytes
List<byte> bytes = plain.ToList();
uint bitCount = (uint)(bytes.Count) * 8;
bytes.Add(128);
while (bytes.Count % 64 != 56) bytes.Add(0);
var uints = new List<uint>();
for (int i = 0; i + 3 < bytes.Count; i += 4)
uints.Add(bytes[i] | (uint)bytes[i + 1] << 8 | (uint)bytes[i + 2] << 16 | (uint)bytes[i + 3] << 24);
uints.Add(bitCount);
uints.Add(0);
// run rounds
uint a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476;
Func<uint, uint, uint> rol = (x, y) => x << (int)y | x >> 32 - (int)y;
for (int q = 0; q + 15 < uints.Count; q += 16)
{
var chunk = uints.GetRange(q, 16);
uint aa = a, bb = b, cc = c, dd = d;
Action<Func<uint, uint, uint, uint>, uint[]> round = (f, y) =>
{
foreach (uint i in new[] { y[0], y[1], y[2], y[3] })
{
a = rol(a + f(b, c, d) + chunk[(int)(i + y[4])] + y[12], y[8]);
d = rol(d + f(a, b, c) + chunk[(int)(i + y[5])] + y[12], y[9]);
c = rol(c + f(d, a, b) + chunk[(int)(i + y[6])] + y[12], y[10]);
b = rol(b + f(c, d, a) + chunk[(int)(i + y[7])] + y[12], y[11]);
}
};
round((x, y, z) => (x & y) | (~x & z), new uint[] { 0, 4, 8, 12, 0, 1, 2, 3, 3, 7, 11, 19, 0 });
round((x, y, z) => (x & y) | (x & z) | (y & z), new uint[] { 0, 1, 2, 3, 0, 4, 8, 12, 3, 5, 9, 13, 0x5a827999 });
round((x, y, z) => x ^ y ^ z, new uint[] { 0, 2, 1, 3, 0, 8, 4, 12, 3, 9, 11, 15, 0x6ed9eba1 });
a += aa; b += bb; c += cc; d += dd;
}
// return hex encoded string
byte[] outBytes = new[] { a, b, c, d }.SelectMany(BitConverter.GetBytes).ToArray();
return outBytes;
}
// Adapted from Vincent LE TOUX' "MakeMeEnterpriseAdmin" // Adapted from Vincent LE TOUX' "MakeMeEnterpriseAdmin"
public static byte[] KerberosChecksum(byte[] key, byte[] data) public static byte[] KerberosChecksum(byte[] key, byte[] data)
{ {