diff --git a/Rubeus/Commands/Asktgs.cs b/Rubeus/Commands/Asktgs.cs new file mode 100644 index 0000000..6b93cd0 --- /dev/null +++ b/Rubeus/Commands/Asktgs.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Rubeus.Commands +{ + public class Asktgs : ICommand + { + public static string CommandName => "asktgs"; + + public void Execute(Dictionary arguments) + { + + bool ptt = false; + string dc = ""; + string service = ""; + + if (arguments.ContainsKey("/ptt")) + { + ptt = true; + } + + if (arguments.ContainsKey("/dc")) + { + dc = arguments["/dc"]; + } + + if (arguments.ContainsKey("/service")) + { + service = arguments["/service"]; + } + else + { + Console.WriteLine("[X] One or more '/service:sname/server.domain.com' specifications are needed"); + return; + } + + if (arguments.ContainsKey("/ticket")) + { + string kirbi64 = arguments["/ticket"]; + + if (Helpers.IsBase64String(kirbi64)) + { + byte[] kirbiBytes = Convert.FromBase64String(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + Ask.TGS(kirbi, service, ptt, dc, true); + return; + } + else if (File.Exists(kirbi64)) + { + byte[] kirbiBytes = File.ReadAllBytes(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + Ask.TGS(kirbi, service, ptt, dc, true); + return; + } + else + { + Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); + } + return; + } + else + { + Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); + return; + } + } + } +} \ No newline at end of file diff --git a/Rubeus/Commands/Asktgt.cs b/Rubeus/Commands/Asktgt.cs new file mode 100644 index 0000000..c287c30 --- /dev/null +++ b/Rubeus/Commands/Asktgt.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; + + +namespace Rubeus.Commands +{ + public class Asktgt : ICommand + { + public static string CommandName => "asktgt"; + + public void Execute(Dictionary arguments) + { + + string user = ""; + string domain = ""; + string hash = ""; + string dc = ""; + bool ptt = false; + uint luid = 0; + Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; + + if (arguments.ContainsKey("/user")) + { + user = arguments["/user"]; + } + if (arguments.ContainsKey("/domain")) + { + domain = arguments["/domain"]; + } + if (arguments.ContainsKey("/dc")) + { + dc = arguments["/dc"]; + } + if (arguments.ContainsKey("/rc4")) + { + hash = arguments["/rc4"]; + encType = Interop.KERB_ETYPE.rc4_hmac; + } + if (arguments.ContainsKey("/aes256")) + { + hash = arguments["/aes256"]; + encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; + } + if (arguments.ContainsKey("/ptt")) + { + ptt = true; + } + + if (arguments.ContainsKey("/luid")) + { + try + { + luid = UInt32.Parse(arguments["/luid"]); + } + catch + { + try + { + luid = Convert.ToUInt32(arguments["/luid"], 16); + } + catch + { + Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/LUID"]); + return; + } + } + } + + if (arguments.ContainsKey("/createnetonly")) + { + // if we're starting a hidden process to apply the ticket to + if (!Helpers.IsHighIntegrity()) + { + Console.WriteLine("[X] You need to be in high integrity to apply a ticket to created logon session"); + return; + } + if (arguments.ContainsKey("/show")) + { + luid = LSA.CreateProcessNetOnly(arguments["/createnetonly"], true); + } + else + { + luid = LSA.CreateProcessNetOnly(arguments["/createnetonly"], false); + } + Console.WriteLine(); + } + + if (String.IsNullOrEmpty(user)) + { + Console.WriteLine("\r\n[X] You must supply a user name!\r\n"); + return; + } + if (String.IsNullOrEmpty(domain)) + { + domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; + } + if (String.IsNullOrEmpty(hash)) + { + Console.WriteLine("\r\n[X] You must supply a /rc4 or /aes256 hash!\r\n"); + return; + } + + if (!((encType == Interop.KERB_ETYPE.rc4_hmac) || (encType == Interop.KERB_ETYPE.aes256_cts_hmac_sha1))) + { + Console.WriteLine("\r\n[X] Only /rc4 and /aes256 are supported at this time.\r\n"); + return; + } + else + { + Ask.TGT(user, domain, hash, encType, ptt, dc, luid); + return; + } + + + + + + + + + + } + } +} \ No newline at end of file diff --git a/Rubeus/Commands/Asreproast.cs b/Rubeus/Commands/Asreproast.cs new file mode 100644 index 0000000..75e7eea --- /dev/null +++ b/Rubeus/Commands/Asreproast.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; + +namespace Rubeus.Commands +{ + public class Asreproast : ICommand + { + public static string CommandName => "asreproast"; + + public void Execute(Dictionary arguments) + { + + string user = ""; + string domain = ""; + string dc = ""; + string format = "john"; + + if (arguments.ContainsKey("/user")) + { + user = arguments["/user"]; + } + if (arguments.ContainsKey("/domain")) + { + domain = arguments["/domain"]; + } + if (arguments.ContainsKey("/dc")) + { + dc = arguments["/dc"]; + } + if (arguments.ContainsKey("/format")) + { + format = arguments["/format"]; + } + + if (String.IsNullOrEmpty(user)) + { + Console.WriteLine("\r\n[X] You must supply a user name!\r\n"); + return; + } + if (String.IsNullOrEmpty(domain)) + { + domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; + } + + if (String.IsNullOrEmpty(dc)) + { + Roast.ASRepRoast(user, domain, "", format); + } + else + { + Roast.ASRepRoast(user, domain, dc, format); + } + + } + + + } +} \ No newline at end of file diff --git a/Rubeus/Commands/Changepw.cs b/Rubeus/Commands/Changepw.cs new file mode 100644 index 0000000..952b71a --- /dev/null +++ b/Rubeus/Commands/Changepw.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.IO; + + +namespace Rubeus.Commands +{ + public class Changepw : ICommand + { + public static string CommandName => "changepw"; + + public void Execute(Dictionary arguments) + { + + + string newPassword = ""; + string dc = ""; + + if (arguments.ContainsKey("/new")) + { + newPassword = arguments["/new"]; + } + if (String.IsNullOrEmpty(newPassword)) + { + Console.WriteLine("\r\n[X] New password must be supplied with /new:X !\r\n"); + return; + } + + if (arguments.ContainsKey("/dc")) + { + dc = arguments["/dc"]; + } + + if (arguments.ContainsKey("/ticket")) + { + string kirbi64 = arguments["/ticket"]; + + if (Helpers.IsBase64String(kirbi64)) + { + byte[] kirbiBytes = Convert.FromBase64String(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + Reset.UserPassword(kirbi, newPassword, dc); + } + else if (File.Exists(kirbi64)) + { + byte[] kirbiBytes = File.ReadAllBytes(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + Reset.UserPassword(kirbi, newPassword, dc); + } + else + { + Console.WriteLine("\r\n[X]/ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); + } + return; + } + else + { + Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); + return; + } + + + + + + + + + + + } + } +} \ No newline at end of file diff --git a/Rubeus/Commands/Createnetonly.cs b/Rubeus/Commands/Createnetonly.cs new file mode 100644 index 0000000..9c4cae5 --- /dev/null +++ b/Rubeus/Commands/Createnetonly.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; + + +namespace Rubeus.Commands +{ + public class Createnetonly : ICommand + { + public static string CommandName => "createnetonly"; + + public void Execute(Dictionary arguments) + { + + + if (arguments.ContainsKey("/program")) + { + if (arguments.ContainsKey("/show")) + { + LSA.CreateProcessNetOnly(arguments["/program"], true); + } + else + { + LSA.CreateProcessNetOnly(arguments["/program"]); + } + } + + else + { + Console.WriteLine("\r\n[X] A /program needs to be supplied!\r\n"); + } + + + } + } +} diff --git a/Rubeus/Commands/Describe.cs b/Rubeus/Commands/Describe.cs new file mode 100644 index 0000000..a01c458 --- /dev/null +++ b/Rubeus/Commands/Describe.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.IO; + + +namespace Rubeus.Commands +{ + public class Describe : ICommand + { + public static string CommandName => "describe"; + + public void Execute(Dictionary arguments) + { + + if (arguments.ContainsKey("/ticket")) + { + string kirbi64 = arguments["/ticket"]; + + if (Helpers.IsBase64String(kirbi64)) + { + byte[] kirbiBytes = Convert.FromBase64String(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + LSA.DisplayTicket(kirbi); + } + else if (File.Exists(kirbi64)) + { + byte[] kirbiBytes = File.ReadAllBytes(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + LSA.DisplayTicket(kirbi); + } + else + { + Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); + } + return; + } + else + { + Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); + return; + } + + + } + } +} diff --git a/Rubeus/Commands/Dump.cs b/Rubeus/Commands/Dump.cs new file mode 100644 index 0000000..c3b1a4b --- /dev/null +++ b/Rubeus/Commands/Dump.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; + + +namespace Rubeus.Commands +{ + public class Dump : ICommand + { + public static string CommandName => "dump"; + + public void Execute(Dictionary arguments) + { + + + if (arguments.ContainsKey("/luid")) + { + string service = ""; + if (arguments.ContainsKey("/service")) + { + service = arguments["/service"]; + } + UInt32 luid = 0; + try + { + luid = UInt32.Parse(arguments["/luid"]); + } + catch + { + try + { + luid = Convert.ToUInt32(arguments["/luid"], 16); + } + catch + { + Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/LUID"]); + return; + } + } + LSA.ListKerberosTicketData(luid, service); + } + else if (arguments.ContainsKey("/service")) + { + LSA.ListKerberosTicketData(0, arguments["/service"]); + } + else + { + LSA.ListKerberosTicketData(); + } + + + + + + + } + } +} \ No newline at end of file diff --git a/Rubeus/Commands/HarvestCommand.cs b/Rubeus/Commands/HarvestCommand.cs new file mode 100644 index 0000000..9f4fe41 --- /dev/null +++ b/Rubeus/Commands/HarvestCommand.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace Rubeus.Commands +{ + public class HarvestCommand : ICommand + { + public static string CommandName => "harvest"; + + public void Execute(Dictionary arguments) + { + int intervalMinutes = 60; + if (arguments.ContainsKey("/interval")) + { + intervalMinutes = Int32.Parse(arguments["/interval"]); + } + + Harvest.HarvestTGTs(intervalMinutes); + + } + + + } +} diff --git a/Rubeus/Commands/ICommand.cs b/Rubeus/Commands/ICommand.cs new file mode 100644 index 0000000..60d217e --- /dev/null +++ b/Rubeus/Commands/ICommand.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Rubeus.Commands +{ + public interface ICommand + { + void Execute(Dictionary arguments); + + } +} \ No newline at end of file diff --git a/Rubeus/Commands/Kerberoast.cs b/Rubeus/Commands/Kerberoast.cs new file mode 100644 index 0000000..b1e5740 --- /dev/null +++ b/Rubeus/Commands/Kerberoast.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Rubeus.Commands +{ + public class Kerberoast : ICommand + { + public static string CommandName => "kerberoast"; + + public void Execute(Dictionary arguments) + { + + + string spn = ""; + string user = ""; + string OU = ""; + + if (arguments.ContainsKey("/spn")) + { + spn = arguments["/spn"]; + } + if (arguments.ContainsKey("/user")) + { + user = arguments["/user"]; + } + if (arguments.ContainsKey("/ou")) + { + OU = arguments["/ou"]; + } + + if (arguments.ContainsKey("/creduser")) + { + if (!Regex.IsMatch(arguments["/creduser"], ".+\\.+", RegexOptions.IgnoreCase)) + { + Console.WriteLine("\r\n[X] /creduser specification must be in fqdn format (domain.com\\user)\r\n"); + return; + } + + string[] parts = arguments["/creduser"].Split('\\'); + string domainName = parts[0]; + string userName = parts[1]; + + if (!arguments.ContainsKey("/credpassword")) + { + Console.WriteLine("\r\n[X] /credpassword is required when specifying /creduser\r\n"); + return; + } + + string password = arguments["/credpassword"]; + + System.Net.NetworkCredential cred = new System.Net.NetworkCredential(userName, password, domainName); + + Roast.Kerberoast(spn, user, OU, cred); + } + else + { + Roast.Kerberoast(spn, user, OU); + } + + + + + + } + } +} \ No newline at end of file diff --git a/Rubeus/Commands/Monitor.cs b/Rubeus/Commands/Monitor.cs new file mode 100644 index 0000000..b247e7c --- /dev/null +++ b/Rubeus/Commands/Monitor.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; + +namespace Rubeus.Commands +{ + public class Monitor : ICommand + { + public static string CommandName => "monitor"; + + public void Execute(Dictionary arguments) + { + + + string targetUser = ""; + int interval = 60; + if (arguments.ContainsKey("/filteruser")) + { + targetUser = arguments["/filteruser"]; + } + if (arguments.ContainsKey("/interval")) + { + interval = Int32.Parse(arguments["/interval"]); + } + Harvest.Monitor4624(interval, targetUser); + + + + } + } +} \ No newline at end of file diff --git a/Rubeus/Commands/Ptt.cs b/Rubeus/Commands/Ptt.cs new file mode 100644 index 0000000..8fa9900 --- /dev/null +++ b/Rubeus/Commands/Ptt.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Rubeus.Commands +{ + public class Ptt : ICommand + { + public static string CommandName => "ptt"; + + public void Execute(Dictionary arguments) + { + + uint luid = 0; + if (arguments.ContainsKey("/luid")) + { + try + { + luid = UInt32.Parse(arguments["/luid"]); + } + catch + { + try + { + luid = Convert.ToUInt32(arguments["/luid"], 16); + } + catch + { + Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/LUID"]); + return; + } + } + } + + if (arguments.ContainsKey("/ticket")) + { + string kirbi64 = arguments["/ticket"]; + + if (Helpers.IsBase64String(kirbi64)) + { + byte[] kirbiBytes = Convert.FromBase64String(kirbi64); + LSA.ImportTicket(kirbiBytes, luid); + } + else if (File.Exists(kirbi64)) + { + byte[] kirbiBytes = File.ReadAllBytes(kirbi64); + LSA.ImportTicket(kirbiBytes, luid); + } + else + { + Console.WriteLine("\r\n[X]/ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); + } + return; + } + else + { + Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); + return; + } + } + + } +} \ No newline at end of file diff --git a/Rubeus/Commands/Purge.cs b/Rubeus/Commands/Purge.cs new file mode 100644 index 0000000..2339d67 --- /dev/null +++ b/Rubeus/Commands/Purge.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; + + +namespace Rubeus.Commands +{ + public class Purge : ICommand + { + public static string CommandName => "purge"; + + public void Execute(Dictionary arguments) + { + + uint luid = 0; + if (arguments.ContainsKey("/luid")) + { + try + { + luid = UInt32.Parse(arguments["/luid"]); + } + catch + { + try + { + luid = Convert.ToUInt32(arguments["/luid"], 16); + } + catch + { + Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/LUID"]); + return; + } + } + } + + LSA.Purge(luid); + + } + } +} \ No newline at end of file diff --git a/Rubeus/Commands/RenewCommand.cs b/Rubeus/Commands/RenewCommand.cs new file mode 100644 index 0000000..dbb5f6a --- /dev/null +++ b/Rubeus/Commands/RenewCommand.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.IO; + + +namespace Rubeus.Commands +{ + public class RenewCommand : ICommand + { + public static string CommandName => "renew"; + + public void Execute(Dictionary arguments) + { + + bool ptt = false; + string dc = ""; + + if (arguments.ContainsKey("/ptt")) + { + ptt = true; + } + + if (arguments.ContainsKey("/dc")) + { + dc = arguments["/dc"]; + } + + if (arguments.ContainsKey("/ticket")) + { + string kirbi64 = arguments["/ticket"]; + + if (Helpers.IsBase64String(kirbi64)) + { + byte[] kirbiBytes = Convert.FromBase64String(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + if (arguments.ContainsKey("/autorenew")) + { + // if we want to auto-renew the TGT up until the renewal limit + Renew.TGTAutoRenew(kirbi, dc); + } + else + { + // otherwise a single renew operation + byte[] blah = Renew.TGT(kirbi, ptt, dc); + } + } + else if (File.Exists(kirbi64)) + { + byte[] kirbiBytes = File.ReadAllBytes(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + if (arguments.ContainsKey("/autorenew")) + { + // if we want to auto-renew the TGT up until the renewal limit + Renew.TGTAutoRenew(kirbi, dc); + } + else + { + // otherwise a single renew operation + byte[] blah = Renew.TGT(kirbi, ptt, dc); + } + } + else + { + Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); + } + return; + } + else + { + Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); + return; + } + + + } + } +} \ No newline at end of file diff --git a/Rubeus/Commands/S4u.cs b/Rubeus/Commands/S4u.cs new file mode 100644 index 0000000..1a4e29c --- /dev/null +++ b/Rubeus/Commands/S4u.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Rubeus.Commands +{ + public class S4u : ICommand + { + public static string CommandName => "s4u"; + + public void Execute(Dictionary arguments) + { + + + + string targetUser = ""; + string targetSPN = ""; + string altSname = ""; + string user = ""; + string domain = ""; + string hash = ""; + bool ptt = false; + string dc = ""; + Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; + + if (arguments.ContainsKey("/user")) + { + user = arguments["/user"]; + } + if (arguments.ContainsKey("/domain")) + { + domain = arguments["/domain"]; + } + if (arguments.ContainsKey("/ptt")) + { + ptt = true; + } + if (arguments.ContainsKey("/dc")) + { + dc = arguments["/dc"]; + } + if (arguments.ContainsKey("/rc4")) + { + hash = arguments["/rc4"]; + encType = Interop.KERB_ETYPE.rc4_hmac; + } + if (arguments.ContainsKey("/aes256")) + { + hash = arguments["/aes256"]; + encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; + } + if (arguments.ContainsKey("/impersonateuser")) + { + targetUser = arguments["/impersonateuser"]; + } + + if (arguments.ContainsKey("/msdsspn")) + { + targetSPN = arguments["/msdsspn"]; + } + + if (arguments.ContainsKey("/altservice")) + { + altSname = arguments["/altservice"]; + } + + if (String.IsNullOrEmpty(targetUser)) + { + Console.WriteLine("\r\n[X] You must supply a /impersonateuser to impersonate!\r\n"); + return; + } + if (String.IsNullOrEmpty(targetSPN)) + { + Console.WriteLine("\r\n[X] You must supply a /msdsspn !\r\n"); + return; + } + + if (arguments.ContainsKey("/ticket")) + { + string kirbi64 = arguments["/ticket"]; + + if (Helpers.IsBase64String(kirbi64)) + { + byte[] kirbiBytes = Convert.FromBase64String(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + S4U.Execute(kirbi, targetUser, targetSPN, ptt, dc, altSname); + } + else if (File.Exists(kirbi64)) + { + byte[] kirbiBytes = File.ReadAllBytes(kirbi64); + KRB_CRED kirbi = new KRB_CRED(kirbiBytes); + S4U.Execute(kirbi, targetUser, targetSPN, ptt, dc, altSname); + } + else + { + Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); + } + return; + } + else if (arguments.ContainsKey("/user")) + { + // if the user is supplying a user and rc4/aes256 hash to first execute a TGT request + + user = arguments["/user"]; + + if (String.IsNullOrEmpty(hash)) + { + Console.WriteLine("\r\n[X] You must supply a /rc4 or /aes256 hash!\r\n"); + return; + } + + S4U.Execute(user, domain, hash, encType, targetUser, targetSPN, ptt, dc, altSname); + return; + } + else + { + Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied for S4U!\r\n"); + Console.WriteLine("[X] Alternatively, supply a /user and hash to first retrieve a TGT.\r\n"); + return; + } + + + + + + + + + + + } + } +} \ No newline at end of file diff --git a/Rubeus/Commands/Tgtdeleg.cs b/Rubeus/Commands/Tgtdeleg.cs new file mode 100644 index 0000000..25f869c --- /dev/null +++ b/Rubeus/Commands/Tgtdeleg.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + + +namespace Rubeus.Commands +{ + public class Tgtdeleg : ICommand + { + public static string CommandName => "tgtdeleg"; + + public void Execute(Dictionary arguments) + { + + if (arguments.ContainsKey("/target")) + { + byte[] blah = LSA.RequestFakeDelegTicket(arguments["/target"]); + } + else + { + byte[] blah = LSA.RequestFakeDelegTicket(); + } + + + } + } +} \ No newline at end of file diff --git a/Rubeus/Domain/ArgumentParser.cs b/Rubeus/Domain/ArgumentParser.cs new file mode 100644 index 0000000..21d44bc --- /dev/null +++ b/Rubeus/Domain/ArgumentParser.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace Rubeus.Domain +{ + public static class ArgumentParser + { + public static ArgumentParserResult Parse(IEnumerable args) + { + var arguments = new Dictionary(); + try + { + + foreach (var argument in args) + { + var idx = argument.IndexOf(':'); + if (idx > 0) + arguments[argument.Substring(0, idx)] = argument.Substring(idx + 1); + else + arguments[argument] = string.Empty; + } + + return ArgumentParserResult.Success(arguments); + } + catch (System.Exception ex) + { + Debug.WriteLine(ex.Message); + return ArgumentParserResult.Failure(); + } + } + + } +} diff --git a/Rubeus/Domain/ArgumentParserResult.cs b/Rubeus/Domain/ArgumentParserResult.cs new file mode 100644 index 0000000..8fb701a --- /dev/null +++ b/Rubeus/Domain/ArgumentParserResult.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Rubeus.Domain +{ + public class ArgumentParserResult + { + public bool ParsedOk { get; } + public Dictionary Arguments { get; } + + private ArgumentParserResult(bool parsedOk, Dictionary arguments) + { + ParsedOk = parsedOk; + Arguments = arguments; + } + + + public static ArgumentParserResult Success(Dictionary arguments) + => new ArgumentParserResult(true, arguments); + + public static ArgumentParserResult Failure() + => new ArgumentParserResult(false, null); + + } +} \ No newline at end of file diff --git a/Rubeus/Domain/CommandCollection.cs b/Rubeus/Domain/CommandCollection.cs new file mode 100644 index 0000000..29c6f62 --- /dev/null +++ b/Rubeus/Domain/CommandCollection.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Rubeus.Commands; + +namespace Rubeus.Domain +{ + public class CommandCollection + { + + private readonly Dictionary> _availableCommands = new Dictionary>(); + + // How To Add A New Command: + // 1. Create your command class in the Commands Folder + // 2. That class must have a CommandName static property that has the Command's name + // and must also Implement the ICommand interface + // 3. Put the code that does the work into the Execute() method + // 4. Add an entry to the _availableCommands dictionary in the Constructor below. + + public CommandCollection() + { + _availableCommands.Add(Asktgs.CommandName, () => new Asktgs()); + _availableCommands.Add(Asktgt.CommandName, () => new Asktgt()); + _availableCommands.Add(Asreproast.CommandName, () => new Asreproast()); + _availableCommands.Add(Changepw.CommandName, () => new Changepw()); + _availableCommands.Add(Createnetonly.CommandName, () => new Createnetonly()); + _availableCommands.Add(Describe.CommandName, () => new Describe()); + _availableCommands.Add(Dump.CommandName, () => new Dump()); + _availableCommands.Add(HarvestCommand.CommandName, () => new HarvestCommand()); + _availableCommands.Add(Kerberoast.CommandName, () => new Kerberoast()); + _availableCommands.Add(Monitor.CommandName, () => new Monitor()); + _availableCommands.Add(Ptt.CommandName, () => new Ptt()); + _availableCommands.Add(Purge.CommandName, () => new Purge()); + _availableCommands.Add(RenewCommand.CommandName, () => new RenewCommand()); + _availableCommands.Add(S4u.CommandName, () => new S4u()); + _availableCommands.Add(Tgtdeleg.CommandName, () => new Tgtdeleg()); + } + + public bool ExecuteCommand(string commandName, Dictionary arguments) + { + bool commandWasFound; + + if (string.IsNullOrEmpty(commandName) || _availableCommands.ContainsKey(commandName) == false) + commandWasFound= false; + else + { + // Create the command object + var command = _availableCommands[commandName].Invoke(); + + // and execute it with the arguments from the command line + command.Execute(arguments); + + commandWasFound = true; + } + + return commandWasFound; + } + + } +} \ No newline at end of file diff --git a/Rubeus/Domain/Info.cs b/Rubeus/Domain/Info.cs new file mode 100644 index 0000000..22ba755 --- /dev/null +++ b/Rubeus/Domain/Info.cs @@ -0,0 +1,85 @@ +using System; + +namespace Rubeus.Domain +{ + public static class Info + { + public static void ShowLogo() + { + Console.WriteLine("\r\n ______ _ "); + Console.WriteLine(" (_____ \\ | | "); + Console.WriteLine(" _____) )_ _| |__ _____ _ _ ___ "); + Console.WriteLine(" | __ /| | | | _ \\| ___ | | | |/___)"); + Console.WriteLine(" | | \\ \\| |_| | |_) ) ____| |_| |___ |"); + Console.WriteLine(" |_| |_|____/|____/|_____)____/(___/\r\n"); + Console.WriteLine(" v1.2.0\r\n"); + } + + + public static void ShowUsage() + { + Console.WriteLine("\r\n Rubeus usage:"); + + Console.WriteLine("\r\n Retrieve a TGT based on a user hash, optionally applying to the current logon session or a specific LUID:"); + Console.WriteLine(" Rubeus.exe asktgt /user:USER [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/ptt] [/luid]"); + + Console.WriteLine("\r\n Retrieve a TGT based on a user hash, start a /netonly process, and to apply the ticket to the new process/logon session:"); + Console.WriteLine(" Rubeus.exe asktgt /user:USER /createnetonly:C:\\Windows\\System32\\cmd.exe [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER]"); + + Console.WriteLine("\r\n Retrieve a service ticket for one or more SPNs, optionally applying the ticket:"); + Console.WriteLine(" Rubeus.exe asktgs [/dc:DOMAIN_CONTROLLER] [/ptt]"); + + Console.WriteLine("\r\n Renew a TGT, optionally applying the ticket or auto-renewing the ticket up to its renew-till limit:"); + Console.WriteLine(" Rubeus.exe renew [/dc:DOMAIN_CONTROLLER] [/ptt] [/autorenew]"); + + Console.WriteLine("\r\n Reset a user's password from a supplied TGT (AoratoPw):"); + Console.WriteLine(" Rubeus.exe changepw /new:PASSWORD [/dc:DOMAIN_CONTROLLER]"); + + Console.WriteLine("\r\n Perform S4U constrained delegation abuse:"); + Console.WriteLine(" Rubeus.exe s4u /impersonateuser:USER /msdsspn:SERVICE/SERVER [/altservice:SERVICE] [/dc:DOMAIN_CONTROLLER] [/ptt]"); + Console.WriteLine(" Rubeus.exe s4u /user:USER [/domain:DOMAIN] /impersonateuser:USER /msdsspn:SERVICE/SERVER [/altservice:SERVICE] [/dc:DOMAIN_CONTROLLER] [/ptt]"); + + Console.WriteLine("\r\n Submit a TGT, optionally targeting a specific LUID (if elevated):"); + Console.WriteLine(" Rubeus.exe ptt [/luid:LOGINID]"); + + Console.WriteLine("\r\n Purge tickets from the current logon session, optionally targeting a specific LUID (if elevated):"); + Console.WriteLine(" Rubeus.exe purge [/luid:LOGINID]"); + + Console.WriteLine("\r\n Parse and describe a ticket (service ticket or TGT):"); + Console.WriteLine(" Rubeus.exe describe "); + + Console.WriteLine("\r\n Create a hidden program (unless /show is passed) with random /netonly credentials, displaying the PID and LUID:"); + Console.WriteLine(" Rubeus.exe createnetonly /program:\"C:\\Windows\\System32\\cmd.exe\" [/show]"); + + Console.WriteLine("\r\n Perform Kerberoasting:"); + Console.WriteLine(" Rubeus.exe kerberoast [/spn:\"blah/blah\"] [/user:USER] [/ou:\"OU,...\"]"); + + Console.WriteLine("\r\n Perform Kerberoasting with alternate credentials:"); + Console.WriteLine(" Rubeus.exe kerberoast /creduser:DOMAIN.FQDN\\USER /credpassword:PASSWORD [/spn:\"blah/blah\"] [/user:USER] [/ou:\"OU,...\"]"); + + Console.WriteLine("\r\n Perform AS-REP \"roasting\" for users without preauth:"); + Console.WriteLine(" Rubeus.exe asreproast /user:USER [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER]"); + + Console.WriteLine("\r\n Dump all current ticket data (if elevated, dump for all users), optionally targeting a specific service/LUID:"); + Console.WriteLine(" Rubeus.exe dump [/service:SERVICE] [/luid:LOGINID]"); + + Console.WriteLine("\r\n Retrieve a usable TGT .kirbi for the current user (w/ session key) without elevation by abusing the Kerberos GSS-API, faking delegation:"); + 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("\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("\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"); + } + + + + + } + + +} diff --git a/Rubeus/Program.cs b/Rubeus/Program.cs index 224fd9f..99bed4b 100755 --- a/Rubeus/Program.cs +++ b/Rubeus/Program.cs @@ -1,766 +1,32 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Asn1; -using System.IO; -using System.Text.RegularExpressions; +using Rubeus.Domain; namespace Rubeus { - class Program + public class Program { - public static void Logo() + public static void Main(string[] args) { - System.Console.WriteLine("\r\n ______ _ "); - System.Console.WriteLine(" (_____ \\ | | "); - System.Console.WriteLine(" _____) )_ _| |__ _____ _ _ ___ "); - System.Console.WriteLine(" | __ /| | | | _ \\| ___ | | | |/___)"); - System.Console.WriteLine(" | | \\ \\| |_| | |_) ) ____| |_| |___ |"); - System.Console.WriteLine(" |_| |_|____/|____/|_____)____/(___/\r\n"); - System.Console.WriteLine(" v1.2.0\r\n"); + Info.ShowLogo(); + + // try to parse the command line arguments, show usage on failure and then bail + var parsed = ArgumentParser.Parse(args); + if (parsed.ParsedOk == false) + Info.ShowUsage(); + else + { + // Try to execute the command using the arguments passed in + + var commandName = args.Length != 0 ? args[0] : ""; + + var commandFound = new CommandCollection().ExecuteCommand(commandName, parsed.Arguments); + + // show the usage if no commands were found for the command name + if (commandFound == false) + Info.ShowUsage(); + } + } - public static void Usage() - { - Console.WriteLine("\r\n Rubeus usage:"); - Console.WriteLine("\r\n Retrieve a TGT based on a user hash, optionally applying to the current logon session or a specific LUID:"); - Console.WriteLine(" Rubeus.exe asktgt /user:USER [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/ptt] [/luid]"); - Console.WriteLine("\r\n Retrieve a TGT based on a user hash, start a /netonly process, and to apply the ticket to the new process/logon session:"); - Console.WriteLine(" Rubeus.exe asktgt /user:USER /createnetonly:C:\\Windows\\System32\\cmd.exe [/show] [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER]"); - Console.WriteLine("\r\n Retrieve a service ticket for one or more SPNs, optionally applying the ticket:"); - Console.WriteLine(" Rubeus.exe asktgs [/dc:DOMAIN_CONTROLLER] [/ptt]"); - Console.WriteLine("\r\n Renew a TGT, optionally applying the ticket or auto-renewing the ticket up to its renew-till limit:"); - Console.WriteLine(" Rubeus.exe renew [/dc:DOMAIN_CONTROLLER] [/ptt] [/autorenew]"); - Console.WriteLine("\r\n Reset a user's password from a supplied TGT (AoratoPw):"); - Console.WriteLine(" Rubeus.exe changepw /new:PASSWORD [/dc:DOMAIN_CONTROLLER]"); - Console.WriteLine("\r\n Perform S4U constrained delegation abuse:"); - Console.WriteLine(" Rubeus.exe s4u /impersonateuser:USER /msdsspn:SERVICE/SERVER [/altservice:SERVICE] [/dc:DOMAIN_CONTROLLER] [/ptt]"); - Console.WriteLine(" Rubeus.exe s4u /user:USER [/domain:DOMAIN] /impersonateuser:USER /msdsspn:SERVICE/SERVER [/altservice:SERVICE] [/dc:DOMAIN_CONTROLLER] [/ptt]"); - Console.WriteLine("\r\n Submit a TGT, optionally targeting a specific LUID (if elevated):"); - Console.WriteLine(" Rubeus.exe ptt [/luid:LOGINID]"); - Console.WriteLine("\r\n Purge tickets from the current logon session, optionally targeting a specific LUID (if elevated):"); - Console.WriteLine(" Rubeus.exe purge [/luid:LOGINID]"); - Console.WriteLine("\r\n Parse and describe a ticket (service ticket or TGT):"); - Console.WriteLine(" Rubeus.exe describe "); - Console.WriteLine("\r\n Create a hidden program (unless /show is passed) with random /netonly credentials, displaying the PID and LUID:"); - Console.WriteLine(" Rubeus.exe createnetonly /program:\"C:\\Windows\\System32\\cmd.exe\" [/show]"); - Console.WriteLine("\r\n Perform Kerberoasting:"); - Console.WriteLine(" Rubeus.exe kerberoast [/spn:\"blah/blah\"] [/user:USER] [/ou:\"OU,...\"]"); - Console.WriteLine("\r\n Perform Kerberoasting with alternate credentials:"); - Console.WriteLine(" Rubeus.exe kerberoast /creduser:DOMAIN.FQDN\\USER /credpassword:PASSWORD [/spn:\"blah/blah\"] [/user:USER] [/ou:\"OU,...\"]"); - Console.WriteLine("\r\n Perform AS-REP \"roasting\" for users without preauth:"); - Console.WriteLine(" Rubeus.exe asreproast /user:USER [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER]"); - Console.WriteLine("\r\n Dump all current ticket data (if elevated, dump for all users), optionally targeting a specific service/LUID:"); - Console.WriteLine(" Rubeus.exe dump [/service:SERVICE] [/luid:LOGINID]"); - Console.WriteLine("\r\n Retrieve a usable TGT .kirbi for the current user (w/ session key) without elevation by abusing the Kerberos GSS-API, faking delegation:"); - 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("\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("\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"); - } - - static void Main(string[] args) - { - Logo(); - - var arguments = new Dictionary(); - foreach (string argument in args) - { - int idx = argument.IndexOf(':'); - if (idx > 0) - { - arguments[argument.Substring(0, idx)] = argument.Substring(idx + 1); - } - else - { - arguments[argument] = ""; - } - } - - if (arguments.ContainsKey("asktgt")) - { - string user = ""; - string domain = ""; - string hash = ""; - string dc = ""; - bool ptt = false; - uint luid = 0; - Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; - - if (arguments.ContainsKey("/user")) - { - user = arguments["/user"]; - } - if (arguments.ContainsKey("/domain")) - { - domain = arguments["/domain"]; - } - if (arguments.ContainsKey("/dc")) - { - dc = arguments["/dc"]; - } - if (arguments.ContainsKey("/rc4")) - { - hash = arguments["/rc4"]; - encType = Interop.KERB_ETYPE.rc4_hmac; - } - if (arguments.ContainsKey("/aes256")) - { - hash = arguments["/aes256"]; - encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; - } - if (arguments.ContainsKey("/ptt")) - { - ptt = true; - } - - if (arguments.ContainsKey("/luid")) - { - try - { - luid = UInt32.Parse(arguments["/luid"]); - } - catch - { - try - { - luid = Convert.ToUInt32(arguments["/luid"], 16); - } - catch - { - Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/LUID"]); - return; - } - } - } - - if (arguments.ContainsKey("/createnetonly")) - { - // if we're starting a hidden process to apply the ticket to - if (!Helpers.IsHighIntegrity()) - { - Console.WriteLine("[X] You need to be in high integrity to apply a ticket to created logon session"); - return; - } - if (arguments.ContainsKey("/show")) - { - luid = LSA.CreateProcessNetOnly(arguments["/createnetonly"], true); - } - else - { - luid = LSA.CreateProcessNetOnly(arguments["/createnetonly"], false); - } - Console.WriteLine(); - } - - if (String.IsNullOrEmpty(user)) - { - Console.WriteLine("\r\n[X] You must supply a user name!\r\n"); - return; - } - if (String.IsNullOrEmpty(domain)) - { - domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; - } - if (String.IsNullOrEmpty(hash)) - { - Console.WriteLine("\r\n[X] You must supply a /rc4 or /aes256 hash!\r\n"); - return; - } - - if ( !((encType == Interop.KERB_ETYPE.rc4_hmac) || (encType == Interop.KERB_ETYPE.aes256_cts_hmac_sha1)) ) - { - Console.WriteLine("\r\n[X] Only /rc4 and /aes256 are supported at this time.\r\n"); - return; - } - else - { - Ask.TGT(user, domain, hash, encType, ptt, dc, luid); - return; - } - } - - if (arguments.ContainsKey("asktgs")) - { - bool ptt = false; - string dc = ""; - string service = ""; - - if (arguments.ContainsKey("/ptt")) - { - ptt = true; - } - - if (arguments.ContainsKey("/dc")) - { - dc = arguments["/dc"]; - } - - if (arguments.ContainsKey("/service")) - { - service = arguments["/service"]; - } - else - { - Console.WriteLine("[X] One or more '/service:sname/server.domain.com' specifications are needed"); - return; - } - - if (arguments.ContainsKey("/ticket")) - { - string kirbi64 = arguments["/ticket"]; - - if (Helpers.IsBase64String(kirbi64)) - { - byte[] kirbiBytes = Convert.FromBase64String(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - Ask.TGS(kirbi, service, ptt, dc, true); - return; - } - else if (File.Exists(kirbi64)) - { - byte[] kirbiBytes = File.ReadAllBytes(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - Ask.TGS(kirbi, service, ptt, dc, true); - return; - } - else - { - Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); - } - return; - } - else - { - Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); - return; - } - } - - if (arguments.ContainsKey("renew")) - { - bool ptt = false; - string dc = ""; - - if (arguments.ContainsKey("/ptt")) - { - ptt = true; - } - - if (arguments.ContainsKey("/dc")) - { - dc = arguments["/dc"]; - } - - if (arguments.ContainsKey("/ticket")) - { - string kirbi64 = arguments["/ticket"]; - - if (Helpers.IsBase64String(kirbi64)) - { - byte[] kirbiBytes = Convert.FromBase64String(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - if (arguments.ContainsKey("/autorenew")) - { - // if we want to auto-renew the TGT up until the renewal limit - Renew.TGTAutoRenew(kirbi, dc); - } - else - { - // otherwise a single renew operation - byte[] blah = Renew.TGT(kirbi, ptt, dc); - } - } - else if (File.Exists(kirbi64)) - { - byte[] kirbiBytes = File.ReadAllBytes(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - if (arguments.ContainsKey("/autorenew")) - { - // if we want to auto-renew the TGT up until the renewal limit - Renew.TGTAutoRenew(kirbi, dc); - } - else - { - // otherwise a single renew operation - byte[] blah = Renew.TGT(kirbi, ptt, dc); - } - } - else - { - Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); - } - return; - } - else - { - Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); - return; - } - } - - else if (arguments.ContainsKey("changepw")) - { - string newPassword = ""; - string dc = ""; - - if (arguments.ContainsKey("/new")) - { - newPassword = arguments["/new"]; - } - if (String.IsNullOrEmpty(newPassword)) - { - Console.WriteLine("\r\n[X] New password must be supplied with /new:X !\r\n"); - return; - } - - if (arguments.ContainsKey("/dc")) - { - dc = arguments["/dc"]; - } - - if (arguments.ContainsKey("/ticket")) - { - string kirbi64 = arguments["/ticket"]; - - if (Helpers.IsBase64String(kirbi64)) - { - byte[] kirbiBytes = Convert.FromBase64String(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - Reset.UserPassword(kirbi, newPassword, dc); - } - else if (File.Exists(kirbi64)) - { - byte[] kirbiBytes = File.ReadAllBytes(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - Reset.UserPassword(kirbi, newPassword, dc); - } - else - { - Console.WriteLine("\r\n[X]/ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); - } - return; - } - else - { - Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); - return; - } - } - - if (arguments.ContainsKey("s4u")) - { - string targetUser = ""; - string targetSPN = ""; - string altSname = ""; - string user = ""; - string domain = ""; - string hash = ""; - bool ptt = false; - string dc = ""; - Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; - - if (arguments.ContainsKey("/user")) - { - user = arguments["/user"]; - } - if (arguments.ContainsKey("/domain")) - { - domain = arguments["/domain"]; - } - if (arguments.ContainsKey("/ptt")) - { - ptt = true; - } - if (arguments.ContainsKey("/dc")) - { - dc = arguments["/dc"]; - } - if (arguments.ContainsKey("/rc4")) - { - hash = arguments["/rc4"]; - encType = Interop.KERB_ETYPE.rc4_hmac; - } - if (arguments.ContainsKey("/aes256")) - { - hash = arguments["/aes256"]; - encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; - } - if (arguments.ContainsKey("/impersonateuser")) - { - targetUser = arguments["/impersonateuser"]; - } - - if (arguments.ContainsKey("/msdsspn")) - { - targetSPN = arguments["/msdsspn"]; - } - - if (arguments.ContainsKey("/altservice")) - { - altSname = arguments["/altservice"]; - } - - if (String.IsNullOrEmpty(targetUser)) - { - Console.WriteLine("\r\n[X] You must supply a /impersonateuser to impersonate!\r\n"); - return; - } - if (String.IsNullOrEmpty(targetSPN)) - { - Console.WriteLine("\r\n[X] You must supply a /msdsspn !\r\n"); - return; - } - - if (arguments.ContainsKey("/ticket")) - { - string kirbi64 = arguments["/ticket"]; - - if (Helpers.IsBase64String(kirbi64)) - { - byte[] kirbiBytes = Convert.FromBase64String(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - S4U.Execute(kirbi, targetUser, targetSPN, ptt, dc, altSname); - } - else if (File.Exists(kirbi64)) - { - byte[] kirbiBytes = File.ReadAllBytes(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - S4U.Execute(kirbi, targetUser, targetSPN, ptt, dc, altSname); - } - else - { - Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); - } - return; - } - else if (arguments.ContainsKey("/user")) - { - // if the user is supplying a user and rc4/aes256 hash to first execute a TGT request - - user = arguments["/user"]; - - if (String.IsNullOrEmpty(hash)) - { - Console.WriteLine("\r\n[X] You must supply a /rc4 or /aes256 hash!\r\n"); - return; - } - - S4U.Execute(user, domain, hash, encType, targetUser, targetSPN, ptt, dc, altSname); - return; - } - else - { - Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied for S4U!\r\n"); - Console.WriteLine("[X] Alternatively, supply a /user and hash to first retrieve a TGT.\r\n"); - return; - } - } - - if (arguments.ContainsKey("ptt")) - { - uint luid = 0; - if (arguments.ContainsKey("/luid")) - { - try - { - luid = UInt32.Parse(arguments["/luid"]); - } - catch - { - try - { - luid = Convert.ToUInt32(arguments["/luid"], 16); - } - catch - { - Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/LUID"]); - return; - } - } - } - - if (arguments.ContainsKey("/ticket")) - { - string kirbi64 = arguments["/ticket"]; - - if (Helpers.IsBase64String(kirbi64)) - { - byte[] kirbiBytes = Convert.FromBase64String(kirbi64); - LSA.ImportTicket(kirbiBytes, luid); - } - else if (File.Exists(kirbi64)) - { - byte[] kirbiBytes = File.ReadAllBytes(kirbi64); - LSA.ImportTicket(kirbiBytes, luid); - } - else - { - Console.WriteLine("\r\n[X]/ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); - } - return; - } - else - { - Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); - return; - } - } - - if (arguments.ContainsKey("purge")) - { - uint luid = 0; - if (arguments.ContainsKey("/luid")) - { - try - { - luid = UInt32.Parse(arguments["/luid"]); - } - catch - { - try - { - luid = Convert.ToUInt32(arguments["/luid"], 16); - } - catch - { - Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/LUID"]); - return; - } - } - } - - LSA.Purge(luid); - } - - else if (arguments.ContainsKey("kerberoast")) - { - string spn = ""; - string user = ""; - string OU = ""; - - if (arguments.ContainsKey("/spn")) - { - spn = arguments["/spn"]; - } - if (arguments.ContainsKey("/user")) - { - user = arguments["/user"]; - } - if (arguments.ContainsKey("/ou")) - { - OU = arguments["/ou"]; - } - - if (arguments.ContainsKey("/creduser")) - { - if (!Regex.IsMatch(arguments["/creduser"], ".+\\.+", RegexOptions.IgnoreCase)) - { - Console.WriteLine("\r\n[X] /creduser specification must be in fqdn format (domain.com\\user)\r\n"); - return; - } - - string[] parts = arguments["/creduser"].Split('\\'); - string domainName = parts[0]; - string userName = parts[1]; - - if (!arguments.ContainsKey("/credpassword")) - { - Console.WriteLine("\r\n[X] /credpassword is required when specifying /creduser\r\n"); - return; - } - - string password = arguments["/credpassword"]; - - System.Net.NetworkCredential cred = new System.Net.NetworkCredential(userName, password, domainName); - - Roast.Kerberoast(spn, user, OU, cred); - } - else - { - Roast.Kerberoast(spn, user, OU); - } - } - - else if (arguments.ContainsKey("asreproast")) - { - string user = ""; - string domain = ""; - string dc = ""; - string format = "john"; - - if (arguments.ContainsKey("/user")) - { - user = arguments["/user"]; - } - if (arguments.ContainsKey("/domain")) - { - domain = arguments["/domain"]; - } - if (arguments.ContainsKey("/dc")) - { - dc = arguments["/dc"]; - } - if (arguments.ContainsKey("/format")) - { - format = arguments["/format"]; - } - - if (String.IsNullOrEmpty(user)) - { - Console.WriteLine("\r\n[X] You must supply a user name!\r\n"); - return; - } - if (String.IsNullOrEmpty(domain)) - { - domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; - } - - if (String.IsNullOrEmpty(dc)) - { - Roast.ASRepRoast(user, domain, "", format); - } - else - { - Roast.ASRepRoast(user, domain, dc, format); - } - } - - else if (arguments.ContainsKey("dump")) - { - if (arguments.ContainsKey("/luid")) - { - string service = ""; - if (arguments.ContainsKey("/service")) - { - service = arguments["/service"]; - } - UInt32 luid = 0; - try - { - luid = UInt32.Parse(arguments["/luid"]); - } - catch - { - try - { - luid = Convert.ToUInt32(arguments["/luid"], 16); - } - catch - { - Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/LUID"]); - return; - } - } - LSA.ListKerberosTicketData(luid, service); - } - else if (arguments.ContainsKey("/service")) - { - LSA.ListKerberosTicketData(0, arguments["/service"]); - } - else - { - LSA.ListKerberosTicketData(); - } - } - - else if (arguments.ContainsKey("tgtdeleg")) - { - if (arguments.ContainsKey("/target")) - { - byte[] blah = LSA.RequestFakeDelegTicket(arguments["/target"]); - } - else - { - byte[] blah = LSA.RequestFakeDelegTicket(); - } - } - - else if (arguments.ContainsKey("monitor")) - { - string targetUser = ""; - int interval = 60; - if (arguments.ContainsKey("/filteruser")) - { - targetUser = arguments["/filteruser"]; - } - if (arguments.ContainsKey("/interval")) - { - interval = Int32.Parse(arguments["/interval"]); - } - Harvest.Monitor4624(interval, targetUser); - } - - else if (arguments.ContainsKey("harvest")) - { - int intervalMinutes = 60; - if (arguments.ContainsKey("/interval")) - { - intervalMinutes = Int32.Parse(arguments["/interval"]); - } - Harvest.HarvestTGTs(intervalMinutes); - } - - else if (arguments.ContainsKey("describe")) - { - if (arguments.ContainsKey("/ticket")) - { - string kirbi64 = arguments["/ticket"]; - - if (Helpers.IsBase64String(kirbi64)) - { - byte[] kirbiBytes = Convert.FromBase64String(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - LSA.DisplayTicket(kirbi); - } - else if (File.Exists(kirbi64)) - { - byte[] kirbiBytes = File.ReadAllBytes(kirbi64); - KRB_CRED kirbi = new KRB_CRED(kirbiBytes); - LSA.DisplayTicket(kirbi); - } - else - { - Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); - } - return; - } - else - { - Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied!\r\n"); - return; - } - } - - else if (arguments.ContainsKey("createnetonly")) - { - - if (arguments.ContainsKey("/program")) - { - if (arguments.ContainsKey("/show")) - { - LSA.CreateProcessNetOnly(arguments["/program"], true); - } - else - { - LSA.CreateProcessNetOnly(arguments["/program"]); - } - } - - else - { - Console.WriteLine("\r\n[X] A /program needs to be supplied!\r\n"); - } - } - - else { - Usage(); - } - } } + } diff --git a/Rubeus/Rubeus.csproj b/Rubeus/Rubeus.csproj index 8977489..be53f95 100755 --- a/Rubeus/Rubeus.csproj +++ b/Rubeus/Rubeus.csproj @@ -47,6 +47,26 @@ + + + + + + + + + + + + + + + + + + + +