Skip to content

Commit

Permalink
[backend] Enhance Caldera traces
Browse files Browse the repository at this point in the history
  • Loading branch information
SamuelHassine committed May 31, 2024
1 parent 1358f28 commit b28ad18
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public ExecutionProcess process(@NotNull final Execution execution, @NotNull fin
InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_COMMAND_LINE).value(exploitResult.getCommand()).build()
);
computeExpectationsForAsset(expectations, content, executionEndpoint.getParent(), isInGroup, injectExpectationSignatures);
execution.addTrace(traceInfo("Caldera executed the ability on asset " + asset.getName() + " using " + executionEndpoint.getProcessName() + " (linkID: " + exploitResult.getLinkId() + ")"));
execution.addTrace(traceInfo("Caldera executed the ability on asset " + asset.getName() + " using " + executionEndpoint.getProcessName() + " (paw: " + executionEndpoint.getExternalReference() + ", linkID: " + exploitResult.getLinkId() + ")"));
} else {
execution.addTrace(traceError("Caldera failed to execute the ability on asset " + asset.getName() + " (" + result + ")"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,69 +59,85 @@ public void run() {
List<InjectStatus> injectStatuses = this.injectStatusRepository.pendingForInjectType(CalderaContract.TYPE);
// For each one ask for traces and status
injectStatuses.forEach((injectStatus -> {
log.log(Level.INFO, "Found inject status: " + injectStatus);
log.log(Level.INFO, "Found inject status: " + injectStatus.getId());
// Add traces and close inject if needed.
Instant finalExecutionTime = injectStatus.getTrackingSentDate();
List<String> linkIds = injectStatus.statusIdentifiers();
log.log(Level.INFO, "Found links IDs: " + linkIds);
List<ResultStatus> completedActions = new ArrayList<>();
for (String linkId : linkIds) {
ResultStatus resultStatus = new ResultStatus();
try {
log.log(Level.INFO, "Trying to get result for " + linkId);
resultStatus = this.calderaService.results(linkId);
} catch (Exception e) {
injectStatus.getTraces().add(traceError("Cannot get result for linkID " + linkId + ", injection has failed"));
resultStatus.setFail(true);
completedActions.add(resultStatus);
injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1);
}
if (resultStatus.getPaw() == null) {
if (injectStatus.getTrackingSentDate().isBefore(Instant.now().minus(EXPIRATION_TIME / 60, ChronoUnit.MINUTES))) {
if (linkIds.isEmpty()) {
computeInjectStatus(injectStatus, finalExecutionTime, 0, 0);
computeInject(injectStatus);
} else {
log.log(Level.INFO, "Found links IDs: " + linkIds);
List<ResultStatus> completedActions = new ArrayList<>();
for (String linkId : linkIds) {
ResultStatus resultStatus = new ResultStatus();
try {
log.log(Level.INFO, "Trying to get result for " + linkId);
resultStatus = this.calderaService.results(linkId);
} catch (Exception e) {
injectStatus.getTraces().add(traceError("Cannot get result for linkID " + linkId + ", injection has failed"));
log.log(Level.INFO, "Cannot get result for linkID " + linkId + ", injection has failed");
resultStatus.setFail(true);
completedActions.add(resultStatus);
injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1);
}
} else {
if (resultStatus.isComplete()) {
completedActions.add(resultStatus);
injectStatus.setTrackingTotalSuccess(injectStatus.getTrackingTotalSuccess() + 1);
// Compute biggest execution time
if (resultStatus.getFinish().isAfter(finalExecutionTime)) {
finalExecutionTime = resultStatus.getFinish();
if (resultStatus.getPaw() == null) {
if (injectStatus.getTrackingSentDate().isBefore(Instant.now().minus(EXPIRATION_TIME / 60, ChronoUnit.MINUTES))) {
injectStatus.getTraces().add(traceError("Cannot get result for linkID " + linkId + ", injection has failed"));
log.log(Level.INFO, "Cannot get result for linkID " + linkId + ", injection has failed");
resultStatus.setFail(true);
completedActions.add(resultStatus);
injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1);
}
} else {
if (resultStatus.isComplete()) {
completedActions.add(resultStatus);
if (resultStatus.isFail()) {
injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1);
injectStatus.getTraces().add(traceError("Failed result for linkID " + linkId + " (" + resultStatus.getContent() + ")"));
} else {
injectStatus.setTrackingTotalSuccess(injectStatus.getTrackingTotalSuccess() + 1);
injectStatus.getTraces().add(traceInfo("Success result for linkID " + linkId + " (" + resultStatus.getContent() + ")"));
}
// Compute biggest execution time
if (resultStatus.getFinish().isAfter(finalExecutionTime)) {
finalExecutionTime = resultStatus.getFinish();
}
} else if (injectStatus.getTrackingSentDate().isBefore(Instant.now().minus(5L, ChronoUnit.MINUTES))) {
injectStatus.getTraces().add(traceError("Timeout on linkID " + linkId + ", injection has failed"));
log.log(Level.INFO, "Timeout on linkID " + linkId + ", injection has failed");
resultStatus.setFail(true);
completedActions.add(resultStatus);
injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1);
}
} else if (injectStatus.getTrackingSentDate().isBefore(Instant.now().minus(5L, ChronoUnit.MINUTES))) {
injectStatus.getTraces().add(traceError("Timeout on linkID " + linkId + ", injection has failed"));
resultStatus.setFail(true);
completedActions.add(resultStatus);
injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1);
}
}
}
// Compute status only if all actions are completed
if (!linkIds.isEmpty() && completedActions.size() == linkIds.size()) {
int failedActions = (int) completedActions.stream().filter(ResultStatus::isFail).count();
computeInjectStatus(injectStatus, finalExecutionTime, completedActions.size(), failedActions);
// Update related inject
computeInject(injectStatus);
// Compute status only if all actions are completed
if (completedActions.size() == linkIds.size()) {
int failedActions = (int) completedActions.stream().filter(ResultStatus::isFail).count();
computeInjectStatus(injectStatus, finalExecutionTime, completedActions.size(), failedActions);
// Update related inject
computeInject(injectStatus);
}
}
}));
}

// -- INJECT STATUS --

@Transactional
public void computeInjectStatus(
@NotNull final InjectStatus injectStatus,
@NotNull final Instant finalExecutionTime,
final int completedActions,
final int failedActions) {
boolean hasError = injectStatus.getTraces().stream().anyMatch(trace -> trace.getStatus().equals(ExecutionStatus.ERROR));
injectStatus.setName(hasError ? ExecutionStatus.ERROR : ExecutionStatus.SUCCESS);
injectStatus.getTraces().add(
traceInfo("caldera", "Caldera executed the ability on " + (completedActions - failedActions) + "/" + completedActions + " asset(s)")
);
if (injectStatus.getTraces().stream().filter(injectStatusExecution -> injectStatusExecution.getStatus().equals(ExecutionStatus.ERROR)).count() == completedActions) {
injectStatus.setName(ExecutionStatus.ERROR);
} else if (injectStatus.getTraces().stream().anyMatch(trace -> trace.getStatus().equals(ExecutionStatus.ERROR))) {
injectStatus.setName(ExecutionStatus.PARTIAL);
} else {
injectStatus.setName(ExecutionStatus.SUCCESS);
}
injectStatus.getTraces().add(traceInfo("caldera", "Caldera executed the ability on " + (completedActions - failedActions) + "/" + completedActions + " asset(s)"));
long executionTime = (finalExecutionTime.toEpochMilli() - injectStatus.getTrackingSentDate().toEpochMilli());
injectStatus.setTrackingTotalExecutionTime(executionTime);
injectStatus.setTrackingEndDate(Instant.now());
Expand All @@ -130,7 +146,6 @@ public void computeInjectStatus(

// -- INJECT --

@Transactional
public void computeInject(@NotNull final InjectStatus injectStatus) {
Inject relatedInject = injectStatus.getInject();
relatedInject.setUpdatedAt(Instant.now());
Expand Down

0 comments on commit b28ad18

Please sign in to comment.