From 86b918b25df3a4a45bff646232cee0ad9905a907 Mon Sep 17 00:00:00 2001 From: mvelazco Date: Tue, 22 Jun 2021 23:25:01 -0400 Subject: [PATCH 01/15] improving attack navigator export feature --- PurpleSharp/Json/PurpleSharp_navigator.json | 2 +- PurpleSharp/Lib/Json.cs | 2 +- PurpleSharp/Program.cs | 45 +++++++++++++++------ 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/PurpleSharp/Json/PurpleSharp_navigator.json b/PurpleSharp/Json/PurpleSharp_navigator.json index dbd6eb5..b05292d 100644 --- a/PurpleSharp/Json/PurpleSharp_navigator.json +++ b/PurpleSharp/Json/PurpleSharp_navigator.json @@ -1 +1 @@ -{"name":"PurpleSharp Coverage","version":"3.0","domain":"mitre-enterprise","description":"Layer of techniques supported by PurpleSharp","hideDisabled":true,"filters":{"stages":["act"],"platforms":["Windows"]},"techniques":[{"techniqueID":"T1053.005","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1059.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1059.005","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1059.007","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1059.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1569.002","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1136.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1543.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1547.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1546.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1197","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1055.002","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1055.004","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.010","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.005","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.011","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1070.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1220","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1055.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1140","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.009","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.004","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1134.004","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1110.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1558.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1003.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1135","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1046","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1087.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1087.002","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1007","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1033","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1049","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1016","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1083","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1482","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1201","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1069.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1069.002","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1012","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1518.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1082","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1124","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1021","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1021.006","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1047","color":"#756bb1","score":1,"enabled":true}]} \ No newline at end of file +{"name":"PurpleSharp Coverage","version":"4.2","domain":"mitre-enterprise","description":"Layer of techniques supported by PurpleSharp","hideDisabled":true,"filters":{"stages":["act"],"platforms":["Windows"]},"techniques":[{"techniqueID":"T1053","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1059","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1569","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1136","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1197","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1543","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1546","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1547","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1134","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1055","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1070","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1140","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1220","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1110","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1558","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1135","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1046","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1087","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1007","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1033","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1049","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1016","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1018","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1083","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1482","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1201","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1069","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1012","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1518","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1082","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1124","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1021","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1047","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1053.005","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1059.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1059.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1059.005","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1059.007","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1569.002","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1136.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1543.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1546.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1547.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1134.004","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1055.002","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1055.004","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1055.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1070.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.010","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.004","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.005","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.009","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1218.011","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1003.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1110.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1558.003","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1087.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1087.002","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1069.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1069.002","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1518.001","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1021.002","color":"#756bb1","score":1,"enabled":true},{"techniqueID":"T1021.006","color":"#756bb1","score":1,"enabled":true}]} \ No newline at end of file diff --git a/PurpleSharp/Lib/Json.cs b/PurpleSharp/Lib/Json.cs index d5d6467..029adf4 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"; diff --git a/PurpleSharp/Program.cs b/PurpleSharp/Program.cs index 1690add..843b78e 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; } @@ -1148,7 +1169,7 @@ public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) break; //T1021 - Remote Service - case "T1021": + case "T1021.002": Simulations.LateralMovement.CreateRemoteServiceOnHosts(playbook_task.host_target_total, playbook_task.task_sleep, playbook_task.cleanup, log); break; From ed200e8a9d4fa241e84d41707c1aa7954b70e60a Mon Sep 17 00:00:00 2001 From: mvelazco Date: Thu, 24 Jun 2021 21:10:20 -0400 Subject: [PATCH 02/15] fixing navigator import --- PurpleSharp/Lib/Json.cs | 4 ++-- PurpleSharp/Lib/Models.cs | 2 +- PurpleSharp/Program.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PurpleSharp/Lib/Json.cs b/PurpleSharp/Lib/Json.cs index 029adf4..ece1f07 100644 --- a/PurpleSharp/Lib/Json.cs +++ b/PurpleSharp/Lib/Json.cs @@ -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/Models.cs b/PurpleSharp/Lib/Models.cs index 1a83857..304ebac 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 diff --git a/PurpleSharp/Program.cs b/PurpleSharp/Program.cs index 843b78e..bb159f0 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -235,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"); From af3aa3c48d238ddeb9a046a206d91ea55fb6b9eb Mon Sep 17 00:00:00 2001 From: mvelazco Date: Tue, 29 Jun 2021 00:21:00 -0400 Subject: [PATCH 03/15] enhancing T1021.002 remote service creation --- PurpleSharp/Lib/Ldap.cs | 1 + PurpleSharp/Lib/Logger.cs | 2 + PurpleSharp/Lib/Models.cs | 4 + PurpleSharp/Lib/Structs.cs | 14 ++ PurpleSharp/Lib/WinAPI.cs | 5 + PurpleSharp/Program.cs | 4 +- PurpleSharp/Simulations/LateralMovement.cs | 96 ++++++++++- .../Simulations/LateralMovementHelper.cs | 152 ++++++++++++++++-- 8 files changed, 261 insertions(+), 17 deletions(-) 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 304ebac..4b9f1ed 100644 --- a/PurpleSharp/Lib/Models.cs +++ b/PurpleSharp/Lib/Models.cs @@ -134,6 +134,10 @@ 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"; + public PlaybookTask() { } 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/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 bb159f0..25194f1 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -1170,7 +1170,9 @@ public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) //T1021 - Remote Service case "T1021.002": - Simulations.LateralMovement.CreateRemoteServiceOnHosts(playbook_task.host_target_total, playbook_task.task_sleep, playbook_task.cleanup, log); + if (playbook_task.variation == 1) Simulations.LateralMovement.CreateRemoteServiceOnHosts(playbook_task, log); + else Simulations.LateralMovement.ModifyRemoteServiceOnHosts(playbook_task, log); + //Simulations.LateralMovement.CreateRemoteServiceOnHosts_Old(playbook_task.host_target_total, playbook_task.task_sleep, playbook_task.cleanup, log); break; //T1047 - Windows Management Instrumentation diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index 7d3c121..69f1ef1 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,6 +52,90 @@ static public void CreateRemoteServiceOnHosts(int nhost, int tsleep, bool cleanu } } + static public void CreateRemoteServiceOnHosts(PlaybookTask playbook_task, string log) + { + string currentPath = AppDomain.CurrentDomain.BaseDirectory; + 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(); + + + if (playbook_task.serviceName.Equals("random")) + { + string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; + 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 + { + host_targets = Targets.GetHostTargets(playbook_task, logger); + foreach (Computer computer in host_targets) + { + Computer temp = computer; + if (!computer.ComputerName.ToUpper().Contains(Environment.MachineName.ToUpper())) + { + tasklist.Add(Task.Factory.StartNew(() => + { + LateralMovementHelper.CreateRemoteServiceApi(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 ModifyRemoteServiceOnHosts(PlaybookTask playbook_task, string log) + { + string currentPath = AppDomain.CurrentDomain.BaseDirectory; + 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 + { + host_targets = Targets.GetHostTargets(playbook_task, logger); + + foreach (Computer computer in host_targets) + { + Computer temp = computer; + if (!computer.ComputerName.ToUpper().Contains(Environment.MachineName.ToUpper())) + { + //LateralMovementHelper.ModifyRemoteServiceApi(temp, playbook_task, logger); + + tasklist.Add(Task.Factory.StartNew(() => + { + LateralMovementHelper.ModifyRemoteServiceApi(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 WinRmCodeExec(int nhost, int tsleep, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index 9cf733d..4af9991 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 ArgumentException("Could not obtain a handle to SCM", "Error"); } 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,141 @@ public static void CreateRemoteServiceApi(Computer computer, bool cleanup, Lib.L } } - */ + - //WinAPI.StartService(svcHandleCreated, 0, null); + 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 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)); + } + } + + 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) { From 4d01ac6a8b7b0b2f02c961ecaae971f5384f9bbb Mon Sep 17 00:00:00 2001 From: mvelazco Date: Thu, 1 Jul 2021 00:14:57 -0400 Subject: [PATCH 04/15] initial changes for T1021.006 --- PurpleSharp/Lib/Models.cs | 3 + PurpleSharp/Program.cs | 2 +- PurpleSharp/Simulations/LateralMovement.cs | 21 ++--- .../Simulations/LateralMovementHelper.cs | 79 ++++++++++++++++--- 4 files changed, 78 insertions(+), 27 deletions(-) diff --git a/PurpleSharp/Lib/Models.cs b/PurpleSharp/Lib/Models.cs index 4b9f1ed..6284c27 100644 --- a/PurpleSharp/Lib/Models.cs +++ b/PurpleSharp/Lib/Models.cs @@ -138,6 +138,9 @@ public class PlaybookTask public string serviceName { get; set; } ="PurpleSharp Updater"; public string servicePath { get; set; } = @"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"; + // WinRM remote execution + public string command { get; set; } = @"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"; + public PlaybookTask() { } diff --git a/PurpleSharp/Program.cs b/PurpleSharp/Program.cs index 25194f1..c84b35b 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -1165,7 +1165,7 @@ public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) //T1021.006 - Windows Remote Management case "T1021.006": - Simulations.LateralMovement.WinRmCodeExec(playbook_task.host_target_total, playbook_task.task_sleep, log); + Simulations.LateralMovement.WinRmCodeExec(playbook_task, log); break; //T1021 - Remote Service diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index 69f1ef1..bcffea9 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -136,34 +136,29 @@ static public void ModifyRemoteServiceOnHosts(PlaybookTask playbook_task, string } - static public void WinRmCodeExec(int nhost, int tsleep, string log) + static public void WinRmCodeExec(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("T1021.006"); logger.TimestampInfo("Using the System.Management.Automation .NET namespace to execute this technique"); + 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(); - //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)); + 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())) { tasklist.Add(Task.Factory.StartNew(() => { - LateralMovementHelper.WinRMCodeExecution(temp, "powershell.exe", logger); + LateralMovementHelper.WinRMCodeExecution(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()); diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index 4af9991..c0b97fe 100644 --- a/PurpleSharp/Simulations/LateralMovementHelper.cs +++ b/PurpleSharp/Simulations/LateralMovementHelper.cs @@ -281,23 +281,28 @@ 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 WinRMCodeExecution(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 "); @@ -310,26 +315,74 @@ 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 WinRMCodeExecution2(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", 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(playbook_task.command); + var results = powershell.Invoke(); + runspace.Close(); + logger.TimestampInfo(String.Format("Successfully executed {0} using WinRM on {1}", playbook_task.command, computer.ComputerName)); + + /* + Console.WriteLine("Return command "); + foreach (var obj in results.Where(o => o != null)) + { + Console.WriteLine("\t" + obj); + } + */ + } + } + catch (Exception ex) + { + if (ex.Message.Contains("Access is denied")) + { + logger.TimestampInfo(String.Format("Failed to start a process using WinRM on {0}. (Access Denied)", 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}. (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())); + throw new Exception(); + } + } } public static void WmiCodeExecution(Computer computer, string command, Lib.Logger logger) From 571e979ef7807e394aa8595eef3f3302be34f45c Mon Sep 17 00:00:00 2001 From: mvelazco Date: Thu, 8 Jul 2021 16:02:02 -0400 Subject: [PATCH 05/15] fixing GetHostTargets option 1 was not taking into consideration multiple hosts as targets --- PurpleSharp/Lib/Targets.cs | 42 ++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/PurpleSharp/Lib/Targets.cs b/PurpleSharp/Lib/Targets.cs index b9f464e..a43ea94 100644 --- a/PurpleSharp/Lib/Targets.cs +++ b/PurpleSharp/Lib/Targets.cs @@ -216,20 +216,34 @@ 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"); host_targets = GetDomainNeighborTargets(playbook_task.host_target_total, logger); @@ -242,18 +256,6 @@ public static List GetHostTargets(PlaybookTask playbook_task, Logger l 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); From 6954dec4328ae0126902e6353badf8a9ef958a9d Mon Sep 17 00:00:00 2001 From: mvelazco Date: Thu, 8 Jul 2021 17:07:03 -0400 Subject: [PATCH 06/15] updating T1047 for lateral movement --- PurpleSharp/Lib/Targets.cs | 15 ++-- PurpleSharp/Program.cs | 2 +- PurpleSharp/Simulations/LateralMovement.cs | 24 +++---- .../Simulations/LateralMovementHelper.cs | 68 ++----------------- 4 files changed, 22 insertions(+), 87 deletions(-) diff --git a/PurpleSharp/Lib/Targets.cs b/PurpleSharp/Lib/Targets.cs index a43ea94..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(); @@ -245,23 +245,20 @@ public static List GetHostTargets(PlaybookTask playbook_task, Logger l 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 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/Program.cs b/PurpleSharp/Program.cs index c84b35b..f7b92ec 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -1177,7 +1177,7 @@ public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) //T1047 - Windows Management Instrumentation case "T1047": - Simulations.LateralMovement.ExecuteWmiOnHosts(playbook_task.host_target_total, playbook_task.task_sleep, log); + Simulations.LateralMovement.ExecuteWmiOnHosts(playbook_task, log); break; // Collection diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index bcffea9..42f81be 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -169,35 +169,27 @@ static public void WinRmCodeExec(PlaybookTask playbook_task, string log) logger.SimulationFailed(ex); } } - - static public void ExecuteWmiOnHosts(int nhost, int tsleep, string log) + static public void ExecuteWmiOnHosts(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("T1047"); logger.TimestampInfo("Using the System.Management .NET API to execute this technique"); - + 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)); - - 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())) { tasklist.Add(Task.Factory.StartNew(() => { - LateralMovementHelper.WmiCodeExecution(temp, "powershell.exe", logger); + LateralMovementHelper.WmiCodeExecution(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)); } } diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index c0b97fe..e5a5dbf 100644 --- a/PurpleSharp/Simulations/LateralMovementHelper.cs +++ b/PurpleSharp/Simulations/LateralMovementHelper.cs @@ -333,90 +333,36 @@ public static void WinRMCodeExecution(Computer computer, PlaybookTask playbook_t } } - public static void WinRMCodeExecution2(Computer computer, PlaybookTask playbook_task, Logger logger) + public static void WmiCodeExecution(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", 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(playbook_task.command); - var results = powershell.Invoke(); - runspace.Close(); - logger.TimestampInfo(String.Format("Successfully executed {0} using WinRM on {1}", playbook_task.command, computer.ComputerName)); - /* - Console.WriteLine("Return command "); - foreach (var obj in results.Where(o => o != null)) - { - Console.WriteLine("\t" + obj); - } - */ - } - } - catch (Exception ex) - { - if (ex.Message.Contains("Access is denied")) - { - logger.TimestampInfo(String.Format("Failed to start a process using WinRM on {0}. (Access Denied)", 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}. (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())); - throw new Exception(); - } - } - } - - public static void WmiCodeExecution(Computer computer, string command, Lib.Logger logger) - { 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 CreateRemoteScheduledTask(Computer computer, string command, bool cleanup) From 0513240d1435ddafe421ff91c25a2048834a3b7a Mon Sep 17 00:00:00 2001 From: mvelazco Date: Sat, 10 Jul 2021 02:16:45 -0400 Subject: [PATCH 07/15] adding T1053 lateral movement variation 1: using schtasks.exe --- PurpleSharp/Lib/Logger.cs | 2 +- PurpleSharp/Lib/Models.cs | 8 +- PurpleSharp/Program.cs | 5 + PurpleSharp/Simulations/LateralMovement.cs | 37 +++- .../Simulations/LateralMovementHelper.cs | 182 ++++++------------ 5 files changed, 106 insertions(+), 128 deletions(-) diff --git a/PurpleSharp/Lib/Logger.cs b/PurpleSharp/Lib/Logger.cs index 02a8289..786c6f6 100644 --- a/PurpleSharp/Lib/Logger.cs +++ b/PurpleSharp/Lib/Logger.cs @@ -84,7 +84,7 @@ 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, "Exception: " + ex.StackTrace); WriteFormattedLog(LogLevel.TINFO, "Simulation Failed"); } diff --git a/PurpleSharp/Lib/Models.cs b/PurpleSharp/Lib/Models.cs index 6284c27..777d2ff 100644 --- a/PurpleSharp/Lib/Models.cs +++ b/PurpleSharp/Lib/Models.cs @@ -138,9 +138,15 @@ public class PlaybookTask public string serviceName { get; set; } ="PurpleSharp Updater"; public string servicePath { get; set; } = @"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"; - // WinRM remote execution + // 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/Program.cs b/PurpleSharp/Program.cs index f7b92ec..8a00fda 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -1180,6 +1180,11 @@ public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) Simulations.LateralMovement.ExecuteWmiOnHosts(playbook_task, log); break; + case "T10531": + if (playbook_task.variation == 1) Simulations.LateralMovement.CreateSchTaskOnHostsCmdline(playbook_task, log); + break; + + // Collection // Command and Control diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index 42f81be..51367c7 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -203,7 +203,42 @@ static public void ExecuteWmiOnHosts(PlaybookTask playbook_task, string log) } } - static public void CreateSchTaskOnHosts(int nhost, int sleep, bool cleanup) + 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 the schtasks.exe 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(() => + { + 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); + } + } + + static public void CreateSchTaskOnHosts_Old(int nhost, int sleep, bool cleanup) { /* var rand = new Random(); diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index e5a5dbf..93e9760 100644 --- a/PurpleSharp/Simulations/LateralMovementHelper.cs +++ b/PurpleSharp/Simulations/LateralMovementHelper.cs @@ -365,157 +365,89 @@ public static void WmiCodeExecution(Computer computer, PlaybookTask playbook_tas } } - 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"; - */ - /* - - - 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); - + //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); - - strJobId = outParams["JobId"].ToString(); - Console.WriteLine("Out parameters:"); - Console.WriteLine("JobId: " + outParams["JobId"]); + wmiScope.Connect(); + Console.WriteLine("Connected"); - 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())); + } } - } + // Based on https://www.programmersought.com/article/80103808764/ + 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 creatTaskArg = string.Format(@"/create /s {0} /sc ONCE /st 10:00 /tn ""{1}"" /tr {2} /rl HIGHEST /ru Local /IT", target, playbook_task.taskName, playbook_task.taskPath); + string runTaskArg = string.Format(@"/run /s {0} /tn ""{1}""", target, playbook_task.taskName); ; + string deleteTaskArg = string.Format(@"/delete /s {0} /tn ""{1}"" /F", target, playbook_task.taskName); + ExecutionHelper.StartProcessNET("schtasks.exe", creatTaskArg, logger); + ExecutionHelper.StartProcessNET("schtasks.exe", runTaskArg, logger); + if (playbook_task.cleanup) ExecutionHelper.StartProcessNET("schtasks.exe", deleteTaskArg, logger); + + } + } } From 277a34c18feb97f7364290f25335028d3ec9be80 Mon Sep 17 00:00:00 2001 From: mvelazco Date: Sat, 10 Jul 2021 20:52:26 -0400 Subject: [PATCH 08/15] Update ExecutionHelper Returning standard error output to better handle errors --- PurpleSharp/Simulations/ExecutionHelper.cs | 18 +++++++++++- PurpleSharp/Simulations/LateralMovement.cs | 3 +- .../Simulations/LateralMovementHelper.cs | 28 ++++++++++--------- 3 files changed, 33 insertions(+), 16 deletions(-) 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 51367c7..95c4ed3 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -208,7 +208,7 @@ static public void CreateSchTaskOnHostsCmdline(PlaybookTask playbook_task, strin string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1053 - Lateral Movement"); - logger.TimestampInfo("Using the schtasks.exe to execute this technique"); + logger.TimestampInfo("Using schtasks.exe to execute this technique"); List host_targets = new List(); List tasklist = new List(); try @@ -219,7 +219,6 @@ static public void CreateSchTaskOnHostsCmdline(PlaybookTask playbook_task, strin Computer temp = computer; if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) { - tasklist.Add(Task.Factory.StartNew(() => { LateralMovementHelper.CreateRemoteScheduledTaskCmdline(temp, playbook_task, logger); diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index 93e9760..ef22e71 100644 --- a/PurpleSharp/Simulations/LateralMovementHelper.cs +++ b/PurpleSharp/Simulations/LateralMovementHelper.cs @@ -27,7 +27,7 @@ public static void CreateRemoteServiceApi_Old(Computer computer, bool cleanup, L DateTime dtime = DateTime.Now; int err = Marshal.GetLastWin32Error(); logger.TimestampInfo(String.Format("Could not obtain a handle to the Service Control Manager on {0}.", computer.Fqdn)); - throw new ArgumentException("Could not obtain a handle to SCM", "Error"); + throw new Exception(); } string servicePath = @"C:\Windows\Temp\superlegit.exe"; // A path to some running service now @@ -426,10 +426,8 @@ public static void CreateRemoteScheduledTaskWmi(Computer computer, PlaybookTask logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. {1}", target, ex.GetType())); } } - } - // Based on https://www.programmersought.com/article/80103808764/ public static void CreateRemoteScheduledTaskCmdline(Computer computer, PlaybookTask playbook_task, Logger logger) { string target = ""; @@ -437,16 +435,20 @@ public static void CreateRemoteScheduledTaskCmdline(Computer computer, PlaybookT else if (!computer.ComputerName.Equals("")) target = computer.ComputerName; else target = computer.IPv4; - string creatTaskArg = string.Format(@"/create /s {0} /sc ONCE /st 10:00 /tn ""{1}"" /tr {2} /rl HIGHEST /ru Local /IT", target, playbook_task.taskName, playbook_task.taskPath); - string runTaskArg = string.Format(@"/run /s {0} /tn ""{1}""", target, playbook_task.taskName); ; - string deleteTaskArg = string.Format(@"/delete /s {0} /tn ""{1}"" /F", target, playbook_task.taskName); - ExecutionHelper.StartProcessNET("schtasks.exe", creatTaskArg, logger); - ExecutionHelper.StartProcessNET("schtasks.exe", runTaskArg, logger); - - if (playbook_task.cleanup) ExecutionHelper.StartProcessNET("schtasks.exe", deleteTaskArg, logger); - - - + 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(); + } + } } From f3ed1f2011b663fe8ab8d4519c1b704b5a0db54d Mon Sep 17 00:00:00 2001 From: mvelazco Date: Sat, 10 Jul 2021 23:29:51 -0400 Subject: [PATCH 09/15] added command line variation for T1021.002 --- PurpleSharp/Program.cs | 4 ++-- PurpleSharp/Simulations/LateralMovement.cs | 8 +++---- .../Simulations/LateralMovementHelper.cs | 24 +++++++++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/PurpleSharp/Program.cs b/PurpleSharp/Program.cs index 8a00fda..0649f74 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -1171,8 +1171,8 @@ public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) //T1021 - Remote Service case "T1021.002": if (playbook_task.variation == 1) Simulations.LateralMovement.CreateRemoteServiceOnHosts(playbook_task, log); - else Simulations.LateralMovement.ModifyRemoteServiceOnHosts(playbook_task, log); - //Simulations.LateralMovement.CreateRemoteServiceOnHosts_Old(playbook_task.host_target_total, playbook_task.task_sleep, playbook_task.cleanup, 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; //T1047 - Windows Management Instrumentation diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index 95c4ed3..7655376 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -57,7 +57,8 @@ static public void CreateRemoteServiceOnHosts(PlaybookTask playbook_task, string string currentPath = AppDomain.CurrentDomain.BaseDirectory; 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"); + 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(); @@ -70,7 +71,6 @@ static public void CreateRemoteServiceOnHosts(PlaybookTask playbook_task, string logger.TimestampInfo("Using random Service Name"); playbook_task.serviceName = new string(Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray()); } - try { host_targets = Targets.GetHostTargets(playbook_task, logger); @@ -81,14 +81,14 @@ static public void CreateRemoteServiceOnHosts(PlaybookTask playbook_task, string { tasklist.Add(Task.Factory.StartNew(() => { - LateralMovementHelper.CreateRemoteServiceApi(temp, playbook_task, 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 (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) { diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index ef22e71..03f52a4 100644 --- a/PurpleSharp/Simulations/LateralMovementHelper.cs +++ b/PurpleSharp/Simulations/LateralMovementHelper.cs @@ -128,6 +128,30 @@ public static void CreateRemoteServiceApi_Old(Computer computer, bool cleanup, L // 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; From c933cb1be1b3baa1fcc06d25b6b6aa982a3ab3a3 Mon Sep 17 00:00:00 2001 From: mvelazco Date: Sun, 11 Jul 2021 01:13:28 -0400 Subject: [PATCH 10/15] new variation for RCE using WMI T1047 update --- PurpleSharp/Simulations/LateralMovement.cs | 8 ++++---- .../Simulations/LateralMovementHelper.cs | 20 ++++++++++++++++--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index 7655376..d4f9927 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -174,7 +174,8 @@ static public void ExecuteWmiOnHosts(PlaybookTask playbook_task, string log) string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1047"); - logger.TimestampInfo("Using the System.Management .NET API to execute this technique"); + 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 @@ -187,15 +188,14 @@ static public void ExecuteWmiOnHosts(PlaybookTask playbook_task, string log) { tasklist.Add(Task.Factory.StartNew(() => { - LateralMovementHelper.WmiCodeExecution(temp, playbook_task, logger); + 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) { diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index 03f52a4..35175f2 100644 --- a/PurpleSharp/Simulations/LateralMovementHelper.cs +++ b/PurpleSharp/Simulations/LateralMovementHelper.cs @@ -357,14 +357,12 @@ public static void WinRMCodeExecution(Computer computer, PlaybookTask playbook_t } } - public static void WmiCodeExecution(Computer computer, PlaybookTask playbook_task, 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(); @@ -389,6 +387,22 @@ public static void WmiCodeExecution(Computer computer, PlaybookTask playbook_tas } } + 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(); + } + + } private static string DateTimetoUTC(DateTime dateParam) { string buffer = dateParam.ToString("********HHmmss.ffffff"); From 7394726bba82ce6c509594c89a12575ee78af782 Mon Sep 17 00:00:00 2001 From: mvelazco Date: Sun, 11 Jul 2021 01:33:35 -0400 Subject: [PATCH 11/15] adding new variation for T1021.006 using powershell.exe and Invoke-Command --- PurpleSharp/Simulations/LateralMovement.cs | 6 ++++-- .../Simulations/LateralMovementHelper.cs | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index d4f9927..742313a 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -141,7 +141,8 @@ static public void WinRmCodeExec(PlaybookTask playbook_task, string log) string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1021.006"); - logger.TimestampInfo("Using the System.Management.Automation .NET namespace to execute this technique"); + 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 host_targets = new List(); List tasklist = new List(); @@ -156,7 +157,8 @@ static public void WinRmCodeExec(PlaybookTask playbook_task, string log) { tasklist.Add(Task.Factory.StartNew(() => { - LateralMovementHelper.WinRMCodeExecution(temp, playbook_task, logger); + 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)); } diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index 35175f2..c6a732b 100644 --- a/PurpleSharp/Simulations/LateralMovementHelper.cs +++ b/PurpleSharp/Simulations/LateralMovementHelper.cs @@ -305,7 +305,23 @@ static bool CreateService(IntPtr scmHandle, string servicePath, string serviceNa return serviceHandleCreated != IntPtr.Zero; } - public static void WinRMCodeExecution(Computer computer, PlaybookTask playbook_task, 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); + //ExecutionHelper.StartProcessApi("", String.Format("powershell.exe -enc {0}", Convert.ToBase64String(plainTextBytes)), logger); + 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 = ""; From 6a5e5a4f5312ce244162aa60af5bcaf80c6038ff Mon Sep 17 00:00:00 2001 From: mvelazco Date: Sun, 11 Jul 2021 10:29:19 -0400 Subject: [PATCH 12/15] adding random task name feature for remote T1053 --- PurpleSharp/Simulations/LateralMovement.cs | 11 ++++++++++- PurpleSharp/Simulations/LateralMovementHelper.cs | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index 742313a..b37348f 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -66,7 +66,7 @@ static public void CreateRemoteServiceOnHosts(PlaybookTask playbook_task, string if (playbook_task.serviceName.Equals("random")) { - string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; + 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()); @@ -213,6 +213,15 @@ static public void CreateSchTaskOnHostsCmdline(PlaybookTask playbook_task, strin 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); diff --git a/PurpleSharp/Simulations/LateralMovementHelper.cs b/PurpleSharp/Simulations/LateralMovementHelper.cs index c6a732b..fe48f5d 100644 --- a/PurpleSharp/Simulations/LateralMovementHelper.cs +++ b/PurpleSharp/Simulations/LateralMovementHelper.cs @@ -315,7 +315,6 @@ public static void WinRMCodeExecutionPowerShell(Computer computer, PlaybookTask 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); - //ExecutionHelper.StartProcessApi("", String.Format("powershell.exe -enc {0}", Convert.ToBase64String(plainTextBytes)), logger); string results = ExecutionHelper.StartProcessNET("powershell.exe", String.Format("-enc {0}", Convert.ToBase64String(plainTextBytes)), logger); if (results.Contains("AccessDenied")) throw new Exception(); From 87f2c0f5949785c23230883fa46483d40df63cce Mon Sep 17 00:00:00 2001 From: mvelazco Date: Sun, 11 Jul 2021 12:20:53 -0400 Subject: [PATCH 13/15] initial support for same technique, different tactic --- PurpleSharp/Lib/Models.cs | 1 + PurpleSharp/Program.cs | 420 ++++++++++++++------------- PurpleSharp/Simulations/Execution.cs | 18 ++ 3 files changed, 238 insertions(+), 201 deletions(-) diff --git a/PurpleSharp/Lib/Models.cs b/PurpleSharp/Lib/Models.cs index 777d2ff..21c3208 100644 --- a/PurpleSharp/Lib/Models.cs +++ b/PurpleSharp/Lib/Models.cs @@ -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; diff --git a/PurpleSharp/Program.cs b/PurpleSharp/Program.cs index 0649f74..61a79eb 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -923,286 +923,304 @@ public static SimulationPlaybookResult ExecuteRemoteTechniquesJsonSerialized(Sim } public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) { - var rand = new Random(); - switch (playbook_task.technique_id) + if (playbook_task.tactic.Equals("")) { - //// Initial Access //// - - //// Execution //// + switch (playbook_task.technique_id) + { + //// Initial Access //// - case "T1059.001": - if (playbook_task.variation == 1) Simulations.Execution.ExecutePowershellCmd(log); - else Simulations.Execution.ExecutePowershellNET(log); - break; + //// Execution //// + /// - case "T1059.003": - Simulations.Execution.WindowsCommandShell(log); - break; + //T1047 - Windows Management Instrumentation + case "T1047": + Simulations.Execution.ExecuteWmiCmd(log); + break; + case "T1059.001": + if (playbook_task.variation == 1) Simulations.Execution.ExecutePowershellCmd(log); + else Simulations.Execution.ExecutePowershellNET(log); + break; - case "T1059.005": - Simulations.Execution.VisualBasic(log); - break; + case "T1059.003": + Simulations.Execution.WindowsCommandShell(log); + break; - case "T1059.007": - Simulations.Execution.JScript(log); - break; - case "T1569.002": - Simulations.Execution.ServiceExecution(log); - break; + case "T1059.005": + Simulations.Execution.VisualBasic(log); + break; + case "T1059.007": + Simulations.Execution.JScript(log); + break; - //T1021.006 - Windows Remote Management + case "T1569.002": + Simulations.Execution.ServiceExecution(log); + break; - //// Persistence //// - //T1053.005 - Scheduled Task + //T1021.006 - Windows Remote Management - case "T1053.005": - Simulations.Persistence.CreateScheduledTaskCmd(log, playbook_task.cleanup); - break; + //// Persistence //// - case "T1136.001": - if (playbook_task.variation == 1) Simulations.Persistence.CreateLocalAccountApi(log, playbook_task.cleanup); - else Simulations.Persistence.CreateLocalAccountCmd(log, playbook_task.cleanup); - break; + //T1053.005 - Scheduled Task - 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 "T1053.005": + Simulations.Persistence.CreateScheduledTaskCmd(log, playbook_task.cleanup); + 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 "T1136.001": + if (playbook_task.variation == 1) Simulations.Persistence.CreateLocalAccountApi(log, playbook_task.cleanup); + else Simulations.Persistence.CreateLocalAccountCmd(log, playbook_task.cleanup); + break; - case "T1546.003": - Simulations.Persistence.WMIEventSubscription(log, playbook_task.cleanup); - 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; - //// Privilege Escalation //// + case "T1547.001": + if (playbook_task.variation == 1) Simulations.Persistence.CreateRegistryRunKeyNET(log, playbook_task.cleanup); + else Simulations.Persistence.CreateRegistryRunKeyCmd(log, playbook_task.cleanup); + break; - //T1543.003 - New Service + case "T1546.003": + Simulations.Persistence.WMIEventSubscription(log, playbook_task.cleanup); + break; - //T1053.005 - Scheduled Task + //// Privilege Escalation //// - //// Defense Evasion //// + //T1543.003 - New Service - case "T1218.010": - Simulations.DefenseEvasion.Regsvr32(log); - break; + //T1053.005 - Scheduled Task - case "T1218.009": - Simulations.DefenseEvasion.RegsvcsRegasm(log); - break; + //// Defense Evasion //// - case "T1218.004": - Simulations.DefenseEvasion.InstallUtil(log); - break; + case "T1218.010": + Simulations.DefenseEvasion.Regsvr32(log); + break; - case "T1140": - Simulations.DefenseEvasion.DeobfuscateDecode(log); - break; + case "T1218.009": + Simulations.DefenseEvasion.RegsvcsRegasm(log); + break; - case "T1218.005": - Simulations.DefenseEvasion.Mshta(log); - break; + case "T1218.004": + Simulations.DefenseEvasion.InstallUtil(log); + break; - case "T1218.003": - Simulations.DefenseEvasion.Csmtp(log); - break; + case "T1140": + Simulations.DefenseEvasion.DeobfuscateDecode(log); + break; - case "T1197": - Simulations.DefenseEvasion.BitsJobs(log); - break; + case "T1218.005": + Simulations.DefenseEvasion.Mshta(log); + break; - case "T1218.011": - Simulations.DefenseEvasion.Rundll32(log); - break; + case "T1218.003": + Simulations.DefenseEvasion.Csmtp(log); + break; - case "T1070.001": - if (playbook_task.variation == 1) Simulations.DefenseEvasion.ClearSecurityEventLogNET(log); - else Simulations.DefenseEvasion.ClearSecurityEventLogCmd(log); + case "T1197": + Simulations.DefenseEvasion.BitsJobs(log); + break; - break; + case "T1218.011": + Simulations.DefenseEvasion.Rundll32(log); + break; - case "T1220": - Simulations.DefenseEvasion.XlScriptProcessing(log); - break; + case "T1070.001": + if (playbook_task.variation == 1) Simulations.DefenseEvasion.ClearSecurityEventLogNET(log); + else Simulations.DefenseEvasion.ClearSecurityEventLogCmd(log); - case "T1055.002": - Simulations.DefenseEvasion.PortableExecutableInjection(log); - break; + break; - case "T1055.003": - Simulations.DefenseEvasion.ThreadHijack(log); - break; + case "T1220": + Simulations.DefenseEvasion.XlScriptProcessing(log); + break; - case "T1055.004": - Simulations.DefenseEvasion.AsynchronousProcedureCall(log); - break; + case "T1055.002": + Simulations.DefenseEvasion.PortableExecutableInjection(log); + break; - case "T1134.004": - Simulations.DefenseEvasion.ParentPidSpoofing(log); - break; + case "T1055.003": + Simulations.DefenseEvasion.ThreadHijack(log); + break; + case "T1055.004": + Simulations.DefenseEvasion.AsynchronousProcedureCall(log); + break; + case "T1134.004": + Simulations.DefenseEvasion.ParentPidSpoofing(log); + break; - //T1218.010 - Regsvr32 + //T1218.010 - Regsvr32 - //// Credential Access //// + //// Credential Access //// - //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); + //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); - break; + break; - //T1558.003 - Kerberoasting - case "T1558.003": - Simulations.CredAccess.Kerberoasting(log, playbook_task.task_sleep); - break; + //T1558.003 - Kerberoasting + case "T1558.003": + Simulations.CredAccess.Kerberoasting(log, playbook_task.task_sleep); + break; - //T1003.001 - LSASS Memory - case "T1003.001": - Simulations.CredAccess.LsassMemoryDump(log); - break; + //T1003.001 - LSASS Memory + case "T1003.001": + Simulations.CredAccess.LsassMemoryDump(log); + break; - //// Discovery //// + //// Discovery //// - //T1016 System Network Configuration Discovery - case "T1016": - Simulations.Discovery.SystemNetworkConfigurationDiscovery(log); - break; + //T1016 System Network Configuration Discovery + case "T1016": + Simulations.Discovery.SystemNetworkConfigurationDiscovery(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; + // 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; - //T1083 File and Directory Discovery - case "T1083": - Simulations.Discovery.FileAndDirectoryDiscovery(log); - break; + //T1083 File and Directory Discovery + case "T1083": + Simulations.Discovery.FileAndDirectoryDiscovery(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; + //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; + //T1046 - Network Service Scanning + case "T1046": + Simulations.Discovery.NetworkServiceDiscovery(playbook_task, 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 "T1087.001": + if (playbook_task.variation == 1) Simulations.Discovery.LocalAccountDiscoveryCmd(log); + else if (playbook_task.variation == 2) Simulations.Discovery.LocalAccountDiscoveryPowerShell(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 "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 "T1007": - Simulations.Discovery.SystemServiceDiscovery(log); - break; + case "T1007": + Simulations.Discovery.SystemServiceDiscovery(log); + break; - case "T1033": - Simulations.Discovery.SystemUserDiscovery(log); - break; + case "T1033": + Simulations.Discovery.SystemUserDiscovery(log); + break; - case "T1049": - Simulations.Discovery.SystemNetworkConnectionsDiscovery(log); - break; + case "T1049": + Simulations.Discovery.SystemNetworkConnectionsDiscovery(log); + break; - case "T1482": - if (playbook_task.variation == 1) Simulations.Discovery.DomainTrustDiscoveryCmd(log); - else Simulations.Discovery.DomainTrustDiscoveryPowerShell(log); - break; + case "T1482": + if (playbook_task.variation == 1) Simulations.Discovery.DomainTrustDiscoveryCmd(log); + else Simulations.Discovery.DomainTrustDiscoveryPowerShell(log); + break; - case "T1201": - Simulations.Discovery.PasswordPolicyDiscovery(log); - break; + case "T1201": + Simulations.Discovery.PasswordPolicyDiscovery(log); + break; - case "T1069.001": - Simulations.Discovery.LocalGroups(log); - break; + case "T1069.001": + Simulations.Discovery.LocalGroups(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; + 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; - case "T1012": - Simulations.Discovery.QueryRegistry(log); - break; + case "T1012": + Simulations.Discovery.QueryRegistry(log); + break; - case "T1518.001": - Simulations.Discovery.SecuritySoftwareDiscovery(log); - break; + case "T1518.001": + Simulations.Discovery.SecuritySoftwareDiscovery(log); + break; - case "T1082": - Simulations.Discovery.SystemInformationDiscovery(log); - break; + case "T1082": + Simulations.Discovery.SystemInformationDiscovery(log); + break; - case "T1124": - Simulations.Discovery.SystemTimeDiscovery(log); - break; + case "T1124": + Simulations.Discovery.SystemTimeDiscovery(log); + break; - //// Lateral Movement //// + //// Lateral Movement //// - //T1021.006 - Windows Remote Management - case "T1021.006": - Simulations.LateralMovement.WinRmCodeExec(playbook_task, log); - break; + //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; + //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; - //T1047 - Windows Management Instrumentation - case "T1047": - Simulations.LateralMovement.ExecuteWmiOnHosts(playbook_task, log); - break; - case "T10531": - if (playbook_task.variation == 1) Simulations.LateralMovement.CreateSchTaskOnHostsCmdline(playbook_task, log); - break; + // Collection - // Collection + // Command and Control - // Command and Control + // Exfiltration - // Exfiltration + // Impact - // Impact + // Other Techniques - // Other Techniques + case "privenum": + Simulations.Discovery.PrivilegeEnumeration(playbook_task.host_target_total, playbook_task.task_sleep, log); + break; - 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/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; From 897f0b8e8f8568292b59740b20ab405a9df8b887 Mon Sep 17 00:00:00 2001 From: mvelazco Date: Sun, 11 Jul 2021 15:58:50 -0400 Subject: [PATCH 14/15] enhancing Kerberoasting (T1558.003) simulation --- PurpleSharp/Lib/Logger.cs | 2 +- PurpleSharp/Lib/Models.cs | 1 + PurpleSharp/Lib/SharpRoast.cs | 17 +++++---- PurpleSharp/Program.cs | 3 +- PurpleSharp/Simulations/CredAccess.cs | 53 +++++++++++++++++++++------ 5 files changed, 55 insertions(+), 21 deletions(-) diff --git a/PurpleSharp/Lib/Logger.cs b/PurpleSharp/Lib/Logger.cs index 786c6f6..02a8289 100644 --- a/PurpleSharp/Lib/Logger.cs +++ b/PurpleSharp/Lib/Logger.cs @@ -84,7 +84,7 @@ 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, "Exception: " + ex.StackTrace); WriteFormattedLog(LogLevel.TINFO, "Simulation Failed"); } diff --git a/PurpleSharp/Lib/Models.cs b/PurpleSharp/Lib/Models.cs index 21c3208..9691670 100644 --- a/PurpleSharp/Lib/Models.cs +++ b/PurpleSharp/Lib/Models.cs @@ -120,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; } 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/Program.cs b/PurpleSharp/Program.cs index 61a79eb..c26760b 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -924,6 +924,7 @@ public static SimulationPlaybookResult ExecuteRemoteTechniquesJsonSerialized(Sim public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) { + // no specific tactic defined if (playbook_task.tactic.Equals("")) { switch (playbook_task.technique_id) @@ -1070,7 +1071,7 @@ public static void ExecutePlaybookTask(PlaybookTask playbook_task, string log) //T1558.003 - Kerberoasting case "T1558.003": - Simulations.CredAccess.Kerberoasting(log, playbook_task.task_sleep); + Simulations.CredAccess.Kerberoasting(playbook_task, log); break; //T1003.001 - LSASS Memory diff --git a/PurpleSharp/Simulations/CredAccess.cs b/PurpleSharp/Simulations/CredAccess.cs index 26b10d8..a6dd6bd 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) From 7946b069a6b9bcbe68065c2d14e7e3e45e992d70 Mon Sep 17 00:00:00 2001 From: mvelazco Date: Sun, 11 Jul 2021 16:38:55 -0400 Subject: [PATCH 15/15] minor fixes --- PurpleSharp/Lib/NamedPipes.cs | 10 ++++---- PurpleSharp/Program.cs | 11 +++----- PurpleSharp/Simulations/CredAccess.cs | 1 - PurpleSharp/Simulations/LateralMovement.cs | 30 ---------------------- 4 files changed, 8 insertions(+), 44 deletions(-) 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/Program.cs b/PurpleSharp/Program.cs index c26760b..631557d 100644 --- a/PurpleSharp/Program.cs +++ b/PurpleSharp/Program.cs @@ -315,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) @@ -351,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"; @@ -836,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); @@ -844,6 +841,7 @@ public static SimulationPlaybookResult ExecuteRemoteTechniquesJsonSerialized(Sim { if (results.Split('\n').Last().Contains("Playbook Finished")) { + Console.WriteLine("[+] Results:"); Console.WriteLine(); Console.WriteLine(results); @@ -1180,9 +1178,6 @@ public static void ExecutePlaybookTask(PlaybookTask playbook_task, string 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 diff --git a/PurpleSharp/Simulations/CredAccess.cs b/PurpleSharp/Simulations/CredAccess.cs index a6dd6bd..5ea5fd7 100644 --- a/PurpleSharp/Simulations/CredAccess.cs +++ b/PurpleSharp/Simulations/CredAccess.cs @@ -197,7 +197,6 @@ public static void LsassMemoryDump(string log) { logger.SimulationFailed(ex); } - } } diff --git a/PurpleSharp/Simulations/LateralMovement.cs b/PurpleSharp/Simulations/LateralMovement.cs index b37348f..c6dfc58 100644 --- a/PurpleSharp/Simulations/LateralMovement.cs +++ b/PurpleSharp/Simulations/LateralMovement.cs @@ -248,35 +248,5 @@ static public void CreateSchTaskOnHostsCmdline(PlaybookTask playbook_task, strin } } - static public void CreateSchTaskOnHosts_Old(int nhost, int sleep, bool cleanup) - { - /* - var rand = new Random(); - int computertype = rand.Next(1, 6); - - List targethosts = Lib.Targets.GetHostTargets(computertype, nhost); - 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) - { - if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) - { - Computer temp = computer; - LateralMovementHelper.CreateRemoteScheduledTask(temp, "powershell.exe", cleanup); - - tasklist.Add(Task.Factory.StartNew(() => - { - LateralMovementHelper.CreateRemoteScheduledTask(computer, command, cleanup); - })); - if (sleep > 0) Thread.Sleep(sleep * 1000); - - } - } - //Task.WaitAll(tasklist.ToArray()); - */ - - } - } } \ No newline at end of file