// stage0 private ActionResult PostStage0(Covenant.Models.Grunts.GruntEncryptedMessage gruntStage0Response) { // Check if this Grunt ID is already active API.Models.Grunt savedGrunt = CovenantClient.ApiGruntsByIdGet(gruntStage0Response.Id); if (savedGrunt == null) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } if (!gruntStage0Response.VerifyHMAC(Convert.FromBase64String(savedGrunt.GruntSharedSecretPassword))) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } Covenant.Models.Grunts.Grunt realGrunt = null; if (savedGrunt.Status != GruntStatus.Uninitialized) { savedGrunt.Status = GruntStatus.Stage0; // We create a new Grunt if this one is not uninitialized API.Models.Grunt tempModel = new API.Models.Grunt { Status = savedGrunt.Status, ListenerId = savedGrunt.ListenerId, CovenantIPAddress = savedGrunt.CovenantIPAddress, GruntSharedSecretPassword = savedGrunt.GruntSharedSecretPassword, Delay = savedGrunt.Delay, Jitter = savedGrunt.Jitter, ConnectAttempts = savedGrunt.ConnectAttempts, DotNetFrameworkVersion = savedGrunt.DotNetFrameworkVersion }; API.Models.Grunt tempGrunt = CovenantClient.ApiGruntsPost(tempModel); realGrunt = Covenant.Models.Grunts.Grunt.Create(tempGrunt); } else { savedGrunt.Status = GruntStatus.Stage0; API.Models.Grunt tempGrunt = CovenantClient.ApiGruntsPut(savedGrunt); realGrunt = Covenant.Models.Grunts.Grunt.Create(tempGrunt); } // EncryptedMessage is the RSA Public Key realGrunt.GruntRSAPublicKey = Convert.ToBase64String(Encrypt.Utilities.AesDecrypt( gruntStage0Response, Convert.FromBase64String(realGrunt.GruntSharedSecretPassword) )); // Generate negotiated session key Aes newAesKey = Aes.Create(); newAesKey.GenerateKey(); realGrunt.GruntNegotiatedSessionKey = Convert.ToBase64String(newAesKey.Key); CovenantClient.ApiGruntsPut(realGrunt.ToModel()); byte[] rsaEncryptedBytes = realGrunt.RSAEncrypt(Convert.FromBase64String(realGrunt.GruntNegotiatedSessionKey)); Covenant.Models.Grunts.GruntEncryptedMessage message = Covenant.Models.Grunts.GruntEncryptedMessage.Create( realGrunt, rsaEncryptedBytes, Convert.FromBase64String(realGrunt.GruntSharedSecretPassword) ); string Stage0Response = message.Id + "," + message.Name + "," + message.IV + "," + message.EncryptedMessage + "," + message.HMAC; // Stage0Response: "Id,Name,Base64(IV),Base64(AES(RSA(SessionKey))),Base64(HMAC)" // Transform response string transformed = this.Profile.Transform(Common.CovenantEncoding.GetBytes(Stage0Response)); // Format transformed response string response = String.Format(this.Profile.HttpPostResponse, transformed); return(Ok(response)); }
private ActionResult PostStage0(API.Models.Grunt egressGrunt, API.Models.Grunt targetGrunt, Covenant.Models.Grunts.GruntEncryptedMessage gruntStage0Response) { if (targetGrunt == null || !gruntStage0Response.VerifyHMAC(Convert.FromBase64String(targetGrunt.GruntSharedSecretPassword))) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } bool egressGruntExists = (egressGrunt != null); Covenant.Models.Grunts.Grunt realTargetGrunt = null; string guid = gruntStage0Response.GUID.Substring(10); if (targetGrunt.Status != GruntStatus.Uninitialized) { // We create a new Grunt if this one is not uninitialized API.Models.Grunt tempModel = new API.Models.Grunt { Id = 0, Guid = gruntStage0Response.GUID.Substring(10), Status = GruntStatus.Stage0, ListenerId = targetGrunt.ListenerId, CovenantIPAddress = targetGrunt.CovenantIPAddress, GruntSharedSecretPassword = targetGrunt.GruntSharedSecretPassword, CommType = targetGrunt.CommType, SmbPipeName = targetGrunt.SmbPipeName, Delay = targetGrunt.Delay, JitterPercent = targetGrunt.JitterPercent, KillDate = targetGrunt.KillDate, ConnectAttempts = targetGrunt.ConnectAttempts, DotNetFrameworkVersion = targetGrunt.DotNetFrameworkVersion, LastCheckIn = DateTime.UtcNow }; API.Models.Grunt tempGrunt = CovenantClient.ApiGruntsPost(tempModel); realTargetGrunt = Covenant.Models.Grunts.Grunt.Create(tempGrunt); } else { targetGrunt.Status = GruntStatus.Stage0; targetGrunt.Guid = guid; targetGrunt.LastCheckIn = DateTime.UtcNow; API.Models.Grunt tempGrunt = CovenantClient.ApiGruntsPut(targetGrunt); realTargetGrunt = Covenant.Models.Grunts.Grunt.Create(tempGrunt); } if (!egressGruntExists) { egressGrunt = realTargetGrunt.ToModel(); } // EncryptedMessage is the RSA Public Key realTargetGrunt.GruntRSAPublicKey = Convert.ToBase64String(Encrypt.Utilities.AesDecrypt( gruntStage0Response, Convert.FromBase64String(realTargetGrunt.GruntSharedSecretPassword) )); // Generate negotiated session key Aes newAesKey = Aes.Create(); newAesKey.GenerateKey(); realTargetGrunt.GruntNegotiatedSessionKey = Convert.ToBase64String(newAesKey.Key); this.CovenantClient.ApiGruntsPut(realTargetGrunt.ToModel()); if (egressGruntExists) { // Add this as Child grunt to Grunt that connects it List <GruntTasking> taskings = this.CovenantClient.ApiTaskingsGet().ToList(); // TODO: Finding the connectTasking this way could cause race conditions, should fix w/ guid of some sort? GruntTasking connectTasking = taskings.Where(GT => GT.Type == GruntTaskingType.Connect && GT.Status == GruntTaskingStatus.Progressed).Reverse().FirstOrDefault(); if (connectTasking == null) { return(NotFound()); } connectTasking = this.CovenantClient.ApiGruntsByIdTaskingsByTidDetailGet(connectTasking.GruntId ?? default, connectTasking.Id ?? default); realTargetGrunt.Hostname = connectTasking.GruntTaskingMessage.Message.Split(",")[0]; this.CovenantClient.ApiGruntsPut(realTargetGrunt.ToModel()); connectTasking.Status = GruntTaskingStatus.Completed; this.CovenantClient.ApiGruntsByIdTaskingsByTidPut(connectTasking.GruntId ?? default, connectTasking.Id ?? default, connectTasking); } byte[] rsaEncryptedBytes = realTargetGrunt.RSAEncrypt(Convert.FromBase64String(realTargetGrunt.GruntNegotiatedSessionKey)); Covenant.Models.Grunts.GruntEncryptedMessage message = null; try { message = this.CreateMessageForGrunt(egressGrunt, realTargetGrunt.ToModel(), rsaEncryptedBytes); } catch (HttpOperationException) { return(NotFound()); } // Transform response string transformed = this.Profile.Transform(Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(message))); // Format transformed response string response = String.Format(this.Profile.HttpPostResponse, transformed); // Stage0Response: "Id,Name,Base64(IV),Base64(AES(RSA(SessionKey))),Base64(HMAC)" return(Ok(response)); }