// This tasks a command and returns a FactionCommand object of the command and arguments public static FactionCommand ProcessCommand(string Command, string[] Arguments = null, int AgentId = 0) { FactionCommand factionCommand = new FactionCommand(); factionCommand.Command = Command; // process arguments if (Arguments != null) { int index; int position = 0; foreach (string arg in Arguments) { if (!error) { string ParameterName = ""; string ParameterValue = ""; // Check to see if arg starts with a param name if (arg.StartsWith('/')) { index = arg.IndexOf(':'); if (index > 0) { ParameterName = arg.TrimStart('/').Substring(0, index).TrimEnd(':'); ParameterValue = arg.Substring(index + 1); } else { // Hopefully catches the edge case where a positional argument starts with / ParameterValue = arg; } } // Make sure that we have a proper parameter name either by name or position CommandParameter parameter; if (String.IsNullOrEmpty(ParameterName)) { parameter = _taskRepository.GetCommandParameter(factionCommand.Command, position); ParameterValue = arg; } else { parameter = _taskRepository.GetCommandParameter(factionCommand.Command, ParameterName); } // If we couldn't find a matching param, fail out. Else, make sure the param name matches whats was defined if (parameter == null) { error = true; } else { ParameterName = parameter.Name; } // Everything should be defined now. If not, throw an error. if (String.IsNullOrEmpty(ParameterName) || String.IsNullOrEmpty(ParameterValue) || error) { error = true; errorMessage = $"ERROR: Unable to process argument: {arg}"; } else { Dictionary <string, string> argDict = new Dictionary <string, string>(); factionCommand.Arguments[ParameterName] = ParameterValue.Trim(' '); } position++; } } return(factionCommand); } return(factionCommand); }
public async Task Handle(NewConsoleMessage newConsoleMessage, string replyTo, string correlationId) { // Reset Error stuff error = false; errorMessage = ""; // figure out what agent we're dealing with Agent agent = _taskRepository.GetAgent(newConsoleMessage.AgentId); agent.AgentType = _taskRepository.GetAgentType(agent.AgentTypeId); // flesh out and save the ConsoleMessage object ConsoleMessage consoleMessage = new ConsoleMessage(); consoleMessage.AgentId = newConsoleMessage.AgentId; consoleMessage.UserId = newConsoleMessage.UserId; consoleMessage.Agent = agent; consoleMessage.User = _taskRepository.GetUser(consoleMessage.UserId.Value); consoleMessage.Content = newConsoleMessage.Content; consoleMessage.Display = newConsoleMessage.Display; consoleMessage.Received = DateTime.UtcNow; consoleMessage.Type = "AgentTask"; _taskRepository.Add(consoleMessage); // Announce our new message to Rabbit ConsoleMessageAnnouncement messageAnnouncement = new ConsoleMessageAnnouncement(); messageAnnouncement.Success = true; messageAnnouncement.Username = consoleMessage.User.Username; messageAnnouncement.ConsoleMessage = consoleMessage; _eventBus.Publish(messageAnnouncement); // These are the commands we allow. If one of these isn't the first part of a command List <string> allowedActions = new List <string>(); allowedActions.Add("HELP"); allowedActions.Add("SHOW"); allowedActions.Add("LOAD"); allowedActions.Add("SET"); allowedActions.Add("USE"); allowedActions.Add("RUN"); allowedActions.Add("EXIT"); // we assume that the command is a RUN command string action = "RUN"; string[] consoleMessageComponents = consoleMessage.Content.Split(' '); if (consoleMessageComponents.Length > 0) { if (allowedActions.Contains(consoleMessageComponents[0].ToUpper())) { action = consoleMessageComponents[0].ToUpper(); } } // if this is a SHOW or HELP commmand, we won't be sending anything to the agent // so lets take care of that here: AgentDetails.Language = _taskRepository.GetLanguage(consoleMessage.Agent.AgentType.LanguageId); AgentDetails.AvailableModules = _taskRepository.GetModules(AgentDetails.Language.Id); AgentDetails.LoadedModules = _taskRepository.GetAgentModules(consoleMessage.AgentId); AgentDetails.AgentType = consoleMessage.Agent.AgentType; if (action == "HELP") { ConsoleMessage message = ProcessHelpMessage(consoleMessage); _taskRepository.Add(message); ConsoleMessageAnnouncement response = new ConsoleMessageAnnouncement(); response.Success = true; response.Username = "******"; response.ConsoleMessage = message; _eventBus.Publish(response); } else if (action == "SHOW") { ConsoleMessage message = ProcessShowMessage(consoleMessage); _taskRepository.Add(message); ConsoleMessageAnnouncement response = new ConsoleMessageAnnouncement(); response.Success = true; response.Username = "******"; response.ConsoleMessage = message; _eventBus.Publish(response); } else { // We'll be tasking the agent to do something so lets create an agentTask AgentTask agentTask = new AgentTask(); agentTask.Action = action; agentTask.AgentId = consoleMessage.AgentId; agentTask.ConsoleMessageId = consoleMessage.Id; agentTask.ConsoleMessage = consoleMessage; agentTask.Agent = consoleMessage.Agent; // Package the AgentTask into a envelope for seralization & encryption. // Then process the ACTION and populate CONTENTS appropriately Dictionary <String, String> outboundMessage = new Dictionary <String, String>(); outboundMessage.Add("AgentName", agentTask.Agent.Name); outboundMessage.Add("Name", agentTask.Name); outboundMessage.Add("Action", agentTask.Action); // Message formats // * load stdlib // * load dotnet/stdlib // * load transport/dns if (agentTask.Action == "LOAD") { LoadModule msg = new LoadModule(); if (consoleMessageComponents[1].Contains("/")) { msg.Language = consoleMessageComponents[1].Split("/")[0]; msg.Name = consoleMessageComponents[1].Split("/")[0]; } else { msg.Language = (_taskRepository.GetLanguage(consoleMessage.Agent.AgentType.LanguageId)).Name; msg.Name = consoleMessageComponents[1]; } bool LoadSuccess = false; foreach (Module module in AgentDetails.AvailableModules) { if (String.Equals(module.Name, msg.Name, StringComparison.CurrentCultureIgnoreCase)) { _eventBus.Publish(msg, null, null, true); string message = _eventBus.ResponseQueue.Take(); ModuleResponse moduleResponse = JsonConvert.DeserializeObject <ModuleResponse>(message); outboundMessage.Add("Command", moduleResponse.Contents); LoadSuccess = true; AgentUpdated agentUpdated = new AgentUpdated { Success = true, Agent = agentTask.Agent }; _eventBus.Publish(agentUpdated); break; } } if (!LoadSuccess) { error = true; errorMessage = $"Module {msg.Name} is not a valid module. Use the 'show modules' command to view available modules"; } } // Message formats // * set beacon:5 else if (agentTask.Action == "SET") { outboundMessage.Add("Command", consoleMessageComponents[1]); } else if (agentTask.Action == "EXIT") { outboundMessage.Add("Command", "exit"); } // Example commands: // * ls // * ls "C:\Program Files" // * ls /path:"C:\Program Files" if (agentTask.Action == "RUN") { string submittedCommand = consoleMessage.Content; string[] processedArgs = null; // check to see if we have parameters (for example: ls /path:foo) int index = submittedCommand.IndexOf(' '); if (index > 0) { // change submittedCommand to just the first part of the command (ex: ls) submittedCommand = submittedCommand.Substring(0, index); string submittedArgs = consoleMessage.Content.Substring(index + 1); if (submittedArgs.Length > 0) { processedArgs = SplitArguments(submittedArgs); } } // Check if command is available try { Command commandObject = _taskRepository.GetCommand(submittedCommand); if (!AgentDetails.IsModuleLoaded(commandObject.Module)) { error = true; errorMessage = $"The module for this command isn't loaded. You can load it by running: 'load {commandObject.Module.Name}'"; } } catch { error = true; errorMessage = $"{submittedCommand} is not a valid command for this agent. To view available commands, run: 'show commands'"; } if (!error) { FactionCommand factionCommand = ProcessCommand(submittedCommand, processedArgs); string command = factionCommand.Command; if (factionCommand.Arguments.Count > 0) { command = $"{factionCommand.Command} {JsonConvert.SerializeObject(factionCommand.Arguments)}"; } outboundMessage.Add("Command", command); } } // If there's an error, send it back if (error) { ConsoleMessage message = new ConsoleMessage(); message.AgentId = consoleMessage.AgentId; message.AgentTaskId = agentTask.Id; message.UserId = 1; message.Type = "AgentTaskError"; message.Display = errorMessage; _taskRepository.Add(message); ConsoleMessageAnnouncement response = new ConsoleMessageAnnouncement(); response.Success = true; response.Username = "******"; response.ConsoleMessage = message; _eventBus.Publish(response); } // Else, create a new task for the agent else { // update agentTask with final command format and save it agentTask.Command = outboundMessage["Command"]; _taskRepository.Add(agentTask); // update the incoming consoleMessage with this task Id consoleMessage.AgentTaskId = agentTask.Id; _taskRepository.Update(consoleMessage.Id, consoleMessage); string jsonOutboundMessage = JsonConvert.SerializeObject(outboundMessage); Dictionary <string, string> encCommand = Crypto.Encrypt(jsonOutboundMessage, agentTask.Id, agentTask.Agent.AesPassword); // Create a AgentTaskMessage object with the seralized/encrypted message contents AgentTaskMessage agentTaskMessage = new AgentTaskMessage(); agentTaskMessage.Agent = agentTask.Agent; agentTaskMessage.Message = encCommand["encryptedMsg"]; agentTaskMessage.AgentId = consoleMessage.Agent.Id; agentTaskMessage.AgentTaskId = agentTask.Id; agentTaskMessage.AgentTask = agentTask; agentTaskMessage.Hmac = encCommand["hmac"]; agentTaskMessage.Iv = encCommand["iv"]; agentTaskMessage.Sent = false; _taskRepository.Add(agentTaskMessage); } } }
public static ConsoleMessage ProcessHelpMessage(ConsoleMessage consoleMessage) { ConsoleMessage consoleResponse = new ConsoleMessage(); consoleResponse.AgentId = consoleMessage.AgentId; consoleResponse.UserId = 1; consoleResponse.Received = DateTime.UtcNow; consoleResponse.Type = "HelpResponse"; // Remove the leading "HELP ", if we can't do this lets assume its just "help" string recievedCommand = ""; try { recievedCommand = consoleMessage.Content.Remove(0, 5); } catch { consoleResponse.Display = $"Faction Agent Help:\n\n* 'show commands' will return a list of available commands.\n* 'show modules' will show available modules\n* 'help <command>` will give you details about a command\n* 'help <command> /<paramater>' will give you details about a commands paramter"; return(consoleResponse); } FactionCommand factionCommand = ProcessCommand(recievedCommand); if (factionCommand.Arguments.Count > 0) { string ParameterName = factionCommand.Arguments.Keys.Last().ToString(); CommandParameter parameter; try { parameter = _taskRepository.GetCommandParameter(factionCommand.Command, ParameterName); if (String.IsNullOrEmpty(parameter.Help)) { consoleResponse.Display = $"No help available for parameter: {parameter.Name} under command {factionCommand.Command}"; } else { consoleResponse.Display = $"Name: {parameter.Name}\nRequired: {parameter.Required}\nAccepted Values: {parameter.Values}\n\n## Help\n{parameter.Help}"; } } catch { consoleResponse.Display = $"No parameter named {ParameterName} found for command {factionCommand.Command}"; } } else { try { Command command = _taskRepository.GetCommand(factionCommand.Command); if (String.IsNullOrEmpty(command.Help)) { consoleResponse.Display = $"No help available for command {command.Name}"; } else { consoleResponse.Display = $"Name: {command.Name}"; consoleResponse.Display += $"\nDescription: {command.Description}"; consoleResponse.Display += $"\nMitre ATT&CK Reference: {command.MitreReference}"; consoleResponse.Display += $"\nOpsecSafe: {command.OpsecSafe}"; consoleResponse.Display += $"\nLoaded: {AgentDetails.IsCommandAvailable(command)}"; consoleResponse.Display += $"\n\nHelp:\n{command.Help}\n"; List <CommandParameter> parameters = _taskRepository.GetCommandParameters(command.Id); if (parameters.Count() > 0) { string parameterText = "\nParameters:"; foreach (CommandParameter param in parameters) { parameterText += $"\nName: {param.Name}"; parameterText += $"\nRequired: {param.Required.ToString()}"; if (param.Position.HasValue) { parameterText += $"\nPosition: {param.Position.Value.ToString()}"; } else { parameterText += $"\nPosition: N/A"; } parameterText += $"\nHelp: {param.Help}\n"; } consoleResponse.Display += parameterText; } if (!String.IsNullOrEmpty(command.Artifacts)) { consoleResponse.Display += "\n\nArtifacts:"; string[] artifacts = command.Artifacts.Split(","); foreach (string artifact in artifacts) { consoleResponse.Display += $"\n* {artifact}"; } } consoleResponse.Display += "\n"; } } catch { consoleResponse.Display = $"No command found named {recievedCommand}"; } } return(consoleResponse); }