diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/Dispatcher.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/Dispatcher.java index a6deb2a50..4c2d18bc7 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/Dispatcher.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/Dispatcher.java @@ -13,6 +13,7 @@ import com.newrelic.agent.security.intcodeagent.websocket.EventSendPool; import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper; +import com.newrelic.api.agent.security.instrumentation.helpers.SystemCommandUtils; import com.newrelic.api.agent.security.schema.*; import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.*; @@ -49,6 +50,8 @@ public class Dispatcher implements Callable { public static final String SEPARATOR1 = ", "; public static final String APP_LOCATION = "app-location"; + public static final String SYSCOMMAND_ENVIRONMENT = "environment"; + public static final String SYSCOMMAND_SCRIPT_CONTENT = "script-content"; private ExitEventBean exitEventBean; private AbstractOperation operation; private SecurityMetaData securityMetaData; @@ -444,12 +447,23 @@ private JavaAgentEventBean prepareSQLDbCommandEvent(SQLOperation operation, private JavaAgentEventBean prepareSystemCommandEvent(JavaAgentEventBean eventBean, ForkExecOperation operationalBean) { - JSONArray params = new JSONArray(); - params.add(operationalBean.getCommand()); - if (operationalBean.getEnvironment() != null) { - params.add(new JSONObject(operationalBean.getEnvironment())); + try { + List shellScripts = SystemCommandUtils.isShellScriptExecution(operationalBean.getCommand()); + List absolutePaths = SystemCommandUtils.getAbsoluteShellScripts(shellScripts); + SystemCommandUtils.scriptContent(absolutePaths, operationalBean); + JSONArray params = new JSONArray(); + params.add(operationalBean.getCommand()); + JSONObject extras = new JSONObject(); + if (operationalBean.getEnvironment() != null) { + extras.put(SYSCOMMAND_ENVIRONMENT, new JSONObject(operationalBean.getEnvironment())); + } + extras.put(SYSCOMMAND_SCRIPT_CONTENT, operationalBean.getScriptContent()); + params.add(extras); + eventBean.setParameters(params); + return eventBean; + } catch (Throwable e){ + e.printStackTrace(); } - eventBean.setParameters(params); return eventBean; } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/SystemCommandUtils.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/SystemCommandUtils.java new file mode 100644 index 000000000..aaf7eb03c --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/SystemCommandUtils.java @@ -0,0 +1,55 @@ +package com.newrelic.api.agent.security.instrumentation.helpers; + +import com.newrelic.api.agent.security.schema.StringUtils; +import com.newrelic.api.agent.security.schema.operation.ForkExecOperation; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SystemCommandUtils { + + private static final Pattern commandShellRegex = Pattern.compile("(\\S+\\.sh(?!\\S))"); + + public static List isShellScriptExecution(String command) { + Matcher matcher = commandShellRegex.matcher(command); + + List shellScripts = new ArrayList<>(); + while (matcher.find()){ + shellScripts.add(matcher.group().trim()); + } + return shellScripts; + } + + public static List getAbsoluteShellScripts(List shellScripts) { + List absoluteSrcipts = new ArrayList<>(); + + for (String shellScript : shellScripts) { + File script = new File(shellScript); + if(script.isFile()){ + absoluteSrcipts.add(script.getAbsolutePath()); + } + } + + return absoluteSrcipts; + } + + public static void scriptContent(List absolutePaths, ForkExecOperation operation) { + for (String absolutePath : absolutePaths) { + try { + BufferedReader reader = new BufferedReader(new FileReader(absolutePath)); + StringBuilder content = new StringBuilder(); + String line = reader.readLine(); + while(line != null) { + content.append(line); + content.append(StringUtils.LF); + line = reader.readLine(); + } + operation.getScriptContent().put(new File(absolutePath).getName(), content.toString()); + } catch (IOException e) { + } + } + } +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/StringUtils.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/StringUtils.java index 482fc8409..63c9c5be0 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/StringUtils.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/StringUtils.java @@ -5,6 +5,8 @@ public class StringUtils { public static final String EMPTY = ""; + + public static final String LF = "\n"; public static final int INDEX_NOT_FOUND = -1; /** diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/ForkExecOperation.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/ForkExecOperation.java index ad6b918b4..0ddd76bca 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/ForkExecOperation.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/ForkExecOperation.java @@ -12,6 +12,8 @@ public class ForkExecOperation extends AbstractOperation { private Map environment; + private Map scriptContent = new HashMap<>(); + public ForkExecOperation(String cmd, Map environment, String className, String methodName) { super(className, methodName); this.setCaseType(VulnerabilityCaseType.SYSTEM_COMMAND); @@ -50,4 +52,11 @@ public void setEnvironment(Map environment) { this.environment = environment; } + public Map getScriptContent() { + return scriptContent; + } + + public void setScriptContent(Map scriptContent) { + this.scriptContent = scriptContent; + } }