public static void StartProcess_old(string binary, string cmdline, Lib.Logger logger, bool cleanup = false) { if (!cleanup) { logger.TimestampInfo("Executing Command: " + cmdline); } else { logger.TimestampInfo("Executing Cleanup Command: " + cmdline); } const uint NORMAL_PRIORITY_CLASS = 0x0020; bool retValue; 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); retValue = WinAPI.CreateProcess(null, cmdline, ref pSec, ref tSec, false, NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref sInfo, out pInfo); if (retValue && cleanup == false) { logger.TimestampInfo(String.Format("Process successfully created. (PID): " + pInfo.dwProcessId)); } else if (retValue != false && cleanup == false) { logger.TimestampInfo("Could not start process!"); } }
public static void StartProcess(string binary, string cmdline) { const uint NORMAL_PRIORITY_CLASS = 0x0020; bool retValue; string Application; if (binary == "powershell") { Application = Environment.GetEnvironmentVariable("windir") + @"\System32\WindowsPowerShell\v1.0\" + binary + ".exe " + cmdline; Console.WriteLine(Environment.GetEnvironmentVariable("windir") + @"\System32\WindowsPowerShell\v1.0\" + binary + ".exe " + cmdline); } else { Application = Environment.GetEnvironmentVariable("windir") + @"\" + binary + ".exe " + @cmdline; } string CommandLine = @cmdline; 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); retValue = WinAPI.CreateProcess(null, cmdline, ref pSec, ref tSec, false, NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref sInfo, out pInfo); Console.WriteLine("Process ID (PID): " + pInfo.dwProcessId); Console.WriteLine("Process Handle : " + pInfo.hProcess); }
public static void StartProcessAsUser(string binary, string cmdline, string domain, string username, string password) { Structs.STARTUPINFO startupInfo = new Structs.STARTUPINFO(); Structs.LogonFlags lflags = new Structs.LogonFlags(); //UInt32 exitCode = 123456; Structs.PROCESS_INFORMATION processInfo = new Structs.PROCESS_INFORMATION(); String command = @"c:\windows\notepad.exe"; String currentDirectory = System.IO.Directory.GetCurrentDirectory(); WinAPI.CreateProcessWithLogonW(username, domain, password, lflags, command, command, (UInt32)0, (UInt32)0, currentDirectory, ref startupInfo, out processInfo); }
public static void StartProcessApi(string binary, string cmdline, Lib.Logger logger) { const uint NORMAL_PRIORITY_CLASS = 0x0020; bool retValue; 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); logger.TimestampInfo(String.Format("Using the Win32 API call CreateProcess to execute: '{0}'", cmdline)); retValue = WinAPI.CreateProcess(null, cmdline, ref pSec, ref tSec, false, NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref sInfo, out pInfo); if (retValue) { logger.TimestampInfo(String.Format("Process successfully created. (PID): " + pInfo.dwProcessId)); } else { logger.TimestampInfo("Could not start process!"); } }
public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref Structs.SECURITY_ATTRIBUTES lpProcessAttributes, ref Structs.SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref Structs.STARTUPINFO2 lpStartupInfo, out Structs.PROCESS_INFORMATION lpProcessInformation);
public static extern bool CreateProcessWithLogonW(String userName, String domain, String password, Structs.LogonFlags logonFlags, String applicationName, String commandLine, Structs.CreationFlags creationFlags, UInt32 environment, String currentDirectory, ref Structs.STARTUPINFO startupInfo, out Structs.PROCESS_INFORMATION processInformation);
public static bool SpoofParent(int parentProcessId, string binaryPath, string cmdLine) { // STARTUPINFOEX members const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000; // STARTUPINFO members (dwFlags and wShowWindow) const int STARTF_USESTDHANDLES = 0x00000100; const int STARTF_USESHOWWINDOW = 0x00000001; const short SW_HIDE = 0x0000; // dwCreationFlags const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000; const uint CREATE_NO_WINDOW = 0x08000000; //var error = Marshal.GetLastWin32Error(); var pInfo = new Structs.PROCESS_INFORMATION(); var siEx = new Structs.STARTUPINFOEX(); // Be sure to set the cb member of the STARTUPINFO structure to sizeof(STARTUPINFOEX). siEx.StartupInfo.cb = Marshal.SizeOf(siEx); IntPtr lpValueProc = IntPtr.Zero; IntPtr hSourceProcessHandle = IntPtr.Zero; if (parentProcessId > 0) { var lpSize = IntPtr.Zero; var success = WinAPI.InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize); if (success || lpSize == IntPtr.Zero) { return(false); } Console.WriteLine("successfully used InitializeProcThreadAttributeList "); siEx.lpAttributeList = Marshal.AllocHGlobal(lpSize); success = WinAPI.InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, ref lpSize); if (!success) { return(false); } Console.WriteLine("successfully used InitializeProcThreadAttributeList"); IntPtr parentHandle = WinAPI.OpenProcess(Structs.ProcessAccessFlags.CreateProcess | Structs.ProcessAccessFlags.DuplicateHandle, false, parentProcessId); if (parentHandle == null) { return(false); } Console.WriteLine("obtained a handle to parent process"); // This value should persist until the attribute list is destroyed using the DeleteProcThreadAttributeList function lpValueProc = Marshal.AllocHGlobal(IntPtr.Size); Marshal.WriteIntPtr(lpValueProc, parentHandle); success = WinAPI.UpdateProcThreadAttribute(siEx.lpAttributeList, 0, (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, lpValueProc, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero); if (!success) { return(false); } Console.WriteLine("successfully used UpdateProcThreadAttribute"); IntPtr hCurrent = System.Diagnostics.Process.GetCurrentProcess().Handle; IntPtr hNewParent = WinAPI.OpenProcess(Structs.ProcessAccessFlags.DuplicateHandle, true, parentProcessId); if (hNewParent == null) { return(false); } Console.WriteLine("successfully used OpenProcess"); } siEx.StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; siEx.StartupInfo.wShowWindow = SW_HIDE; var ps = new Structs.SECURITY_ATTRIBUTES(); var ts = new Structs.SECURITY_ATTRIBUTES(); ps.nLength = Marshal.SizeOf(ps); ts.nLength = Marshal.SizeOf(ts); //bool ret = CreateProcess(null, command, ref ps, ref ts, true, EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW, IntPtr.Zero, null, ref siEx, out pInfo); Console.WriteLine("About to call create processd"); bool ret = WinAPI.CreateProcess(binaryPath, cmdLine, ref ps, ref ts, true, EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW, IntPtr.Zero, null, ref siEx, out pInfo); Console.WriteLine(Marshal.GetLastWin32Error()); if (!ret) { Console.WriteLine("[!] Proccess failed to execute!"); return(false); } Console.WriteLine("successfully used CreateProcess"); return(true); }
// From https://www.codeproject.com/Articles/35773/Subverting-Vista-UAC-in-Both-32-and-64-bit-Archite public static bool StartProcessAsLoggedUser(String applicationName, string startingDir, out Structs.PROCESS_INFORMATION procInfo) { int winlogonPid = 0; IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero; procInfo = new Structs.PROCESS_INFORMATION(); // obtain the currently active session id; every logged on user in the system has a unique session id uint dwSessionId = WinAPI.WTSGetActiveConsoleSessionId(); // obtain the process id of the winlogon process that is running within the currently active session // -- chaged by ty // Process[] processes = Process.GetProcessesByName("winlogon"); Process[] processes = Process.GetProcessesByName("explorer"); foreach (Process p in processes) { if ((uint)p.SessionId == dwSessionId) { winlogonPid = p.Id; } } // obtain a handle to the winlogon process //hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid); hProcess = WinAPI.OpenProcess(Structs.ProcessAccessFlags.CreateProcess | Structs.ProcessAccessFlags.DuplicateHandle | Structs.ProcessAccessFlags.QueryInformation, false, winlogonPid); // obtain a handle to the access token of the winlogon process if (!WinAPI.OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken)) { WinAPI.CloseHandle(hProcess); return(false); } // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser // I would prefer to not have to use a security attribute variable and to just // simply pass null and inherit (by default) the security attributes // of the existing token. However, in C# structures are value types and therefore // cannot be assigned the null value. Structs.SECURITY_ATTRIBUTES sa = new Structs.SECURITY_ATTRIBUTES(); sa.nLength = Marshal.SizeOf(sa); // copy the access token of the winlogon process; the newly created token will be a primary token if (!WinAPI.DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)Structs.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)Structs.TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) { WinAPI.CloseHandle(hProcess); WinAPI.CloseHandle(hPToken); return(false); } // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning // the window station has a desktop that is invisible and the process is incapable of receiving // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user // interaction with the new process. Structs.STARTUPINFO2 si = new Structs.STARTUPINFO2(); si.cb = (int)Marshal.SizeOf(si); si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop // flags that specify the priority and creation method of the process int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; // create a new process in the current user's logon session bool result = WinAPI.CreateProcessAsUser(hUserTokenDup, // client's access token null, // file to execute applicationName, // command line ref sa, // pointer to process SECURITY_ATTRIBUTES ref sa, // pointer to thread SECURITY_ATTRIBUTES false, // handles are not inheritable dwCreationFlags, // creation flags IntPtr.Zero, // pointer to new environment block startingDir, // name of current directory ref si, // pointer to STARTUPINFO structure out procInfo // receives information about new process ); // invalidate the handles WinAPI.CloseHandle(hProcess); WinAPI.CloseHandle(hPToken); WinAPI.CloseHandle(hUserTokenDup); return(result); // return the result }
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); } }