From 65616c01df49a736fa2de742f7ecc3234ccdf2da Mon Sep 17 00:00:00 2001 From: Johanah LEKEU Date: Thu, 26 Sep 2024 17:02:42 +0200 Subject: [PATCH] Add expiration time on automatic expectations --- .../injectors/caldera/CalderaContract.java | 244 +++++++-------- .../openbas/integrations/PayloadService.java | 283 +++++++++--------- 2 files changed, 270 insertions(+), 257 deletions(-) diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaContract.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaContract.java index cfbb416e4f..31eeb141aa 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaContract.java @@ -38,126 +38,130 @@ @RequiredArgsConstructor public class CalderaContract extends Contractor { - public static final String TYPE = "openbas_caldera"; - - private final CalderaInjectorConfig config; - private final CalderaInjectorService injectorCalderaService; - - @Override - public boolean isExpose() { - return this.config.isEnable(); + public static final String TYPE = "openbas_caldera"; + + private final CalderaInjectorConfig config; + private final CalderaInjectorService injectorCalderaService; + + @Override + public boolean isExpose() { + return this.config.isEnable(); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public ContractConfig getConfig() { + Map labels = Map.of(en, "Caldera", fr, "Caldera"); + return new ContractConfig(TYPE, labels, "#8b0000", "#8b0000", "/img/icon-caldera.png", isExpose()); + } + + @Override + public List contracts() { + if (this.config.isEnable()) { + ContractConfig contractConfig = getConfig(); + // Add contract based on abilities + return new ArrayList<>(abilityContracts(contractConfig)); } - - @Override - public String getType() { - return TYPE; - } - - @Override - public ContractConfig getConfig() { - Map labels = Map.of(en, "Caldera", fr, "Caldera"); - return new ContractConfig(TYPE, labels, "#8b0000", "#8b0000", "/img/icon-caldera.png", isExpose()); - } - - @Override - public List contracts() { - if (this.config.isEnable()) { - ContractConfig contractConfig = getConfig(); - // Add contract based on abilities - return new ArrayList<>(abilityContracts(contractConfig)); + return List.of(); + } + + // -- PRIVATE -- + + private ContractSelect obfuscatorField() { + List obfuscators = this.injectorCalderaService.obfuscators(); + Map obfuscatorChoices = obfuscators.stream() + .collect(Collectors.toMap(Obfuscator::getName, Obfuscator::getName)); + return selectFieldWithDefault( + "obfuscator", + "Obfuscators", + obfuscatorChoices, + "base64" + ); + } + + private ContractExpectations expectations() { + // Prevention + Expectation preventionExpectation = new Expectation(); + preventionExpectation.setType(PREVENTION); + preventionExpectation.setName("Expect inject to be prevented"); + preventionExpectation.setScore(100.0); + preventionExpectation.setExpirationTime(21600L); + // Detection + Expectation detectionExpectation = new Expectation(); + detectionExpectation.setType(DETECTION); + detectionExpectation.setName("Expect inject to be detected"); + detectionExpectation.setScore(100.0); + detectionExpectation.setExpirationTime(21600L); + return expectationsField("expectations", "Expectations", List.of(preventionExpectation, detectionExpectation)); + } + + private List abilityContracts(@NotNull final ContractConfig contractConfig) { + // Fields + ContractSelect obfuscatorField = obfuscatorField(); + ContractAsset assetField = assetField("assets", "Assets", Multiple); + ContractAssetGroup assetGroupField = assetGroupField("assetgroups", "Asset groups", Multiple); + ContractExpectations expectationsField = expectations(); + + List abilities = this.injectorCalderaService.abilities().stream() + .filter(ability -> !ability.getTactic().equals("openbas")).toList(); + // Build contracts + return abilities.stream().map((ability -> { + ContractDef builder = contractBuilder(); + builder.mandatoryGroup(assetField, assetGroupField); + builder.optional(obfuscatorField); + builder.optional(expectationsField); + List platforms = new ArrayList<>(); + ability.getExecutors().forEach(executor -> { + String command = executor.getCommand(); + if (command != null && !command.isEmpty()) { + Matcher matcher = Pattern.compile("#\\{(.*?)\\}").matcher(command); + while (matcher.find()) { + if (!matcher.group(1).isEmpty()) { + builder.mandatory(ContractText.textField(matcher.group(1), matcher.group(1))); + } + } } - return List.of(); - } - - // -- PRIVATE -- - - private ContractSelect obfuscatorField() { - List obfuscators = this.injectorCalderaService.obfuscators(); - Map obfuscatorChoices = obfuscators.stream().collect(Collectors.toMap(Obfuscator::getName, Obfuscator::getName)); - return selectFieldWithDefault( - "obfuscator", - "Obfuscators", - obfuscatorChoices, - "base64" - ); - } - - private ContractExpectations expectations() { - // Prevention - Expectation preventionExpectation = new Expectation(); - preventionExpectation.setType(PREVENTION); - preventionExpectation.setName("Expect inject to be prevented"); - preventionExpectation.setScore(100.0); - // Detection - Expectation detectionExpectation = new Expectation(); - detectionExpectation.setType(DETECTION); - detectionExpectation.setName("Expect inject to be detected"); - detectionExpectation.setScore(100.0); - return expectationsField("expectations", "Expectations", List.of(preventionExpectation, detectionExpectation)); - } - - private List abilityContracts(@NotNull final ContractConfig contractConfig) { - // Fields - ContractSelect obfuscatorField = obfuscatorField(); - ContractAsset assetField = assetField("assets", "Assets", Multiple); - ContractAssetGroup assetGroupField = assetGroupField("assetgroups", "Asset groups", Multiple); - ContractExpectations expectationsField = expectations(); - - List abilities = this.injectorCalderaService.abilities().stream().filter(ability -> !ability.getTactic().equals("openbas")).toList(); - // Build contracts - return abilities.stream().map((ability -> { - ContractDef builder = contractBuilder(); - builder.mandatoryGroup(assetField, assetGroupField); - builder.optional(obfuscatorField); - builder.optional(expectationsField); - List platforms = new ArrayList<>(); - ability.getExecutors().forEach(executor -> { - String command = executor.getCommand(); - if (command != null && !command.isEmpty()) { - Matcher matcher = Pattern.compile("#\\{(.*?)\\}").matcher(command); - while (matcher.find()) { - if (!matcher.group(1).isEmpty()) { - builder.mandatory(ContractText.textField(matcher.group(1), matcher.group(1))); - } - } - } - if (!executor.getPlatform().equals("unknown")) { - PLATFORM_TYPE platform = toPlatform(executor.getPlatform()); - if (!platforms.contains(platform)) { - platforms.add(platform); - } - } else { - if (executor.getName().equals("psh")) { - if (!platforms.contains(PLATFORM_TYPE.Windows)) { - platforms.add(PLATFORM_TYPE.Windows); - } - } else if (executor.getName().equals("sh")) { - if (!platforms.contains(PLATFORM_TYPE.Linux)) { - platforms.add(PLATFORM_TYPE.Linux); - } - } else if (executor.getName().equals("cmd")) { - if (!platforms.contains(PLATFORM_TYPE.Windows)) { - platforms.add(PLATFORM_TYPE.Windows); - } - } - } - }); - Contract contract = executableContract( - contractConfig, - ability.getAbility_id(), - Map.of(en, ability.getName(), fr, ability.getName()), - builder.build(), - platforms, - true - ); - contract.addAttackPattern(ability.getTechnique_id()); - return contract; - })).collect(Collectors.toList()); - } - - @Override - public ContractorIcon getIcon() { - InputStream iconStream = getClass().getResourceAsStream("/img/icon-caldera.png"); - return new ContractorIcon(iconStream); - } + if (!executor.getPlatform().equals("unknown")) { + PLATFORM_TYPE platform = toPlatform(executor.getPlatform()); + if (!platforms.contains(platform)) { + platforms.add(platform); + } + } else { + if (executor.getName().equals("psh")) { + if (!platforms.contains(PLATFORM_TYPE.Windows)) { + platforms.add(PLATFORM_TYPE.Windows); + } + } else if (executor.getName().equals("sh")) { + if (!platforms.contains(PLATFORM_TYPE.Linux)) { + platforms.add(PLATFORM_TYPE.Linux); + } + } else if (executor.getName().equals("cmd")) { + if (!platforms.contains(PLATFORM_TYPE.Windows)) { + platforms.add(PLATFORM_TYPE.Windows); + } + } + } + }); + Contract contract = executableContract( + contractConfig, + ability.getAbility_id(), + Map.of(en, ability.getName(), fr, ability.getName()), + builder.build(), + platforms, + true + ); + contract.addAttackPattern(ability.getTechnique_id()); + return contract; + })).collect(Collectors.toList()); + } + + @Override + public ContractorIcon getIcon() { + InputStream iconStream = getClass().getResourceAsStream("/img/icon-caldera.png"); + return new ContractorIcon(iconStream); + } } diff --git a/openbas-framework/src/main/java/io/openbas/integrations/PayloadService.java b/openbas-framework/src/main/java/io/openbas/integrations/PayloadService.java index eff85d067f..506d81a9ef 100644 --- a/openbas-framework/src/main/java/io/openbas/integrations/PayloadService.java +++ b/openbas-framework/src/main/java/io/openbas/integrations/PayloadService.java @@ -45,151 +45,160 @@ @Service public class PayloadService { - @Resource - protected ObjectMapper mapper; + @Resource + protected ObjectMapper mapper; - private final PayloadRepository payloadRepository; - private final InjectorRepository injectorRepository; - private final InjectorContractRepository injectorContractRepository; - private final AttackPatternRepository attackPatternRepository; + private final PayloadRepository payloadRepository; + private final InjectorRepository injectorRepository; + private final InjectorContractRepository injectorContractRepository; + private final AttackPatternRepository attackPatternRepository; - public void updateInjectorContractsForPayload(Payload payload) { - List injectors = this.injectorRepository.findAllByPayloads(true); - injectors.forEach(injector -> updateInjectorContract(injector, payload)); - } + public void updateInjectorContractsForPayload(Payload payload) { + List injectors = this.injectorRepository.findAllByPayloads(true); + injectors.forEach(injector -> updateInjectorContract(injector, payload)); + } - private void updateInjectorContract(Injector injector, Payload payload) { - Optional injectorContract = injectorContractRepository.findInjectorContractByInjectorAndPayload(injector, payload); - if (injectorContract.isPresent()) { - InjectorContract existingInjectorContract = injectorContract.get(); - Contract contract = buildContract(existingInjectorContract.getId(), injector, payload); - Map labels = Map.of("en", payload.getName(), "fr", payload.getName()); - existingInjectorContract.setLabels(labels); - existingInjectorContract.setNeedsExecutor(true); - existingInjectorContract.setManual(false); - existingInjectorContract.setInjector(injector); - existingInjectorContract.setPayload(payload); - existingInjectorContract.setPlatforms(payload.getPlatforms()); - existingInjectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(payload.getAttackPatterns().stream().map(AttackPattern::getId).toList()))); - existingInjectorContract.setAtomicTesting(true); - try { - existingInjectorContract.setContent(mapper.writeValueAsString(contract)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - injectorContractRepository.save(existingInjectorContract); - } else { - String contractId = String.valueOf(UUID.randomUUID()); - Map labels = Map.of("en", payload.getName(), "fr", payload.getName()); - Contract contract = buildContract(contractId, injector, payload); - InjectorContract newInjectorContract = new InjectorContract(); - newInjectorContract.setId(contractId); - newInjectorContract.setLabels(labels); - newInjectorContract.setNeedsExecutor(true); - newInjectorContract.setManual(false); - newInjectorContract.setInjector(injector); - newInjectorContract.setPayload(payload); - newInjectorContract.setPlatforms(payload.getPlatforms()); - newInjectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(payload.getAttackPatterns().stream().map(AttackPattern::getId).toList()))); - newInjectorContract.setAtomicTesting(true); - try { - newInjectorContract.setContent(mapper.writeValueAsString(contract)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - injectorContractRepository.save(newInjectorContract); - } + private void updateInjectorContract(Injector injector, Payload payload) { + Optional injectorContract = injectorContractRepository.findInjectorContractByInjectorAndPayload( + injector, payload); + if (injectorContract.isPresent()) { + InjectorContract existingInjectorContract = injectorContract.get(); + Contract contract = buildContract(existingInjectorContract.getId(), injector, payload); + Map labels = Map.of("en", payload.getName(), "fr", payload.getName()); + existingInjectorContract.setLabels(labels); + existingInjectorContract.setNeedsExecutor(true); + existingInjectorContract.setManual(false); + existingInjectorContract.setInjector(injector); + existingInjectorContract.setPayload(payload); + existingInjectorContract.setPlatforms(payload.getPlatforms()); + existingInjectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById( + payload.getAttackPatterns().stream().map(AttackPattern::getId).toList()))); + existingInjectorContract.setAtomicTesting(true); + try { + existingInjectorContract.setContent(mapper.writeValueAsString(contract)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + injectorContractRepository.save(existingInjectorContract); + } else { + String contractId = String.valueOf(UUID.randomUUID()); + Map labels = Map.of("en", payload.getName(), "fr", payload.getName()); + Contract contract = buildContract(contractId, injector, payload); + InjectorContract newInjectorContract = new InjectorContract(); + newInjectorContract.setId(contractId); + newInjectorContract.setLabels(labels); + newInjectorContract.setNeedsExecutor(true); + newInjectorContract.setManual(false); + newInjectorContract.setInjector(injector); + newInjectorContract.setPayload(payload); + newInjectorContract.setPlatforms(payload.getPlatforms()); + newInjectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById( + payload.getAttackPatterns().stream().map(AttackPattern::getId).toList()))); + newInjectorContract.setAtomicTesting(true); + try { + newInjectorContract.setContent(mapper.writeValueAsString(contract)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + injectorContractRepository.save(newInjectorContract); } + } - private Contract buildContract(@NotNull final String contractId, @NotNull final Injector injector, @NotNull final Payload payload) { - Map labels = Map.of(en, injector.getName(), fr, injector.getName()); - ContractConfig contractConfig = new ContractConfig(injector.getType(), labels, "#000000", "#000000", "/img/icon-" + injector.getType() + ".png", true); - ContractAsset assetField = assetField("assets", "Assets", Multiple); - ContractAssetGroup assetGroupField = assetGroupField("assetgroups", "Asset groups", Multiple); - ContractExpectations expectationsField = expectations(); - ContractDef builder = contractBuilder(); - builder.mandatoryGroup(assetField, assetGroupField); - builder.optional(expectationsField); - if( payload.getArguments() != null ) { - payload.getArguments().forEach(payloadArgument -> { - builder.mandatory(textField(payloadArgument.getKey(), payloadArgument.getKey(), payloadArgument.getDefaultValue())); - }); - } - return executableContract( - contractConfig, - contractId, - Map.of(en, payload.getName(), fr, payload.getName()), - builder.build(), - Arrays.asList(payload.getPlatforms()), - true - ); + private Contract buildContract(@NotNull final String contractId, @NotNull final Injector injector, + @NotNull final Payload payload) { + Map labels = Map.of(en, injector.getName(), fr, injector.getName()); + ContractConfig contractConfig = new ContractConfig(injector.getType(), labels, "#000000", "#000000", + "/img/icon-" + injector.getType() + ".png", true); + ContractAsset assetField = assetField("assets", "Assets", Multiple); + ContractAssetGroup assetGroupField = assetGroupField("assetgroups", "Asset groups", Multiple); + ContractExpectations expectationsField = expectations(); + ContractDef builder = contractBuilder(); + builder.mandatoryGroup(assetField, assetGroupField); + builder.optional(expectationsField); + if (payload.getArguments() != null) { + payload.getArguments().forEach(payloadArgument -> { + builder.mandatory( + textField(payloadArgument.getKey(), payloadArgument.getKey(), payloadArgument.getDefaultValue())); + }); } + return executableContract( + contractConfig, + contractId, + Map.of(en, payload.getName(), fr, payload.getName()), + builder.build(), + Arrays.asList(payload.getPlatforms()), + true + ); + } - private ContractExpectations expectations() { - // Prevention - Expectation preventionExpectation = new Expectation(); - preventionExpectation.setType(PREVENTION); - preventionExpectation.setName("Expect inject to be prevented"); - preventionExpectation.setScore(100.0); - // Detection - Expectation detectionExpectation = new Expectation(); - detectionExpectation.setType(DETECTION); - detectionExpectation.setName("Expect inject to be detected"); - detectionExpectation.setScore(100.0); - return expectationsField("expectations", "Expectations", List.of(preventionExpectation, detectionExpectation)); - } + private ContractExpectations expectations() { + // Prevention + Expectation preventionExpectation = new Expectation(); + preventionExpectation.setType(PREVENTION); + preventionExpectation.setName("Expect inject to be prevented"); + preventionExpectation.setScore(100.0); + preventionExpectation.setExpirationTime(21600L); + // Detection + Expectation detectionExpectation = new Expectation(); + detectionExpectation.setType(DETECTION); + detectionExpectation.setName("Expect inject to be detected"); + detectionExpectation.setScore(100.0); + detectionExpectation.setExpirationTime(21600L); + return expectationsField("expectations", "Expectations", List.of(preventionExpectation, detectionExpectation)); + } - public Payload duplicate(@NotBlank final String payloadId) { - Payload origin = this.payloadRepository.findById(payloadId).orElseThrow(); - Payload duplicate; - switch (origin.getType()) { - case "Command": - Command originCommand = (Command) Hibernate.unproxy(origin); - Command duplicateCommand = new Command(); - duplicateCommonProperties(originCommand, duplicateCommand); - duplicate = payloadRepository.save(duplicateCommand); - break; - case "Executable": - Executable originExecutable = (Executable) Hibernate.unproxy(origin); - Executable duplicateExecutable = new Executable(); - duplicateCommonProperties(originExecutable, duplicateExecutable); - duplicateExecutable.setExecutableFile(originExecutable.getExecutableFile()); - duplicate = payloadRepository.save(duplicateExecutable); - break; - case "FileDrop": - FileDrop originFileDrop = (FileDrop) Hibernate.unproxy(origin); - FileDrop duplicateFileDrop = new FileDrop(); - duplicateCommonProperties(originFileDrop, duplicateFileDrop); - duplicate = payloadRepository.save(duplicateFileDrop); - break; - case "DnsResolution": - DnsResolution originDnsResolution = (DnsResolution) Hibernate.unproxy(origin); - DnsResolution duplicateDnsResolution = new DnsResolution(); - duplicateCommonProperties(originDnsResolution, duplicateDnsResolution); - duplicate = payloadRepository.save(duplicateDnsResolution); - break; - case "NetworkTraffic": - NetworkTraffic originNetworkTraffic = (NetworkTraffic) Hibernate.unproxy(origin); - NetworkTraffic duplicateNetworkTraffic = new NetworkTraffic(); - duplicateCommonProperties(originNetworkTraffic, duplicateNetworkTraffic); - duplicate = payloadRepository.save(duplicateNetworkTraffic); - break; - default: - throw new UnsupportedOperationException("Payload type " + origin.getType() + " is not supported"); - } - this.updateInjectorContractsForPayload(duplicate); - return duplicate; + public Payload duplicate(@NotBlank final String payloadId) { + Payload origin = this.payloadRepository.findById(payloadId).orElseThrow(); + Payload duplicate; + switch (origin.getType()) { + case "Command": + Command originCommand = (Command) Hibernate.unproxy(origin); + Command duplicateCommand = new Command(); + duplicateCommonProperties(originCommand, duplicateCommand); + duplicate = payloadRepository.save(duplicateCommand); + break; + case "Executable": + Executable originExecutable = (Executable) Hibernate.unproxy(origin); + Executable duplicateExecutable = new Executable(); + duplicateCommonProperties(originExecutable, duplicateExecutable); + duplicateExecutable.setExecutableFile(originExecutable.getExecutableFile()); + duplicate = payloadRepository.save(duplicateExecutable); + break; + case "FileDrop": + FileDrop originFileDrop = (FileDrop) Hibernate.unproxy(origin); + FileDrop duplicateFileDrop = new FileDrop(); + duplicateCommonProperties(originFileDrop, duplicateFileDrop); + duplicate = payloadRepository.save(duplicateFileDrop); + break; + case "DnsResolution": + DnsResolution originDnsResolution = (DnsResolution) Hibernate.unproxy(origin); + DnsResolution duplicateDnsResolution = new DnsResolution(); + duplicateCommonProperties(originDnsResolution, duplicateDnsResolution); + duplicate = payloadRepository.save(duplicateDnsResolution); + break; + case "NetworkTraffic": + NetworkTraffic originNetworkTraffic = (NetworkTraffic) Hibernate.unproxy(origin); + NetworkTraffic duplicateNetworkTraffic = new NetworkTraffic(); + duplicateCommonProperties(originNetworkTraffic, duplicateNetworkTraffic); + duplicate = payloadRepository.save(duplicateNetworkTraffic); + break; + default: + throw new UnsupportedOperationException("Payload type " + origin.getType() + " is not supported"); } + this.updateInjectorContractsForPayload(duplicate); + return duplicate; + } - private void duplicateCommonProperties(@org.jetbrains.annotations.NotNull final T origin, @org.jetbrains.annotations.NotNull T duplicate) { - BeanUtils.copyProperties(origin, duplicate); - duplicate.setId(null); - duplicate.setName(StringUtils.duplicateString(origin.getName())); - duplicate.setAttackPatterns(new ArrayList<>(origin.getAttackPatterns())); - duplicate.setTags(new HashSet<>(origin.getTags())); - duplicate.setExternalId(null); - duplicate.setSource(MANUAL); - duplicate.setStatus(VERIFIED); - duplicate.setCollector(null); - } + private void duplicateCommonProperties(@org.jetbrains.annotations.NotNull final T origin, + @org.jetbrains.annotations.NotNull T duplicate) { + BeanUtils.copyProperties(origin, duplicate); + duplicate.setId(null); + duplicate.setName(StringUtils.duplicateString(origin.getName())); + duplicate.setAttackPatterns(new ArrayList<>(origin.getAttackPatterns())); + duplicate.setTags(new HashSet<>(origin.getTags())); + duplicate.setExternalId(null); + duplicate.setSource(MANUAL); + duplicate.setStatus(VERIFIED); + duplicate.setCollector(null); + } }