All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.newrelic.agent.security.instrumentator.dispatcher.Dispatcher Maven / Gradle / Ivy

Go to download

The New Relic Security Java agent module for full-stack security. To be used in newrelic-java-agent only.

The newest version!
package com.newrelic.agent.security.instrumentator.dispatcher;

import com.google.gson.Gson;
import com.newrelic.agent.security.AgentInfo;
import com.newrelic.agent.security.instrumentator.helper.DynamoDBRequestConverter;
import com.newrelic.agent.security.instrumentator.utils.AgentUtils;
import com.newrelic.agent.security.instrumentator.utils.CallbackUtils;
import com.newrelic.agent.security.instrumentator.utils.INRSettingsKey;
import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool;
import com.newrelic.api.agent.security.Agent;
import com.newrelic.api.agent.security.utils.logging.LogLevel;
import com.newrelic.agent.security.intcodeagent.logging.DeployedApplication;
import com.newrelic.agent.security.intcodeagent.models.javaagent.ExitEventBean;
import com.newrelic.agent.security.intcodeagent.models.javaagent.JavaAgentEventBean;
import com.newrelic.agent.security.intcodeagent.websocket.EventSendPool;
import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter;
import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.security.instrumentation.helpers.AppServerInfoHelper;
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.*;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import java.io.File;
import java.io.ObjectInputStream;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.newrelic.agent.security.intcodeagent.logging.IAgentConstants.*;

/**
 * Agent utility for out of band processing and sending of events to K2 validator.
 */
public class Dispatcher implements Callable {

    private static final String SEPARATOR_QUESTIONMARK = "?";
    private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance();
    public static final String ERROR = "Error : ";
    public static final String EMPTY_FILE_SHA = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
    public static final String DROPPING_APPLICATION_INFO_POSTING_DUE_TO_SIZE_0 = "Dropping application info posting due to size 0 : ";
    public static final String QUESTION_CHAR = SEPARATOR_QUESTIONMARK;
    public static final char SEPARATOR = '.';
    private static final String EVENT_ZERO_SENT = "[STEP-8] => First event sent for validation. Security agent started successfully. %s";
    private static final String SENDING_EVENT_ZERO = "[EVENT] Sending first event for validation. Security agent started successfully ";
    private static final String POSTING_UPDATED_APPLICATION_INFO = "[APP_INFO][DEPLOYED_APP] Sending updated application info to Security Engine : %s";

    public static final String SEPARATOR1 = ", ";
    public static final String APP_LOCATION = "app-location";
    public static final String REDIS_MODE = "mode";
    public static final String REDIS_ARGUMENTS = "arguments";
    public static final String REDIS_TYPE = "type";
    public static final String SYSCOMMAND_ENVIRONMENT = "environment";
    public static final String SYSCOMMAND_SCRIPT_CONTENT = "script-content";
    public static final String UNABLE_TO_CONVERT_OPERATION_TO_EVENT = "Unable to convert operation to event: %s, %s, %s";
    public static final String COOKIE_NAME = "name";
    public static final String COOKIE_VALUE = "value";
    public static final String COOKIE_IS_SECURE = "isSecure";
    public static final String COOKIE_IS_HTTP_ONLY = "isHttpOnly";
    public static final String COOKIE_IS_SAME_SITE_STRICT = "isSameSiteStrict";
    private ExitEventBean exitEventBean;
    private AbstractOperation operation;
    private SecurityMetaData securityMetaData;
    private Map extraInfo = new HashMap();
    private boolean isNRCode = false;
    private static AtomicBoolean firstEventSent = new AtomicBoolean(false);
    private final String SQL_STORED_PROCEDURE ="SQL_STORED_PROCEDURE";

    public ExitEventBean getExitEventBean() {
        return exitEventBean;
    }

    public AbstractOperation getOperation() {
        return operation;
    }

    public SecurityMetaData getSecurityMetaData() {
        return securityMetaData;
    }

    private static Gson GsonUtil = new Gson();

    public Dispatcher(AbstractOperation operation, SecurityMetaData securityMetaData) {
        this.securityMetaData = securityMetaData;
        this.operation = operation;
        extraInfo.put(BLOCKING_END_TIME, System.currentTimeMillis());
    }


    public Dispatcher(ExitEventBean exitEventBean) {
        this.exitEventBean = exitEventBean;
    }


    /**
     * Processing of hooked data on the basis of case type.
     * Followed by delegated sending of event.
     */
    @Override
    public Object call() throws Exception {
        try {
            if (this.exitEventBean != null) {
                EventSendPool.getInstance().sendEvent(exitEventBean);
                return null;
            }
            if (!firstEventSent.get()) {
                logger.logInit(LogLevel.INFO, SENDING_EVENT_ZERO, this.getClass().getName());
            }

            if (operation == null) {
                // Invalid Event. Just drop.
                return null;
            }

            JavaAgentEventBean eventBean = prepareEvent(securityMetaData.getRequest(), securityMetaData.getMetaData(),
                    operation.getCaseType(), securityMetaData.getFuzzRequestIdentifier());
            setGenericProperties(operation, eventBean);
            switch (operation.getCaseType()) {
                case REFLECTED_XSS:
                    processReflectedXSSEvent(eventBean);
                    return null;
                case FILE_OPERATION:
                    FileOperation fileOperationalBean = (FileOperation) operation;
                    eventBean = processFileOperationEvent(eventBean, fileOperationalBean);
                    if (eventBean == null) {
                        return null;
                    }
                    break;
                case SYSTEM_COMMAND:
                    ForkExecOperation operationalBean = (ForkExecOperation) operation;
                    eventBean = prepareSystemCommandEvent(eventBean, operationalBean);
                    break;
                case SQL_DB_COMMAND:
                    if (operation instanceof SQLOperation) {
                        eventBean = prepareSQLDbCommandEvent((SQLOperation) operation, eventBean);
                        break;
                    } else if (operation instanceof BatchSQLOperation) {
                        eventBean = prepareSQLDbCommandEvent((BatchSQLOperation) operation, eventBean);
                        break;
                    }
                case NOSQL_DB_COMMAND:
                    if(operation instanceof SQLOperation) {
                        eventBean = prepareSQLDbCommandEvent((SQLOperation) operation, eventBean);
                        break;
                    } else if (operation instanceof BatchSQLOperation) {
                        eventBean = prepareSQLDbCommandEvent((BatchSQLOperation) operation, eventBean);
                        break;
                    } else if (operation instanceof NoSQLOperation) {
                        eventBean = prepareNoSQLEvent(eventBean, (NoSQLOperation) operation);
                        break;
                    }

                case DYNAMO_DB_COMMAND:
                    DynamoDBOperation dynamoDBOperation = (DynamoDBOperation) operation;
                    eventBean = prepareDynamoDBEvent(eventBean, dynamoDBOperation);
                    if (eventBean == null) {
                        return null;
                    }
                    break;

                case FILE_INTEGRITY:
                    FileIntegrityOperation fileIntegrityBean = (FileIntegrityOperation) operation;
                    eventBean = prepareFileIntegrityEvent(eventBean, fileIntegrityBean);
                    break;
                case LDAP:
                    LDAPOperation ldapOperationalBean = (LDAPOperation) operation;
                    eventBean = prepareLDAPEvent(eventBean, ldapOperationalBean);
                    break;
                case RANDOM:
                    RandomOperation randomOperationalBean = (RandomOperation) operation;
                    eventBean = prepareRandomEvent(eventBean, randomOperationalBean);
                    break;
                case HTTP_REQUEST:
                    SSRFOperation ssrfOperationalBean = (SSRFOperation) operation;
                    eventBean = prepareSSRFEvent(eventBean, ssrfOperationalBean);
                    break;
                case XPATH:
                    XPathOperation xPathOperationalBean = (XPathOperation) operation;
                    eventBean = prepareXPATHEvent(eventBean, xPathOperationalBean);
                    break;
                case SECURE_COOKIE:
                    SecureCookieOperationSet secureCookieOperationalBean = (SecureCookieOperationSet) operation;
                    eventBean = prepareSecureCookieEvent(eventBean, secureCookieOperationalBean);
                    break;
                case TRUSTBOUNDARY:
                    TrustBoundaryOperation trustBoundaryOperationalBean = (TrustBoundaryOperation) operation;
                    eventBean = prepareTrustBoundaryEvent(eventBean, trustBoundaryOperationalBean);
                    break;
                case CRYPTO:
                    HashCryptoOperation hashCryptoOperationalBean = (HashCryptoOperation) operation;
                    eventBean = prepareCryptoEvent(eventBean, hashCryptoOperationalBean);
                    break;
                case HASH:
                    HashCryptoOperation hashOperationalBean = (HashCryptoOperation) operation;
                    eventBean = prepareHashEvent(eventBean, hashOperationalBean);
                    break;
                case JAVASCRIPT_INJECTION:
                    JSInjectionOperation jsInjectionOperationalBean = (JSInjectionOperation) operation;
                    eventBean = prepareJSInjectionEvent(eventBean, jsInjectionOperationalBean);
                    break;
                case XQUERY_INJECTION:
                    XQueryOperation xQueryOperationalBean = (XQueryOperation) operation;
                    eventBean = prepareXQueryInjectionEvent(eventBean, xQueryOperationalBean);
                    break;
                case CACHING_DATA_STORE:
                    if(operation instanceof RedisOperation) {
                        RedisOperation redisOperation = (RedisOperation) operation;
                        eventBean = prepareCachingDataStoreEvent(eventBean, redisOperation);
                    } else if (operation instanceof JCacheOperation) {
                        JCacheOperation jCacheOperation = (JCacheOperation) operation;
                        eventBean = prepareJCacheCachingDataStoreEvent(eventBean, jCacheOperation);
                    } else if (operation instanceof MemcachedOperation) {
                        MemcachedOperation memcachedOperationalBean = (MemcachedOperation) operation;
                        eventBean = prepareMemcachedEvent(eventBean, memcachedOperationalBean);
                    }
                    break;
                case SOLR_DB_REQUEST:
                    SolrDbOperation solrDbOperation = (SolrDbOperation) operation;
                    eventBean = prepareSolrDbRequestEvent(eventBean, solrDbOperation);
                    break;
                default:

            }

            if (!VulnerabilityCaseType.FILE_INTEGRITY.equals(operation.getCaseType())) {
                if (VulnerabilityCaseType.FILE_OPERATION.equals(operation.getCaseType())
                        && ((FileOperation) operation).isGetBooleanAttributesCall()) {
                    eventBean = processStackTrace(eventBean, operation.getCaseType(), false);
                } else {
                    eventBean = processStackTrace(eventBean, operation.getCaseType(), true);
                }
                if (eventBean == null) {
                    return null;
                }
            }

            EventSendPool.getInstance().sendEvent(eventBean);
            if (!firstEventSent.get()) {
                logger.logInit(LogLevel.INFO, String.format(EVENT_ZERO_SENT, eventBean), this.getClass().getName());
                firstEventSent.set(true);
            }
//        detectDeployedApplication();
        } catch (Throwable e) {
            logger.postLogMessageIfNecessary(LogLevel.WARNING, String.format(UNABLE_TO_CONVERT_OPERATION_TO_EVENT, operation.getApiID(), operation.getSourceMethod(), JsonConverter.getObjectMapper().writeValueAsString(operation.getUserClassEntity())), e,
                    this.getClass().getName());
            Agent.getInstance().reportIncident(LogLevel.WARNING, String.format(UNABLE_TO_CONVERT_OPERATION_TO_EVENT, operation.getApiID(), operation.getSourceMethod(), JsonConverter.getObjectMapper().writeValueAsString(operation.getUserClassEntity())), e,
                    this.getClass().getName());
        }
        return null;
    }

    private JavaAgentEventBean prepareSolrDbRequestEvent(JavaAgentEventBean eventBean, SolrDbOperation solrDbOperation) {
        JSONArray params = new JSONArray();
        JSONObject request = new JSONObject();
        request.put("collection", solrDbOperation.getCollection());
        request.put("method", solrDbOperation.getMethod());
        request.put("connectionURL", solrDbOperation.getConnectionURL());
        request.put("path", solrDbOperation.getPath());
        request.put("params", solrDbOperation.getParams());
        request.put("documents", solrDbOperation.getDocuments());
        params.add(request);
        eventBean.setParameters(params);
        return eventBean;
    }

    private JavaAgentEventBean prepareCachingDataStoreEvent(JavaAgentEventBean eventBean, RedisOperation redisOperation) {
        JSONArray params = new JSONArray();
        for (Object data : redisOperation.getArguments()) {
            params.add(data);
        }
        JSONObject command = new JSONObject();
        command.put(REDIS_MODE, redisOperation.getMode());
        command.put(REDIS_ARGUMENTS, params);
        command.put(REDIS_TYPE, redisOperation.getType());
        JSONArray parameter = new JSONArray();
        parameter.add(command);
        eventBean.setParameters(parameter);
        return eventBean;
    }

    private JavaAgentEventBean prepareJCacheCachingDataStoreEvent(JavaAgentEventBean eventBean, JCacheOperation jCacheOperation) {
        JSONArray params = new JSONArray();
        for (Object data : jCacheOperation.getArguments()) {
            if (isPrimitiveType(data.getClass())) {
                params.add(data);
            } else {
                params.add(GsonUtil.toJson(data));
            }
        }

        JSONObject command = new JSONObject();
        command.put(REDIS_ARGUMENTS, params);
        command.put(REDIS_TYPE, jCacheOperation.getType());

        JSONArray parameter = new JSONArray();
        parameter.add(command);
        eventBean.setParameters(parameter);
        eventBean.setEventCategory(jCacheOperation.getCategory());
        return eventBean;
    }

    public boolean isPrimitiveType(Class clazz) {
        return (clazz.isPrimitive() && clazz != void.class) || clazz == Double.class || clazz == Float.class || clazz == Long.class ||
                clazz == Integer.class || clazz == Short.class || clazz == Character.class || clazz == Byte.class || clazz == Boolean.class ||
                clazz == String.class;
    }

    @Nullable
    private JavaAgentEventBean processFileOperationEvent(JavaAgentEventBean eventBean, FileOperation fileOperationalBean) {
        prepareFileEvent(eventBean, fileOperationalBean);
        String URL = StringUtils.substringBefore(securityMetaData.getRequest().getUrl(), QUESTION_CHAR);
        if (!(AgentUtils.getInstance().getAgentPolicy().getVulnerabilityScan().getEnabled()
                && AgentUtils.getInstance().getAgentPolicy().getVulnerabilityScan().getIastScan().getEnabled()) && allowedExtensionFileIO(eventBean.getParameters(), eventBean.getSourceMethod(), URL)) {
            // Event is bypassed. Drop it.
            return null;
        }
        return eventBean;
    }


    /**
     * Validate and send if required event for REFLECTED XSS
     */
    private void processReflectedXSSEvent(JavaAgentEventBean eventBean) {
        if (!NewRelic.getAgent().getConfig().getValue(INRSettingsKey.SECURITY_DETECTION_RXSS_ENABLED, true)) {
            AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDroppedDueTo().incrementRxssDetectionDeactivated();
            return;
        }
        Set xssConstructs = CallbackUtils.checkForReflectedXSS(securityMetaData.getRequest(), securityMetaData.getResponse());
        if ((!xssConstructs.isEmpty() && !actuallyEmpty(xssConstructs) && StringUtils.isNotBlank(securityMetaData.getResponse().getResponseBody())) ||
                (AgentUtils.getInstance().getAgentPolicy().getVulnerabilityScan().getEnabled()
                        && AgentUtils.getInstance().getAgentPolicy().getVulnerabilityScan().getIastScan().getEnabled())) {
            JSONArray params = new JSONArray();
            params.addAll(xssConstructs);
            params.add(securityMetaData.getResponse().getResponseBody());
            eventBean.setParameters(params);
            eventBean.setHttpResponse(securityMetaData.getResponse());
            eventBean.setApplicationUUID(AgentInfo.getInstance().getApplicationUUID());
            eventBean.setPid(AgentInfo.getInstance().getVMPID());
            eventBean.setId(operation.getExecutionId());
            eventBean.setStartTime(operation.getStartTime());
            eventBean.setBlockingProcessingTime(
                    (Long) extraInfo.get(BLOCKING_END_TIME) - eventBean.getStartTime());

            eventBean.setApiId(operation.getApiID());
            EventSendPool.getInstance().sendEvent(eventBean);
            if (!firstEventSent.get()) {
                logger.logInit(LogLevel.INFO, String.format(EVENT_ZERO_SENT, eventBean), this.getClass().getName());
                firstEventSent.set(true);
            }
//            detectDeployedApplication();
        }
    }

    private boolean actuallyEmpty(Set xssConstructs) {
        for (String xssConstruct : xssConstructs) {
            if (StringUtils.isNotBlank(xssConstruct)) {
                return false;
            }
        }
        return true;
    }


    private String getMatchPackagePrefix(String className) {
        String[] parts = StringUtils.split(className, SEPARATOR);
        if (parts.length == 1) {
            return StringUtils.EMPTY;
        }
        if (parts.length > 2) {
            return StringUtils.join(parts, SEPARATOR, 0, 2);
        } else {
            return StringUtils.join(parts, SEPARATOR, 0, parts.length - 1);
        }

    }

    private void setAppLocationStatusFile(Set deployedApplications) {
        String appLocations = StringUtils.EMPTY;

        for (DeployedApplication deployedApplication : deployedApplications) {
            if (StringUtils.isNotBlank(deployedApplication.getDeployedPath())) {
                StringUtils.joinWith(SEPARATOR1, appLocations, deployedApplication.getDeployedPath());
            }
        }
        AgentUtils.getInstance().getStatusLogValues().put(APP_LOCATION, appLocations);
    }


    private JavaAgentEventBean prepareJSInjectionEvent(JavaAgentEventBean eventBean,
            JSInjectionOperation jsInjectionOperationalBean) {
        JSONArray params = new JSONArray();
        params.add(jsInjectionOperationalBean.getJavaScriptCode());
        eventBean.setParameters(params);
        return eventBean;
    }

    private JavaAgentEventBean prepareXQueryInjectionEvent(JavaAgentEventBean eventBean,
            XQueryOperation xQueryOperationalBean) {
        JSONArray params = new JSONArray();
        params.add(xQueryOperationalBean.getExpression());
        eventBean.setParameters(params);
        return eventBean;
    }


    private JavaAgentEventBean prepareXPATHEvent(JavaAgentEventBean eventBean,
            XPathOperation xPathOperationalBean) {
        JSONArray params = new JSONArray();
        params.add(xPathOperationalBean.getExpression());
        eventBean.setParameters(params);
        return eventBean;
    }

    private JavaAgentEventBean prepareHashEvent(JavaAgentEventBean eventBean,
            HashCryptoOperation hashOperationalBean) {
        JSONArray params = new JSONArray();
        params.add(hashOperationalBean.getName());
        if (StringUtils.isNotBlank(hashOperationalBean.getProvider())) {
            params.add(hashOperationalBean.getProvider());
        }
        eventBean.setParameters(params);
        return eventBean;
    }

    private JavaAgentEventBean prepareCryptoEvent(JavaAgentEventBean eventBean,
            HashCryptoOperation hashCryptoOperationalBean) {
        JSONArray params = new JSONArray();
        params.add(hashCryptoOperationalBean.getName());
        if (StringUtils.isNotBlank(hashCryptoOperationalBean.getProvider())) {
            params.add(hashCryptoOperationalBean.getProvider());
        }
        eventBean.setParameters(params);
        eventBean.setEventCategory(hashCryptoOperationalBean.getEventCategory());
//        if (eventBean.getSourceMethod().equals(JAVAX_CRYPTO_CIPHER_GETINSTANCE_STRING)
//                || eventBean.getSourceMethod().equals(JAVAX_CRYPTO_CIPHER_GETINSTANCE_STRING_PROVIDER)) {
//            eventBean.setEventCategory(CIPHER);
//        } else if (eventBean.getSourceMethod().equals(JAVAX_CRYPTO_KEYGENERATOR_GETINSTANCE_STRING)
//                || eventBean.getSourceMethod().equals(JAVAX_CRYPTO_KEYGENERATOR_GETINSTANCE_STRING_STRING)
//                || eventBean.getSourceMethod().equals(JAVAX_CRYPTO_KEYGENERATOR_GETINSTANCE_STRING_PROVIDER)) {
//            eventBean.setEventCategory(KEYGENERATOR);
//        } else if (eventBean.getSourceMethod().equals(JAVA_SECURITY_KEYPAIRGENERATOR_GETINSTANCE_STRING)
//                || eventBean.getSourceMethod().equals(JAVA_SECURITY_KEYPAIRGENERATOR_GETINSTANCE_STRING_STRING)
//                || eventBean.getSourceMethod().equals(JAVA_SECURITY_KEYPAIRGENERATOR_GETINSTANCE_STRING_PROVIDER)) {
//            eventBean.setEventCategory(KEYPAIRGENERATOR);
//        }
        return eventBean;
    }

    private JavaAgentEventBean prepareTrustBoundaryEvent(JavaAgentEventBean eventBean,
            TrustBoundaryOperation trustBoundaryOperationalBean) {
        JSONArray params = new JSONArray();
        params.add(trustBoundaryOperationalBean.getKey());
        params.add(JsonConverter.toJSON(trustBoundaryOperationalBean.getValue()));
        eventBean.setParameters(params);
        return eventBean;
    }

    private JavaAgentEventBean prepareRandomEvent(JavaAgentEventBean eventBean,
            RandomOperation randomOperationalBean) {
        JSONArray params = new JSONArray();
        params.add(randomOperationalBean.getClassName());
        eventBean.setEventCategory(randomOperationalBean.getEventCatgory());
        eventBean.setParameters(params);
        return eventBean;
    }

    private JavaAgentEventBean prepareSecureCookieEvent(JavaAgentEventBean eventBean,
            SecureCookieOperationSet secureCookieOperationalBean) {
        JSONArray params = new JSONArray();
        for (SecureCookieOperationSet.SecureCookieOperation secureCookieOperation : secureCookieOperationalBean.getOperations()) {
            JSONObject cookie = new JSONObject();
            cookie.put(COOKIE_NAME, secureCookieOperation.getName());
            cookie.put(COOKIE_VALUE, secureCookieOperation.getValue());
            cookie.put(COOKIE_IS_SECURE, secureCookieOperation.isSecure());
            cookie.put(COOKIE_IS_HTTP_ONLY, secureCookieOperation.isHttpOnly());
            cookie.put(COOKIE_IS_SAME_SITE_STRICT, secureCookieOperation.isSameSiteStrict());
            params.add(cookie);
        }
        eventBean.setParameters(params);
        return eventBean;
    }

    private JavaAgentEventBean prepareLDAPEvent(JavaAgentEventBean eventBean, LDAPOperation ldapOperationalBean) {
        JSONArray params = new JSONArray();
        JSONObject object = new JSONObject();
        object.put(NAME, ldapOperationalBean.getName());
        object.put(FILTER, ldapOperationalBean.getFilter());
        params.add(object);
        eventBean.setParameters(params);
        return eventBean;
    }

    private JavaAgentEventBean prepareFileIntegrityEvent(JavaAgentEventBean eventBean,
            FileIntegrityOperation fileIntegrityBean) {
        JSONArray params = new JSONArray();
        params.add(fileIntegrityBean.getFileName());
        eventBean.setParameters(params);
//		eventBean.setUserAPIInfo(fileIntegrityBean.getLineNumber(), fileIntegrityBean.getClassName(),
//				fileIntegrityBean.getUserMethodName());
        return eventBean;
    }

    private JavaAgentEventBean prepareSQLDbCommandEvent(BatchSQLOperation operation,
            JavaAgentEventBean eventBean) {
        JSONArray params = new JSONArray();
        for (SQLOperation operationalBean : operation.getOperations()) {
            JSONObject query = new JSONObject();
            query.put(QUERY, operationalBean.getQuery());
            if(operationalBean.getParams() != null) {
                query.put(PARAMETERS, new JSONObject(operationalBean.getParams()));
            }
            params.add(query);
        }
        eventBean.setParameters(params);
        eventBean.setEventCategory(operation.getOperations().get(0).getDbName());
        return eventBean;
    }

    private JavaAgentEventBean prepareSQLDbCommandEvent(SQLOperation operation,
                                                        JavaAgentEventBean eventBean) {
        JSONArray params = new JSONArray();
        JSONObject query = new JSONObject();
        query.put(QUERY, operation.getQuery());
        if(operation.getParams() != null) {
            query.put(PARAMETERS, new JSONObject(operation.getParams()));
        }
        if(operation.getObjectParams() != null && !operation.getObjectParams().isEmpty()){
            JSONObject jsonObject = (JSONObject) query.get(PARAMETERS);
            if(jsonObject == null){
                query.put(PARAMETERS, jsonObject);
            }
            for (Map.Entry objParameter : operation.getObjectParams().entrySet()) {
                jsonObject.put(objParameter.getKey(), JsonConverter.toJSON(objParameter.getValue()));
            }
        }
        params.add(query);
        eventBean.setParameters(params);
        if (operation.isStoredProcedureCall()) {
            eventBean.setEventCategory(SQL_STORED_PROCEDURE);
        } else {
            eventBean.setEventCategory(operation.getDbName());
        }

        return eventBean;
    }

    private JavaAgentEventBean prepareSystemCommandEvent(JavaAgentEventBean eventBean,
            ForkExecOperation operationalBean) {
        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();
        }
        return eventBean;
    }

    private static JavaAgentEventBean prepareFileEvent(JavaAgentEventBean eventBean,
            FileOperation fileOperationalBean) {
        JSONArray params = new JSONArray();
        params.addAll(fileOperationalBean.getFileName());
        eventBean.setParameters(params);
        if(fileOperationalBean.isGetBooleanAttributesCall()) {
            eventBean.setEventCategory("FILE_EXISTS");
        }
        return eventBean;
    }

    private static JavaAgentEventBean prepareNoSQLEvent(JavaAgentEventBean eventBean,
            NoSQLOperation noSQLOperationalBean) throws ParseException {
        JSONArray params = new JSONArray();
        eventBean.setEventCategory(MONGO);
        JSONParser jsonParser = new JSONParser();
        for (String data : noSQLOperationalBean.getPayload()) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("payload", jsonParser.parse(data));
            jsonObject.put("payloadType", noSQLOperationalBean.getPayloadType());
            params.add(jsonObject);
        }
        eventBean.setParameters(params);
        return eventBean;
    }

    private static JavaAgentEventBean prepareMemcachedEvent(JavaAgentEventBean eventBean, MemcachedOperation memcachedOperationalBean) {
        JSONArray params = new JSONArray();
        for (Object data : memcachedOperationalBean.getArguments()) {
            params.add(data);
        }
        JSONObject command = new JSONObject();
        command.put(REDIS_ARGUMENTS, params);
        command.put(REDIS_TYPE, memcachedOperationalBean.getType());
        command.put(REDIS_MODE, memcachedOperationalBean.getCommand());
        JSONArray parameter = new JSONArray();
        parameter.add(command);
        eventBean.setParameters(parameter);
        eventBean.setEventCategory(memcachedOperationalBean.getCategory());
        return eventBean;
    }

    private static JavaAgentEventBean prepareDynamoDBEvent(JavaAgentEventBean eventBean, DynamoDBOperation dynamoDBOperation) {
        JSONArray params = new JSONArray();
        eventBean.setEventCategory(dynamoDBOperation.getCategory().toString());
        List originalPayloads = dynamoDBOperation.getPayload();
        for (DynamoDBRequest data : originalPayloads) {
            params.add(DynamoDBRequestConverter.convert(dynamoDBOperation.getCategory(), data));
        }
        eventBean.setParameters(params);
        return eventBean;
    }

    private static JavaAgentEventBean prepareSSRFEvent(JavaAgentEventBean eventBean,
            SSRFOperation ssrfOperationalBean) {
        JSONArray params = new JSONArray();
        params.add(ssrfOperationalBean.getArg());
        eventBean.setParameters(params);
        if (ssrfOperationalBean.isJNDILookup()) {
            eventBean.setEventCategory("JNDILookup");
        }
        return eventBean;
    }

    private boolean allowedExtensionFileIO(JSONArray params, String sourceString, String url) {
        if (JAVA_IO_FILE_INPUTSTREAM_OPEN.equals(sourceString)) {
            for (int i = 0; i < params.size(); i++) {
                String filePath = params.get(i).toString();

                if (StringUtils.containsIgnoreCase(filePath, File.separator)) {
                    filePath = StringUtils.substringAfterLast(filePath, File.separator);
                }

                if (StringUtils.containsIgnoreCase(url, File.separator)) {
                    url = StringUtils.substringAfterLast(url, File.separator);
                }

                if (StringUtils.equals(url, filePath))
                    return true;
            }
        }
        return false;
    }

    private JavaAgentEventBean processStackTrace(JavaAgentEventBean eventBean,
            VulnerabilityCaseType vulnerabilityCaseType, boolean deserialisationCheck) {

        String klassName = null;
        for (int i = 0; i < operation.getStackTrace().length; i++) {
            // TODO : check this sequence. Why this is being set from inside Deserialisation check.

            klassName = operation.getStackTrace()[i].getClassName();
            if (VulnerabilityCaseType.SYSTEM_COMMAND.equals(vulnerabilityCaseType)
                    || VulnerabilityCaseType.SQL_DB_COMMAND.equals(vulnerabilityCaseType)
                    || VulnerabilityCaseType.FILE_INTEGRITY.equals(vulnerabilityCaseType)
                    || VulnerabilityCaseType.NOSQL_DB_COMMAND.equals(vulnerabilityCaseType)
                    || VulnerabilityCaseType.FILE_OPERATION.equals(vulnerabilityCaseType)
                    || VulnerabilityCaseType.HTTP_REQUEST.equals(vulnerabilityCaseType)
                    || VulnerabilityCaseType.SYSTEM_EXIT.equals(vulnerabilityCaseType)) {
                xxeTriggerCheck(i, eventBean, klassName);
                if (deserialisationCheck) {
                    deserializationTriggerCheck(i, eventBean, klassName);
                }
            }
        }
        return eventBean;
    }

    private void xxeTriggerCheck(int i, JavaAgentEventBean eventBean, String klassName) {

        if ((StringUtils.contains(klassName, XML_DOCUMENT_FRAGMENT_SCANNER_IMPL)
                && StringUtils.equals(operation.getStackTrace()[i].getMethodName(), SCAN_DOCUMENT))
                || (StringUtils.contains(klassName, XML_ENTITY_MANAGER)
                && StringUtils.equals(operation.getStackTrace()[i].getMethodName(), SETUP_CURRENT_ENTITY))) {
            eventBean.getMetaData().setTriggerViaXXE(true);
        }
    }

    private void deserializationTriggerCheck(int index, JavaAgentEventBean eventBean, String klassName) {
        if (!NewRelic.getAgent().getConfig().getValue(INRSettingsKey.SECURITY_DETECTION_DESERIALIZATION_ENABLED, true)) {
            return;
        }
        if (ObjectInputStream.class.getName().equals(klassName)
                && StringUtils.equals(operation.getStackTrace()[index].getMethodName(), READ_OBJECT)) {
            eventBean.getMetaData().setTriggerViaDeserialisation(true);
        }
    }

    private void rciTriggerCheck(int index, JavaAgentEventBean eventBean, String klassName) {
        if (!NewRelic.getAgent().getConfig().getValue(INRSettingsKey.SECURITY_DETECTION_RCI_ENABLED, true)) {
            return;
        }

        if (operation.getStackTrace()[index].getLineNumber() <= 0 && index > 0
                && operation.getStackTrace()[index - 1].getLineNumber() > 0 &&
                StringUtils.isNotBlank(operation.getStackTrace()[index - 1].getFileName())) {
            eventBean.getMetaData().setTriggerViaRCI(true);
            eventBean.getMetaData().getRciMethodsCalls().add(AgentUtils.stackTraceElementToString(operation.getStackTrace()[index]));
            eventBean.getMetaData().getRciMethodsCalls().add(AgentUtils.stackTraceElementToString(operation.getStackTrace()[index - 1]));
        }
        if (StringUtils.contains(klassName, REFLECT_NATIVE_METHOD_ACCESSOR_IMPL)
                && StringUtils.equals(operation.getStackTrace()[index].getMethodName(), INVOKE_0) && index > 0) {
            eventBean.getMetaData().setTriggerViaRCI(true);
            eventBean.getMetaData().getRciMethodsCalls().add(AgentUtils.stackTraceElementToString(operation.getStackTrace()[index - 1]));
        }
    }

    private JavaAgentEventBean setGenericProperties(AbstractOperation objectBean, JavaAgentEventBean eventBean) {
        eventBean.setApplicationUUID(AgentInfo.getInstance().getApplicationUUID());
        eventBean.setPid(AgentInfo.getInstance().getVMPID());
        eventBean.setSourceMethod(objectBean.getSourceMethod());
        eventBean.setId(objectBean.getExecutionId());
        eventBean.setParentId(securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, String.class));
        eventBean.setStartTime(objectBean.getStartTime());
        eventBean.setBlockingProcessingTime((Long) extraInfo.get(BLOCKING_END_TIME) - eventBean.getStartTime());
        eventBean.setApiId(objectBean.getApiID());
        eventBean.setUserAPIInfo(operation.getUserClassEntity().getUserClassElement().getLineNumber(),
                operation.getUserClassEntity().getUserClassElement().getClassName(),
                operation.getUserClassEntity().getUserClassElement().getMethodName());
        eventBean.getLinkingMetadata().put(NR_APM_TRACE_ID, securityMetaData.getCustomAttribute(NR_APM_TRACE_ID, String.class));
        eventBean.getLinkingMetadata().put(NR_APM_SPAN_ID, securityMetaData.getCustomAttribute(NR_APM_SPAN_ID, String.class));
        return eventBean;
    }

    private JavaAgentEventBean prepareEvent(HttpRequest httpRequestBean, AgentMetaData metaData,
            VulnerabilityCaseType vulnerabilityCaseType, K2RequestIdentifier k2RequestIdentifier) {
        JavaAgentEventBean eventBean = new JavaAgentEventBean();
        eventBean.setHttpRequest(httpRequestBean);
        eventBean.setMetaData(metaData);
        eventBean.getMetaData().setAppServerInfo(AppServerInfoHelper.getAppServerInfo());
        eventBean.setCaseType(vulnerabilityCaseType.getCaseType());
        eventBean.setIsAPIBlocked(metaData.isApiBlocked());
        eventBean.setStacktrace(operation.getStackTrace());
        eventBean.setIsIASTRequest(k2RequestIdentifier.getK2Request());
        if (AgentUtils.getInstance().getAgentPolicy().getVulnerabilityScan().getEnabled() && AgentUtils.getInstance().getAgentPolicy().getVulnerabilityScan().getIastScan().getEnabled()) {
            eventBean.setIsIASTEnable(true);
        }
        return eventBean;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy