Skip to content

Commit

Permalink
[frontend/backend] improve code
Browse files Browse the repository at this point in the history
Signed-off-by: Marine LM <[email protected]>
  • Loading branch information
MarineLeM committed Jan 2, 2025
1 parent 3aae1be commit 2f92dcc
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.openbas.injectors.caldera.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.openbas.model.inject.form.Expectation;
import java.util.ArrayList;
Expand All @@ -17,6 +18,7 @@ public class CalderaInjectContent {
@JsonProperty("expectations")
private List<Expectation> expectations = new ArrayList<>();

@JsonIgnore
public static String getDefaultObfuscator() {
return "plain-text";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import io.openbas.model.inject.form.Expectation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;

Expand All @@ -18,15 +16,4 @@ public class OpenBASImplantInjectContent {

@JsonProperty("expectations")
private List<Expectation> expectations = new ArrayList<>();

public static String getDefaultObfuscator() {
return "plain-text";
}

public static Map<String, String> getObfuscatorState() {
Map<String, String> obfuscatorMap = new HashMap<>();
obfuscatorMap.put("base64", "CMD does not support base64 obfuscation");
obfuscatorMap.put("plain-text", "");
return obfuscatorMap;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.openbas.injectors.openbas.util;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import lombok.Getter;

public class OpenBASObfuscationMap {
private final Map<String, OpenBASObfuscation> obfuscationMap;

@Getter
public static class OpenBASObfuscation {
private final String information;
private final BiFunction<String, String, String> obfuscate;

public OpenBASObfuscation(String information, BiFunction<String, String, String> obfuscate) {
this.information = information;
this.obfuscate = obfuscate;
}
}

public OpenBASObfuscationMap() {
this.obfuscationMap = new HashMap<>();
this.registerObfuscation("plain-text", "", this::obfuscatePlainText);
this.registerObfuscation(
"base64", "CMD does not support base64 obfuscation", this::obfuscateBase64);
}

public void registerObfuscation(
String key, String information, BiFunction<String, String, String> function) {
if (key == null || function == null) {
throw new IllegalArgumentException("Key and function must not be null.");
}
obfuscationMap.put(key, new OpenBASObfuscation(information, function));
}

public String executeObfuscation(String key, String command, String executor) {
OpenBASObfuscation obfuscation = obfuscationMap.get(key);
if (obfuscation != null) {
return obfuscation.getObfuscate().apply(command, executor);
}
throw new IllegalArgumentException("No obfuscation found for key: " + key);
}

public Map<String, String> getAllObfuscationInfo() {
Map<String, String> keyInfoMap = new HashMap<>();
for (Map.Entry<String, OpenBASObfuscation> entry : obfuscationMap.entrySet()) {
keyInfoMap.put(entry.getKey(), entry.getValue().getInformation());
}
return keyInfoMap;
}

private String obfuscatePlainText(String command, String executor) {
return command;
}

private String obfuscateBase64(String command, String executor) {
String obfuscatedCommand = command;

if (executor.equals("psh") || executor.equals("cmd")) {
byte[] utf16Bytes = command.getBytes(StandardCharsets.UTF_16LE);
String base64 = Base64.getEncoder().encodeToString(utf16Bytes);
obfuscatedCommand = String.format("powershell -Enc %s", base64);

} else if (executor.equals("bash") || executor.equals("sh")) {
obfuscatedCommand =
String.format(
"eval \"$(echo %s | base64 --decode)\"",
Base64.getEncoder().encodeToString(command.getBytes()));
}
return obfuscatedCommand;
}

public String getDefaultObfuscator() {
return "plain-text";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.openbas.database.model.*;
import io.openbas.database.repository.InjectRepository;
import io.openbas.injectors.openbas.util.OpenBASObfuscationMap;
import io.openbas.injectors.openbas.model.OpenBASImplantInjectContent;
import io.openbas.rest.exception.ElementNotFoundException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
Expand Down Expand Up @@ -76,39 +76,21 @@ public static String replaceCmdVariables(String cmd) {
return result.toString();
}

private String obfuscateCommandBase64(String command, String executor) {
String obfuscatedCommand = command;

if (executor.equals("psh") || executor.equals("cmd")) {
byte[] utf16Bytes = command.getBytes(StandardCharsets.UTF_16LE);
String base64 = Base64.getEncoder().encodeToString(utf16Bytes);
obfuscatedCommand = String.format("powershell -Enc %s", base64);

} else if (executor.equals("bash") || executor.equals("sh")) {
obfuscatedCommand =
String.format(
"eval \"$(echo %s | base64 --decode)\"",
Base64.getEncoder().encodeToString(command.getBytes()));
}
return obfuscatedCommand;
}

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

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

if (obfuscator.equals("base64")) {
computedCommand = obfuscateCommandBase64(computedCommand, executor);
}
computedCommand = obfuscationMap.executeObfuscation(obfuscator, computedCommand, executor);

return Base64.getEncoder().encodeToString(computedCommand.getBytes());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@
import io.openbas.injector_contract.Contract;
import io.openbas.injector_contract.ContractConfig;
import io.openbas.injector_contract.ContractDef;
import io.openbas.injector_contract.fields.ContractAsset;
import io.openbas.injector_contract.fields.ContractAssetGroup;
import io.openbas.injector_contract.fields.ContractExpectations;
import io.openbas.injector_contract.fields.ContractSelect;
import io.openbas.injectors.openbas.model.OpenBASImplantInjectContent;
import io.openbas.injector_contract.fields.*;
import io.openbas.injectors.openbas.util.OpenBASObfuscationMap;
import io.openbas.utils.StringUtils;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
Expand Down Expand Up @@ -110,14 +107,11 @@ private void updateInjectorContract(Injector injector, Payload payload) {
}
}

private ContractSelect obfuscatorField() {
Map<String, String> obfuscatorState = OpenBASImplantInjectContent.getObfuscatorState();

return ContractSelect.selectFieldWithChoiceInformations(
"obfuscator",
"Obfuscators",
obfuscatorState,
OpenBASImplantInjectContent.getDefaultObfuscator());
private ContractChoiceInformation obfuscatorField() {
OpenBASObfuscationMap obfuscationMap = new OpenBASObfuscationMap();
Map<String, String> obfuscationInfo = obfuscationMap.getAllObfuscationInfo();
return ContractChoiceInformation.choiceInformationField(
"obfuscator", "Obfuscators", obfuscationInfo, obfuscationMap.getDefaultObfuscator());
}

private Contract buildContract(
Expand All @@ -139,8 +133,8 @@ private Contract buildContract(
ContractDef builder = contractBuilder();
builder.mandatoryGroup(assetField, assetGroupField);

if (injector.getType().equals("openbas_implant") && payload.getType().equals("Command")) {
ContractSelect obfuscatorField = obfuscatorField();
if (payload.getType().equals("Command")) {
ContractChoiceInformation obfuscatorField = obfuscatorField();
builder.optional(obfuscatorField);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public enum ContractType {
Textarea,
@JsonProperty("select")
Select,
@JsonProperty("choice")
Choice,
@JsonProperty("article")
Article,
@JsonProperty("challenge")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.openbas.injector_contract.fields;

import io.openbas.injector_contract.ContractCardinality;
import io.openbas.injector_contract.ContractType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class ContractChoiceInformation extends ContractCardinalityElement {
private List<ChoiceItem> choices = List.of();

public ContractChoiceInformation(String key, String label, ContractCardinality cardinality) {
super(key, label, cardinality);
}

@Getter
public static class ChoiceItem {
private final String label;
private final String value;
private final String information;

public ChoiceItem(String label, String value, String information) {
this.information = information;
this.label = label;
this.value = value;
}
}

public static ContractChoiceInformation choiceInformationField(
String key, String label, Map<String, String> choiceInformations, String def) {
ContractChoiceInformation contractChoice =
new ContractChoiceInformation(key, label, ContractCardinality.One);

ArrayList<ChoiceItem> choiceItems = new ArrayList<>();
for (Map.Entry<String, String> entry : choiceInformations.entrySet()) {
choiceItems.add(new ChoiceItem(entry.getKey(), entry.getKey(), entry.getValue()));
}

contractChoice.setChoices(choiceItems);
contractChoice.setDefaultValue(List.of(def));
return contractChoice;
}

@Override
public ContractType getType() {
return ContractType.Choice;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.Setter;

Expand All @@ -28,19 +27,6 @@ public static ContractSelect selectFieldWithDefault(
return contractSelect;
}

public static ContractSelect selectFieldWithChoiceInformations(
String key, String label, Map<String, String> choiceInformations, String def) {
ContractSelect contractSelect = new ContractSelect(key, label, ContractCardinality.One);

Map<String, String> choices =
choiceInformations.keySet().stream().collect(Collectors.toMap(k -> k, k -> k));

contractSelect.setChoices(choices);
contractSelect.setDefaultValue(List.of(def));
contractSelect.setChoiceInformations(choiceInformations);
return contractSelect;
}

@Override
public ContractType getType() {
return ContractType.Select;
Expand Down
Loading

0 comments on commit 2f92dcc

Please sign in to comment.