private APIModels.GruntTaskingMessage GetGruntTaskingMessage(APIModels.GruntTasking tasking, APIModels.DotNetVersion version) { string Message = ""; switch (tasking.Type) { case APIModels.GruntTaskingType.Assembly: switch (version) { case APIModels.DotNetVersion.Net35: Message = Convert.ToBase64String(this.GetCompressedILAssembly35(tasking.GruntTask.Name)); if (tasking.Parameters.Any()) { Message += "," + String.Join(",", tasking.Parameters.Select(P => Convert.ToBase64String(Common.CovenantEncoding.GetBytes(P)))); } break; case APIModels.DotNetVersion.Net40: Message = Convert.ToBase64String(this.GetCompressedILAssembly40(tasking.GruntTask.Name)); if (tasking.Parameters.Any()) { Message += "," + String.Join(",", tasking.Parameters.Select(P => Convert.ToBase64String(Common.CovenantEncoding.GetBytes(P)))); } break; } break; case APIModels.GruntTaskingType.SetOption: if (tasking.Parameters.Count >= 2) { Message = tasking.Parameters[0] + "," + tasking.Parameters[1]; } break; case APIModels.GruntTaskingType.Connect: if (tasking.Parameters.Count >= 2) { Message = tasking.Parameters[0] + "," + tasking.Parameters[1]; } break; case APIModels.GruntTaskingType.Disconnect: if (tasking.Parameters.Count >= 1) { Message = tasking.Parameters[0]; } break; default: Message = string.Join(",", tasking.Parameters.Select(P => Convert.ToBase64String(Common.CovenantEncoding.GetBytes(P)))); break; } return(new APIModels.GruntTaskingMessage { Type = tasking.Type, Name = tasking.Name, Message = Message, Token = tasking.GruntTask == null ? false : tasking.GruntTask.TokenTask }); }
private async Task <APIModels.GruntTasking> MarkTasked(APIModels.GruntTasking tasking) { if (tasking == null) { return(null); } tasking.Status = APIModels.GruntTaskingStatus.Tasked; tasking.TaskingTime = DateTime.UtcNow; return(await _client.ApiTaskingsPutAsync(tasking)); }
/// <summary> /// Initializes a new instance of the GruntCommand class. /// </summary> public GruntCommand(string command, System.DateTime commandTime, int commandOutputId, string userId, int?id = default(int?), CommandOutput commandOutput = default(CommandOutput), CovenantUser user = default(CovenantUser), int?gruntTaskingId = default(int?), GruntTasking gruntTasking = default(GruntTasking), int?gruntId = default(int?)) { Id = id; Command = command; CommandTime = commandTime; CommandOutputId = commandOutputId; CommandOutput = commandOutput; UserId = userId; User = user; GruntTaskingId = gruntTaskingId; GruntTasking = gruntTasking; GruntId = gruntId; CustomInit(); }
/// <summary> /// Validate the object. /// </summary> /// <exception cref="ValidationException"> /// Thrown if validation fails /// </exception> public virtual void Validate() { if (Command == null) { throw new ValidationException(ValidationRules.CannotBeNull, "Command"); } if (UserId == null) { throw new ValidationException(ValidationRules.CannotBeNull, "UserId"); } if (CommandOutput != null) { CommandOutput.Validate(); } if (GruntTasking != null) { GruntTasking.Validate(); } }
private int GetTaskingHashCode(APIModels.GruntTasking tasking) { if (tasking != null) { int code = tasking.Id ?? default; code ^= tasking.GruntId; code ^= tasking.GruntTaskId ?? default; code ^= tasking.GruntCommandId; foreach (char c in tasking.Name) { code ^= c; } foreach (char c in tasking.GruntCommand.CommandTime.ToString()) { code ^= c; } return(code); } return(Guid.NewGuid().GetHashCode()); }
private async Task PostStage0(APIModels.Grunt egressGrunt, APIModels.Grunt targetGrunt, ModelUtilities.GruntEncryptedMessage gruntStage0Response, string guid) { if (targetGrunt == null || !gruntStage0Response.VerifyHMAC(Convert.FromBase64String(targetGrunt.GruntSharedSecretPassword))) { // Always return NotFound, don't give away unnecessary info this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.NotFound, Message = "", Tasking = null }); return; } bool egressGruntExists = egressGrunt != null; if (targetGrunt.Status != APIModels.GruntStatus.Uninitialized) { // We create a new Grunt if this one is not uninitialized APIModels.Grunt tempModel = new APIModels.Grunt { Id = 0, Name = Utilities.CreateShortGuid(), Guid = guid, OriginalServerGuid = Utilities.CreateShortGuid(), Status = APIModels.GruntStatus.Stage0, ListenerId = targetGrunt.ListenerId, Listener = targetGrunt.Listener, ImplantTemplateId = targetGrunt.ImplantTemplateId, ImplantTemplate = targetGrunt.ImplantTemplate, GruntSharedSecretPassword = targetGrunt.GruntSharedSecretPassword, SmbPipeName = targetGrunt.SmbPipeName, Delay = targetGrunt.Delay, JitterPercent = targetGrunt.JitterPercent, KillDate = targetGrunt.KillDate, ConnectAttempts = targetGrunt.ConnectAttempts, DotNetFrameworkVersion = targetGrunt.DotNetFrameworkVersion, LastCheckIn = DateTime.UtcNow }; targetGrunt = await _client.ApiGruntsPostAsync(tempModel); } else { targetGrunt.Status = APIModels.GruntStatus.Stage0; targetGrunt.Guid = guid; targetGrunt.LastCheckIn = DateTime.UtcNow; targetGrunt = await _client.ApiGruntsPutAsync(targetGrunt); } if (!egressGruntExists) { egressGrunt = targetGrunt; } // EncryptedMessage is the RSA Public Key targetGrunt.GruntRSAPublicKey = Convert.ToBase64String(EncryptUtilities.AesDecrypt( gruntStage0Response, Convert.FromBase64String(targetGrunt.GruntSharedSecretPassword) )); // Generate negotiated session key using (Aes newAesKey = Aes.Create()) { newAesKey.GenerateKey(); targetGrunt.GruntNegotiatedSessionKey = Convert.ToBase64String(newAesKey.Key); await _client.ApiGruntsPutAsync(targetGrunt); } if (egressGruntExists) { // Add this as Child grunt to Grunt that connects it List <APIModels.GruntTasking> taskings = _client.ApiTaskingsGet().ToList(); // TODO: Finding the connectTasking this way could cause race conditions, should fix w/ guid of some sort? APIModels.GruntTasking connectTasking = taskings.Where(GT => GT.Type == APIModels.GruntTaskingType.Connect && GT.Status == APIModels.GruntTaskingStatus.Progressed).Reverse().FirstOrDefault(); if (connectTasking == null) { this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.NotFound, Message = "", Tasking = null }); return; } APIModels.GruntTaskingMessage tmessage = this.GetGruntTaskingMessage(connectTasking, targetGrunt.DotNetFrameworkVersion); targetGrunt.Hostname = tmessage.Message.Split(",")[0]; await _client.ApiGruntsPutAsync(targetGrunt); connectTasking.Status = APIModels.GruntTaskingStatus.Completed; await _client.ApiTaskingsPutAsync(connectTasking); } byte[] rsaEncryptedBytes = EncryptUtilities.GruntRSAEncrypt(targetGrunt, Convert.FromBase64String(targetGrunt.GruntNegotiatedSessionKey)); ModelUtilities.GruntEncryptedMessage message = null; try { message = this.CreateMessageForGrunt(egressGrunt, targetGrunt, rsaEncryptedBytes); } catch (HttpOperationException) { this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.NotFound, Message = "", Tasking = null }); return; } // Transform response // Stage0Response: "Id,Name,Base64(IV),Base64(AES(RSA(SessionKey))),Base64(HMAC)" string transformed = this._utilities.ProfileTransform(_transform, Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(message))); this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.Ok, Message = transformed, Tasking = null }); return; }
private async Task InternalRead(string guid) { try { APIModels.Grunt grunt = await CheckInGrunt(await GetGruntForGuid(guid)); if (grunt == null) { // Invalid GUID. May not be legitimate Grunt request, respond Ok this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.Ok, Message = "" }); } else { IList <APIModels.GruntTasking> gruntTaskings = await _client.ApiGruntsByIdTaskingsSearchUninitializedGetAsync(grunt.Id ?? default); if (gruntTaskings == null || gruntTaskings.Count == 0) { // No GruntTasking assigned. Respond with empty template this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.Ok, Message = "" }); } else { foreach (APIModels.GruntTasking tasking in gruntTaskings) { APIModels.GruntTasking gruntTasking = tasking; if (gruntTasking.Type == APIModels.GruntTaskingType.Assembly && gruntTasking.GruntTask == null) { // Can't find corresponding task. Should never reach this point. Will just respond NotFound. this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.NotFound, Message = "", Tasking = gruntTasking }); } else { gruntTasking.Grunt = gruntTasking.GruntId == grunt.Id ? grunt : await _client.ApiGruntsByIdGetAsync(gruntTasking.GruntId); ModelUtilities.GruntEncryptedMessage message = null; try { message = this.CreateMessageForGrunt(grunt, gruntTasking.Grunt, this.GetGruntTaskingMessage(gruntTasking, gruntTasking.Grunt.DotNetFrameworkVersion)); // Transform response string transformed = this._utilities.ProfileTransform(_transform, Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(message))); this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.Ok, Message = transformed, Tasking = gruntTasking }); } catch (HttpOperationException) { gruntTasking.Status = APIModels.GruntTaskingStatus.Aborted; await _client.ApiTaskingsPutAsync(gruntTasking); this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.NotFound, Message = "", Tasking = null }); } } } } } } catch (Exception) { this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.NotFound, Message = "" }); } }