Skip to content

Commit

Permalink
[backend] send encoded command into implant (#1831)
Browse files Browse the repository at this point in the history
Signed-off-by: Marine LM <[email protected]>
  • Loading branch information
MarineLeM authored Dec 3, 2024
1 parent ad4a804 commit 62aec5d
Show file tree
Hide file tree
Showing 25 changed files with 358 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,15 @@ public ExecutionProcess process(
List<InjectExpectationSignature> injectExpectationSignatures =
new ArrayList<>();
if (injectorContract.getPayload() != null) {
switch (injectorContract.getPayload().getType()) {
case "Command":
switch (injectorContract.getPayload().getTypeEnum()) {
case PayloadType.COMMAND:
injectExpectationSignatures.add(
InjectExpectationSignature.builder()
.type(EXPECTATION_SIGNATURE_TYPE_PROCESS_NAME)
.value(executionEndpoint.getProcessName())
.build());
break;
case "Executable":
case PayloadType.EXECUTABLE:
Executable payloadExecutable =
(Executable) Hibernate.unproxy(injectorContract.getPayload());
injectExpectationSignatures.add(
Expand All @@ -163,7 +163,7 @@ public ExecutionProcess process(
.build());
// TODO File hash
break;
case "FileDrop":
case PayloadType.FILE_DROP:
FileDrop payloadFileDrop =
(FileDrop) Hibernate.unproxy(injectorContract.getPayload());
injectExpectationSignatures.add(
Expand All @@ -173,7 +173,7 @@ public ExecutionProcess process(
.build());
// TODO File hash
break;
case "DnsResolution":
case PayloadType.DNS_RESOLUTION:
DnsResolution payloadDnsResolution =
(DnsResolution)
Hibernate.unproxy(injectorContract.getPayload());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ public Ability createAbility(Payload payload) {
if (payload.getCleanupCommand() != null) {
cleanupCommands.add(payload.getCleanupCommand());
}
switch (payload.getType()) {
case "Command":
switch (payload.getTypeEnum()) {
case PayloadType.COMMAND:
Command payloadCommand = (Command) Hibernate.unproxy(payload);
Arrays.stream(payloadCommand.getPlatforms())
.forEach(
Expand All @@ -84,7 +84,7 @@ public Ability createAbility(Payload payload) {
executors.add(executor);
});
break;
case "Executable":
case PayloadType.EXECUTABLE:
Executable payloadExecutable = (Executable) Hibernate.unproxy(payload);
Arrays.stream(payloadExecutable.getPlatforms())
.forEach(
Expand Down Expand Up @@ -127,7 +127,7 @@ public Ability createAbility(Payload payload) {
executors.add(executor);
});
break;
case "FileDrop":
case PayloadType.FILE_DROP:
FileDrop payloadFileDrop = (FileDrop) Hibernate.unproxy(payload);
Arrays.stream(payloadFileDrop.getPlatforms())
.forEach(
Expand Down Expand Up @@ -164,7 +164,7 @@ public Ability createAbility(Payload payload) {
executors.add(executor);
});
break;
case "DnsResolution":
case PayloadType.DNS_RESOLUTION:
DnsResolution payloadDnsResolution = (DnsResolution) Hibernate.unproxy(payload);
Arrays.stream(payloadDnsResolution.getPlatforms())
.forEach(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.openbas.migration;

import java.sql.Connection;
import java.sql.Statement;
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;
import org.springframework.stereotype.Component;

@Component
public class V3_49__Drop_injects_payloads_table extends BaseJavaMigration {

@Override
public void migrate(Context context) throws Exception {
Connection connection = context.getConnection();
Statement statement = connection.createStatement();

statement.executeUpdate("DROP TABLE IF EXISTS injects_payloads");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import io.openbas.rest.document.form.DocumentUpdateInput;
import io.openbas.rest.exception.ElementNotFoundException;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.service.FileService;
import io.openbas.service.InjectService;
import io.openbas.utils.pagination.SearchPaginationInput;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.transaction.Transactional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.helper.TeamHelper;
import io.openbas.rest.inject.form.InjectExpectationResultsByAttackPattern;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.service.*;
import io.openbas.telemetry.Tracing;
import io.openbas.utils.AtomicTestingUtils.ExpectationResultsByType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import io.openbas.database.model.InjectTestStatus;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.inject.output.InjectOutput;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.service.InjectSearchService;
import io.openbas.service.InjectService;
import io.openbas.service.InjectTestStatusService;
import io.openbas.utils.pagination.SearchPaginationInput;
import io.swagger.v3.oas.annotations.Operation;
Expand Down
16 changes: 13 additions & 3 deletions openbas-api/src/main/java/io/openbas/rest/inject/InjectApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
import io.openbas.rest.exception.ElementNotFoundException;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.inject.form.*;
import io.openbas.rest.inject.service.ExecutableInjectService;
import io.openbas.rest.inject.service.InjectDuplicateService;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.service.InjectSearchService;
import io.openbas.service.InjectService;
import io.openbas.service.ScenarioService;
import io.openbas.telemetry.Tracing;
import io.openbas.utils.pagination.SearchPaginationInput;
Expand Down Expand Up @@ -73,13 +74,14 @@ public class InjectApi extends RestBehavior {
private final InjectRepository injectRepository;
private final InjectDocumentRepository injectDocumentRepository;
private final TeamRepository teamRepository;
private final AssetService assetService;
private final AssetGroupService assetGroupService;
private final TagRepository tagRepository;
private final DocumentRepository documentRepository;
private final AssetService assetService;
private final AssetGroupService assetGroupService;
private final ExecutionContextService executionContextService;
private final ScenarioService scenarioService;
private final InjectService injectService;
private final ExecutableInjectService executableInjectService;
private final InjectSearchService injectSearchService;
private final InjectDuplicateService injectDuplicateService;

Expand Down Expand Up @@ -163,6 +165,14 @@ public Inject injectExecutionCallback(
return injectRepository.save(inject);
}

@GetMapping(INJECT_URI + "/{injectId}/executable-payload")
@Tracing(name = "Get payload ready to be executed", layer = "api", operation = "GET")
public Payload getExecutablePayloadInject(@PathVariable @NotBlank final String injectId) {
return executableInjectService.getExecutablePayloadInject(injectId);
}

// -- EXERCISES --

@Transactional(rollbackFor = Exception.class)
@PutMapping(INJECT_URI + "/{exerciseId}/{injectId}")
@PreAuthorize("isExercisePlanner(#exerciseId)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import io.openbas.database.model.InjectTestStatus;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.inject.output.InjectOutput;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.service.InjectSearchService;
import io.openbas.service.InjectService;
import io.openbas.service.InjectTestStatusService;
import io.openbas.telemetry.Tracing;
import io.openbas.utils.pagination.SearchPaginationInput;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package io.openbas.rest.inject.service;

import com.fasterxml.jackson.databind.node.ObjectNode;
import io.openbas.database.model.*;
import io.openbas.database.repository.InjectRepository;
import io.openbas.rest.exception.ElementNotFoundException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class ExecutableInjectService {

private final InjectRepository injectRepository;
private static final Pattern argumentsRegex = Pattern.compile("#\\{([^#{}]+)}");

private List<String> getArgumentsFromCommandLines(String command) {
Matcher matcher = argumentsRegex.matcher(command);
List<String> commandParameters = new ArrayList<>();

while (matcher.find()) {
commandParameters.add(matcher.group(1));
}

return commandParameters;
}

private String replaceArgumentsByValue(
String command, List<PayloadArgument> defaultArguments, ObjectNode injectContent) {

List<String> arguments = getArgumentsFromCommandLines(command);

for (String argument : arguments) {
String value = "";

// Try to get the value from injectContent
if (injectContent.has(argument) && !injectContent.get(argument).asText().isEmpty()) {
value = injectContent.get(argument).asText();
} else {
// Fallback to defaultContent
value =
defaultArguments.stream()
.filter(a -> a.getKey().equals(argument))
.map(PayloadArgument::getDefaultValue)
.findFirst()
.orElse("");
}

command = command.replace("#{" + argument + "}", value);
}

return command;
}

private String processAndEncodeCommand(
String command,
String executor,
List<PayloadArgument> defaultArguments,
ObjectNode injectContent,
String obfuscator) {
String computedCommand = replaceArgumentsByValue(command, defaultArguments, injectContent);

if (executor.equals("cmd")) {
computedCommand = computedCommand.trim().replace("\n", " & ");
}

if (obfuscator.equals("base64")) {
return Base64.getEncoder().encodeToString(computedCommand.getBytes());
}

return computedCommand;
}

public Payload getExecutablePayloadInject(String injectId) {
Inject inject =
this.injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new);
InjectorContract contract =
inject.getInjectorContract().orElseThrow(ElementNotFoundException::new);

// prerequisite
contract
.getPayload()
.getPrerequisites()
.forEach(
prerequisite -> {
if (prerequisite.getCheckCommand() != null) {
prerequisite.setCheckCommand(
processAndEncodeCommand(
prerequisite.getCheckCommand(),
prerequisite.getExecutor(),
contract.getPayload().getArguments(),
inject.getContent(),
"base64"));
}
if (prerequisite.getGetCommand() != null) {
prerequisite.setGetCommand(
processAndEncodeCommand(
prerequisite.getGetCommand(),
prerequisite.getExecutor(),
contract.getPayload().getArguments(),
inject.getContent(),
"base64"));
}
});

// cleanup
if (contract.getPayload().getCleanupCommand() != null) {
contract
.getPayload()
.setCleanupCommand(
processAndEncodeCommand(
contract.getPayload().getCleanupCommand(),
contract.getPayload().getCleanupExecutor(),
contract.getPayload().getArguments(),
inject.getContent(),
"base64"));
}

// Command
if (contract.getPayload().getTypeEnum().equals(PayloadType.COMMAND)) {
Command payloadCommand = (Command) contract.getPayload();
payloadCommand.setContent(
processAndEncodeCommand(
payloadCommand.getContent(),
payloadCommand.getExecutor(),
contract.getPayload().getArguments(),
inject.getContent(),
"base64"));
return payloadCommand;
}

return contract.getPayload();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.openbas.service;
package io.openbas.rest.inject.service;

import static io.openbas.utils.StringUtils.duplicateString;
import static java.time.Instant.now;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public Payload updatePayload(
fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds())));
payload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds())));
payload.setUpdatedAt(Instant.now());
switch (PayloadType.fromString(payload.getType())) {
switch (payload.getTypeEnum()) {
case PayloadType.COMMAND:
Command payloadCommand = (Command) Hibernate.unproxy(payload);
payloadCommand.setUpdateAttributes(input);
Expand Down Expand Up @@ -247,7 +247,7 @@ public Payload upsertPayload(@Valid @RequestBody PayloadUpsertInput input) {
input.getAttackPatternsExternalIds())));
existingPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds())));
existingPayload.setUpdatedAt(Instant.now());
switch (PayloadType.fromString(existingPayload.getType())) {
switch (existingPayload.getTypeEnum()) {
case PayloadType.COMMAND:
Command payloadCommand = (Command) Hibernate.unproxy(existingPayload);
payloadCommand.setUpdateAttributes(input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import io.openbas.database.model.*;
import io.openbas.rest.exercise.service.ExerciseService;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.rest.report.form.ReportInjectCommentInput;
import io.openbas.rest.report.form.ReportInput;
import io.openbas.rest.report.model.Report;
import io.openbas.rest.report.service.ReportService;
import io.openbas.service.InjectService;
import jakarta.transaction.Transactional;
import jakarta.validation.Valid;
import java.util.UUID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import io.openbas.database.repository.ImportMapperRepository;
import io.openbas.rest.exception.ElementNotFoundException;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.rest.scenario.form.InjectsImportInput;
import io.openbas.rest.scenario.response.ImportTestSummary;
import io.openbas.service.InjectImportService;
import io.openbas.service.InjectService;
import io.openbas.service.ScenarioService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.transaction.Transactional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import io.openbas.rest.atomic_testing.form.InjectResultOutput;
import io.openbas.rest.atomic_testing.form.InjectResultOverviewOutput;
import io.openbas.rest.exception.ElementNotFoundException;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.utils.InjectMapper;
import io.openbas.utils.pagination.SearchPaginationInput;
import jakarta.annotation.Resource;
Expand All @@ -45,9 +46,7 @@ public class AtomicTestingService {
private final AssetGroupRepository assetGroupRepository;
private final AssetRepository assetRepository;
private final InjectRepository injectRepository;
private final InjectStatusRepository injectStatusRepository;
private final InjectorContractRepository injectorContractRepository;
private final InjectDocumentRepository injectDocumentRepository;
private final UserRepository userRepository;
private final TeamRepository teamRepository;
private final TagRepository tagRepository;
Expand Down
Loading

0 comments on commit 62aec5d

Please sign in to comment.