From 1d34df3bdb5bbf80c1e46eb09eb61d72745bf1cd Mon Sep 17 00:00:00 2001 From: idawda Date: Wed, 19 Mar 2025 16:51:07 +0530 Subject: [PATCH 1/2] NR-293076: Honour debug flag --- .../instrumentator/dispatcher/Dispatcher.java | 4 +- .../dispatcher/DispatcherPool.java | 7 +++ .../helper/DynamoDBRequestConverter.java | 6 +++ .../IASTDataTransferRequestProcessor.java | 9 ++++ .../instrumentator/utils/CallbackUtils.java | 6 +++ .../utils/InstrumentationUtils.java | 13 ++++-- .../httpclient/ApacheHttpClientWrapper.java | 5 ++- .../apache/httpclient/IastHttpClient.java | 4 ++ .../intcodeagent/schedulers/FileCleaner.java | 13 ++++++ .../intcodeagent/utils/EncryptorUtils.java | 12 +++++ .../newrelic/api/agent/security/Agent.java | 44 ++++++++++++++----- 11 files changed, 107 insertions(+), 16 deletions(-) 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 1dc26ef1e..02828e76f 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 @@ -589,7 +589,9 @@ private JavaAgentEventBean prepareSystemCommandEvent(JavaAgentEventBean eventBea eventBean.setParameters(params); return eventBean; } catch (Throwable e){ - e.printStackTrace(); + if (Agent.isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Error while preparing SYSTEM_COMMAND event: " + JsonConverter.toJSON(operation), e, Agent.class.getName()); + } } return eventBean; } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/DispatcherPool.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/DispatcherPool.java index 7297009b1..05548b55a 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/DispatcherPool.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/dispatcher/DispatcherPool.java @@ -6,6 +6,7 @@ import com.newrelic.agent.security.intcodeagent.executor.CustomThreadPoolExecutor; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.utils.IastExclusionUtils; +import com.newrelic.api.agent.security.Agent; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; import com.newrelic.agent.security.intcodeagent.models.javaagent.EventStats; @@ -116,6 +117,9 @@ protected void afterExecute(Runnable r, Throwable t) { AbstractOperation operation = dispatcher.getOperation(); SecurityMetaData securityMetaData = dispatcher.getSecurityMetaData(); if(t != null){ + if (Agent.isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Debug: Error occurred while sending the event.", t, DispatcherPool.class.getName()); + } AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDispatcher().incrementError(); if(operation != null) { if(securityMetaData != null && securityMetaData.getFuzzRequestIdentifier().getK2Request()) { @@ -211,6 +215,9 @@ public void dispatchEvent(AbstractOperation operation, SecurityMetaData security RestRequestThreadPool.getInstance().registerEventForProcessedCC(parentId, operation.getExecutionId()); } } + if (Agent.isDebugEnabled()) { + logger.log(LogLevel.FINEST, String.format("Debug: Register execution id %s with parent-id as %s", operation.getExecutionId(), parentId), this.getClass().getName()); + } } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/helper/DynamoDBRequestConverter.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/helper/DynamoDBRequestConverter.java index 05cf8d22f..2c45e7d5b 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/helper/DynamoDBRequestConverter.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/helper/DynamoDBRequestConverter.java @@ -1,7 +1,10 @@ package com.newrelic.agent.security.instrumentator.helper; +import com.newrelic.agent.security.instrumentator.utils.CallbackUtils; +import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; import com.newrelic.api.agent.security.Agent; +import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.schema.helper.DynamoDBRequest; import com.newrelic.api.agent.security.schema.operation.DynamoDBOperation; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -127,6 +130,9 @@ else if (value.getClass().getName().contains("AttributeValue")) { } } } catch (IllegalAccessException ignored) { + if (Agent.isDebugEnabled()) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, "Debug: Error occurred while sending the event.", ignored, CallbackUtils.class.getName()); + } } } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/IASTDataTransferRequestProcessor.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/IASTDataTransferRequestProcessor.java index 31ebfa7a7..2a9e12c58 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/IASTDataTransferRequestProcessor.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/httpclient/IASTDataTransferRequestProcessor.java @@ -4,7 +4,9 @@ import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.instrumentator.utils.INRSettingsKey; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.schedulers.FileCleaner; import com.newrelic.agent.security.util.IUtilConstants; +import com.newrelic.api.agent.security.Agent; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.models.IASTDataTransferRequest; import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter; @@ -77,6 +79,9 @@ private void task() { // Sleep if under cooldown long cooldownSleepTime = cooldownTillTimestamp.get() - currentTimestamp; if(cooldownSleepTime > 0) { + if (Agent.isDebugEnabled()) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Debug: Executing IASTDataTransferRequest thread to sleep due to %s millis due Cool down.", cooldownSleepTime), FileCleaner.class.getName()); + } Thread.sleep(cooldownSleepTime); } @@ -99,6 +104,10 @@ private void task() { int currentRecordBacklog = Math.max(currentRecordBacklogRest, currentRecordBacklogGrpc); int remainingRecordCapacity = Math.min(remainingRecordCapacityRest, remainingRecordCapacityGrpc); + if (Agent.isDebugEnabled()) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Debug: IAST Replay backlog for REST and gRPC are : %s and %s respectively.", currentRecordBacklogRest, currentRecordBacklogRest), FileCleaner.class.getName()); + } + int batchSize = currentFetchThreshold - currentRecordBacklog; if(!AgentUsageMetric.isRASPProcessingActive()){ batchSize /= 2; diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/CallbackUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/CallbackUtils.java index 9d74d6bbd..c52dedeb2 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/CallbackUtils.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/CallbackUtils.java @@ -1,6 +1,7 @@ package com.newrelic.agent.security.instrumentator.utils; 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.api.agent.security.instrumentation.helpers.ServletHelper; import com.newrelic.api.agent.security.schema.HttpRequest; @@ -71,6 +72,9 @@ public static Set checkForReflectedXSS(HttpRequest httpRequest, HttpResp logger.log(LogLevel.FINER, String.format("Checking reflected XSS : %s :: %s", combinedRequestData, combinedResponseDataString), CallbackUtils.class.getName()); Set attackContructs = isXSS(combinedRequestData); + if (Agent.isDebugEnabled()) { + logger.log(LogLevel.FINEST, String.format("Debug: RXSS Attack Constructs found in Request %s", attackContructs), CallbackUtils.class.getName()); + } for (String construct : attackContructs) { if (StringUtils.containsIgnoreCase(combinedResponseDataString, construct)) { @@ -84,6 +88,8 @@ public static Set checkForReflectedXSS(HttpRequest httpRequest, HttpResp } if (toReturn.isEmpty()) { toReturn.add(StringUtils.EMPTY); + } else if (Agent.isDebugEnabled()) { + logger.log(LogLevel.FINEST, String.format("Debug: RXSS Attack Constructs found : %s", toReturn), CallbackUtils.class.getName()); } return toReturn; } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/InstrumentationUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/InstrumentationUtils.java index e7c8017b3..50680d970 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/InstrumentationUtils.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/instrumentator/utils/InstrumentationUtils.java @@ -5,17 +5,18 @@ import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.intcodeagent.controlcommand.ControlCommandProcessorThreadPool; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; -import com.newrelic.agent.security.intcodeagent.schedulers.FileCleaner; -import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.HealthCheckScheduleThread; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; import com.newrelic.agent.security.intcodeagent.models.javaagent.ShutDownEvent; +import com.newrelic.agent.security.intcodeagent.schedulers.FileCleaner; import com.newrelic.agent.security.intcodeagent.websocket.EventSendPool; import com.newrelic.agent.security.intcodeagent.websocket.WSClient; import com.newrelic.agent.security.intcodeagent.websocket.WSReconnectionST; +import com.newrelic.api.agent.security.Agent; +import com.newrelic.api.agent.security.utils.logging.LogLevel; import org.apache.commons.io.FileUtils; -import org.java_websocket.framing.CloseFrame; import org.apache.commons.lang3.StringUtils; +import org.java_websocket.framing.CloseFrame; import java.io.File; import java.util.concurrent.TimeUnit; @@ -70,6 +71,9 @@ public static void shutdownLogic() { } catch (Throwable e) { } try { + if (Agent.isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Debug: Shutting down IAST Services..", InstrumentationUtils.class.getName()); + } HealthCheckScheduleThread.getInstance().cancelTask(true); DispatcherPool.shutDownPool(); ControlCommandProcessorThreadPool.shutDownPool(); @@ -78,6 +82,9 @@ public static void shutdownLogic() { WSClient.shutDownWSClient(true, CloseFrame.NORMAL, "IAST agent shutting down"); FileCleaner.cancelTask(); if(StringUtils.isNotBlank(OsVariablesInstance.getInstance().getOsVariables().getTmpDirectory())) { + if (Agent.isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Debug: IAST Shutdown : Cleaning Tmp directory created during IAST analysis", InstrumentationUtils.class.getName()); + } FileUtils.deleteQuietly(new File(OsVariablesInstance.getInstance().getOsVariables().getTmpDirectory())); } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpClientWrapper.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpClientWrapper.java index 5e2d549a4..93acfb95b 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpClientWrapper.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/ApacheHttpClientWrapper.java @@ -2,6 +2,7 @@ import com.newrelic.agent.security.AgentInfo; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.api.agent.security.Agent; import com.newrelic.api.agent.security.schema.HttpRequest; import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.http.ReadResult; @@ -90,7 +91,9 @@ public ApacheHttpClientWrapper(int requestTimeoutInMillis) { .loadTrustMaterial(null, acceptingTrustStrategy) .build(); } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException exception){ - + if (Agent.isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Debug: Error while building SSL Context for Apache HTTP Client", exception, this.getClass().getName()); + } } this.connectionManager = createHttpClientConnectionManager(sslContext); this.httpClient = HttpClientBuilder.create() diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/IastHttpClient.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/IastHttpClient.java index fe5b82712..77663c482 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/IastHttpClient.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/apache/httpclient/IastHttpClient.java @@ -3,6 +3,7 @@ import com.newrelic.agent.security.instrumentator.httpclient.RestRequestThreadPool; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.models.FuzzRequestBean; +import com.newrelic.api.agent.security.Agent; import com.newrelic.api.agent.security.instrumentation.helpers.AppServerInfoHelper; import com.newrelic.api.agent.security.schema.AppServerInfo; import com.newrelic.api.agent.security.schema.HttpRequest; @@ -77,6 +78,9 @@ public void tryToEstablishApplicationEndpoint(HttpRequest request) { int serverPort = request.getServerPort(); if(serverPort > 0){ Map endpoints = prepareEndpoints(serverPort); + if (Agent.isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Debug: Trying to establish Application Endpoint", IastHttpClient.class.getName()); + } for (Map.Entry endpoint : endpoints.entrySet()) { try { ReadResult result = httpClient.execute(request, endpoint.getValue(), null, true); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/FileCleaner.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/FileCleaner.java index f5e46b925..4fa330d0f 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/FileCleaner.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/schedulers/FileCleaner.java @@ -4,6 +4,9 @@ import com.newrelic.agent.security.instrumentator.os.OSVariables; import com.newrelic.agent.security.instrumentator.os.OsVariablesInstance; import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.agent.security.intcodeagent.utils.EncryptorUtils; +import com.newrelic.api.agent.security.Agent; +import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper; import org.apache.commons.io.FileUtils; @@ -33,6 +36,7 @@ public class FileCleaner { @Override public void run() { + // TODO: add debug trace AgentInfo.getInstance().getJaHealthCheck().getSchedulerRuns().incrementIastFileCleaner(); long delay = Instant.now().toEpochMilli() - TimeUnit.MINUTES.toMillis(2); logger.log(LogLevel.INFO, FILE_CLEANER_INVOKED_INITIATING_TEMP_FILE_DIRECTORY_CLEANUP, FileCleaner.class.getName()); @@ -40,6 +44,9 @@ public void run() { return; } FileUtils.iterateFiles(new File(osVariables.getTmpDirectory()), new AgeFileFilter(delay), DirectoryFileFilter.INSTANCE).forEachRemaining( file -> { + if (Agent.isDebugEnabled()) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Debug: Cleaning temp files created during IAST analysis : %s", file), FileCleaner.class.getName()); + } FileUtils.deleteQuietly(file); }); @@ -51,8 +58,14 @@ public void run() { long age = delay - Files.getLastModifiedTime(Paths.get(file)).toMillis(); if(age > 0){ FileUtils.deleteQuietly(new File(file)); + if (Agent.isDebugEnabled()) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Debug: Cleaning temp files created during IAST analysis : %s", file), FileCleaner.class.getName()); + } } } catch (IOException | InvalidPathException e) { + if (Agent.isDebugEnabled()) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Debug: Error while cleaning temp files created during IAST analysis : %s", file), e, FileCleaner.class.getName()); + } } } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/EncryptorUtils.java b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/EncryptorUtils.java index bf81b8b88..9aa1c86b9 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/EncryptorUtils.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/agent/security/intcodeagent/utils/EncryptorUtils.java @@ -1,6 +1,9 @@ package com.newrelic.agent.security.intcodeagent.utils; +import com.newrelic.agent.security.instrumentator.utils.CallbackUtils; import com.newrelic.agent.security.instrumentator.utils.HashGenerator; +import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; +import com.newrelic.api.agent.security.Agent; import com.newrelic.api.agent.security.NewRelicSecurity; import com.newrelic.api.agent.security.utils.logging.LogLevel; import org.apache.commons.codec.DecoderException; @@ -34,6 +37,9 @@ public class EncryptorUtils { private static Cipher cipher = null; private static void prepareCipherInstance(String password) throws Exception { + if (Agent.isDebugEnabled()) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, "Debug: Preparing Cipher instance for decrypting data", EncryptorUtils.class.getName()); + } SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_2_WITH_HMAC_SHA_1); KeySpec spec = new PBEKeySpec(password.toCharArray(), generateSalt(password), ITERATION, KEY_LEN); SecretKey tmp = factory.generateSecret(spec); @@ -62,6 +68,9 @@ public static String decrypt(String password, String encryptedData) { // Decrypt the content byte[] decryptedBytes = cipher.doFinal(Hex.decodeHex(encryptedData)); decryptedData = new String(decryptedBytes, OFFSET, decryptedBytes.length - OFFSET); + if (Agent.isDebugEnabled()) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Debug: Decrypted data for encrypted data %s is : %s", encryptedData, decryptedData), EncryptorUtils.class.getName()); + } NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format(ENCRYPTED_DATA_S_DECRYPTED_DATA_S, encryptedData, decryptedData), EncryptorUtils.class.getName()); return decryptedData; } catch (DecoderException ignored) { @@ -83,6 +92,9 @@ public static boolean verifyHashData(String knownDecryptedDataHash, String decry NewRelicSecurity.getAgent().log(LogLevel.WARNING, String.format("Known-Decrypted Data Hash is empty %s", knownDecryptedDataHash), EncryptorUtils.class.getName()); return false; } + if (Agent.isDebugEnabled() && !StringUtils.equals(HashGenerator.getSHA256HexDigest(decryptedData), knownDecryptedDataHash)) { + NewRelicSecurity.getAgent().log(LogLevel.FINEST, String.format("Debug: The hash of the decrypted data for %s does not match.", decryptedData), EncryptorUtils.class.getName()); + } return StringUtils.equals(HashGenerator.getSHA256HexDigest(decryptedData), knownDecryptedDataHash); } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java index 5039317fa..fed2b892f 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java @@ -18,6 +18,7 @@ import com.newrelic.agent.security.intcodeagent.models.javaagent.*; import com.newrelic.agent.security.intcodeagent.utils.*; import com.newrelic.api.agent.security.instrumentation.helpers.*; +import com.newrelic.api.agent.security.schema.operation.FileOperation; import com.newrelic.api.agent.security.schema.operation.SecureCookieOperationSet; import com.newrelic.api.agent.security.schema.policy.IastDetectionCategory; import com.newrelic.api.agent.security.utils.logging.LogLevel; @@ -38,6 +39,7 @@ import java.io.File; import java.io.IOException; +import java.io.ObjectInputStream; import java.lang.instrument.Instrumentation; import java.lang.instrument.UnmodifiableClassException; import java.net.HttpURLConnection; @@ -66,6 +68,8 @@ public class Agent implements SecurityAgent { public static final String SKIPPING_THE_API_S_AS_IT_IS_PART_OF_THE_SKIP_SCAN_LIST = "Skipping the API %s as it is part of the skip scan list"; public static final String INVALID_CRON_EXPRESSION_PROVIDED_FOR_IAST_RESTRICTED_MODE = "Invalid cron expression provided for IAST Mode"; + private static final boolean DEBUG = Boolean.getBoolean("newrelic.debug") || Boolean.parseBoolean(System.getenv("NEWRELIC_DEBUG")); + private AgentInfo info; private AgentConfig config; @@ -400,8 +404,8 @@ public void registerOperation(AbstractOperation operation) { String executionId = ExecutionIDGenerator.getExecutionId(); operation.setExecutionId(executionId); operation.setStartTime(Instant.now().toEpochMilli()); - if (securityMetaData != null && securityMetaData.getFuzzRequestIdentifier().getK2Request()) { - logger.log(LogLevel.FINEST, String.format("New Event generation with id %s of type %s", operation.getExecutionId(), operation.getClass().getSimpleName()), Agent.class.getName()); + if (securityMetaData != null && securityMetaData.getFuzzRequestIdentifier().getK2Request() && isDebugEnabled()) { + logger.log(LogLevel.FINEST, String.format("Debug: New Event generation with id %s of type %s", operation.getExecutionId(), operation.getClass().getSimpleName()), Agent.class.getName()); } if (operation instanceof RXSSOperation) { operation.setStackTrace(securityMetaData.getMetaData().getServiceTrace()); @@ -422,17 +426,19 @@ public void registerOperation(AbstractOperation operation) { } if(NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_SECURITY_HOME_APP, false) && checkIfCSECGeneratedEvent(operation)) { - logger.log(LogLevel.FINEST, DROPPING_EVENT_AS_IT_WAS_GENERATED_BY_K_2_INTERNAL_API_CALL + - JsonConverter.toJSON(operation), - Agent.class.getName()); + if (isDebugEnabled()) { + logger.log(LogLevel.FINEST, DROPPING_EVENT_AS_IT_WAS_GENERATED_BY_K_2_INTERNAL_API_CALL + + JsonConverter.toJSON(operation), Agent.class.getName()); + } AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDroppedDueTo().incrementCsecInternalEvent(); return; } if(!NewRelic.getAgent().getConfig().getValue(IUtilConstants.NR_SECURITY_HOME_APP, false) && checkIfNRGeneratedEvent(operation)) { - logger.log(LogLevel.FINEST, DROPPING_EVENT_AS_IT_WAS_GENERATED_BY_K_2_INTERNAL_API_CALL + - JsonConverter.toJSON(operation), - Agent.class.getName()); + if (isDebugEnabled()) { + logger.log(LogLevel.FINEST, DROPPING_EVENT_AS_IT_WAS_GENERATED_BY_K_2_INTERNAL_API_CALL + + JsonConverter.toJSON(operation), Agent.class.getName()); + } AgentInfo.getInstance().getJaHealthCheck().getEventStats().getDroppedDueTo().incrementNrInternalEvent(); return; } @@ -462,7 +468,9 @@ public void registerOperation(AbstractOperation operation) { String route = getEndpointRoute(StringUtils.substringBefore(request.getUrl(), "?"), frameWork); if (route != null) { request.setRoute(route); - logger.log(LogLevel.FINEST,"Route detection using Application Endpoint", this.getClass().getName()); + if (isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Debug: Route detection using Application Endpoint", this.getClass().getName()); + } } } @@ -647,6 +655,9 @@ private UserClassEntity setUserClassEntity(AbstractOperation operation, Security // Section for user class identification using API handlers if( !securityMetaData.getMetaData().isFoundAnnotedUserLevelServiceMethod() && URLMappingsHelper.getHandlersHash().contains(stackTraceElement.getClassName().hashCode())){ //Found -> assign user class and return + if (isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Debug: Setting User Class details using API Endpoints detected", this.getClass().getName()); + } userClassEntity.setUserClassElement(stackTraceElement); securityMetaData.getMetaData().setUserLevelServiceMethodEncountered(true); userClassEntity.setCalledByUserCode(true); @@ -686,10 +697,18 @@ private UserClassEntity setUserClassEntity(AbstractOperation operation, Security // user class identification using annotations if (securityMetaData.getMetaData().isFoundAnnotedUserLevelServiceMethod()) { - return setUserClassEntityByAnnotation(securityMetaData.getMetaData().getServiceTrace()); + if (isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Debug: Setting User Class details using annotations", this.getClass().getName()); + } + userClassEntity.setUserClassElement(securityMetaData.getMetaData().getServiceTrace()[0]); + userClassEntity.setCalledByUserCode(true); + return userClassEntity; } if(userClassEntity.getUserClassElement() == null && operation.getStackTrace().length >= 2){ + if (isDebugEnabled()) { + logger.log(LogLevel.FINEST, "Debug: Not able to detect correct user class details", this.getClass().getName()); + } userClassEntity.setUserClassElement(operation.getStackTrace()[1]); userClassEntity.setCalledByUserCode(securityMetaData.getMetaData().isUserLevelServiceMethodEncountered()); } @@ -719,7 +738,7 @@ private void setRequiredStackTrace(AbstractOperation operation, SecurityMetaData } } - private static void processStackTrace(AbstractOperation operation) { + private void processStackTrace(AbstractOperation operation) { StackTraceElement[] stackTrace = operation.getStackTrace(); int resetFactor = 0; @@ -1085,4 +1104,7 @@ public void reportURLMapping() { SchedulerHelper.getInstance().scheduleURLMappingPosting(AgentUtils::sendApplicationURLMappings); } + public static boolean isDebugEnabled() { + return DEBUG; + } } \ No newline at end of file From c0798095e2accfd8ded6d8c11e698b0f421bb99f Mon Sep 17 00:00:00 2001 From: idawda Date: Wed, 19 Mar 2025 18:05:50 +0530 Subject: [PATCH 2/2] Optimise event stacktrace processing --- .../instrumentator/dispatcher/Dispatcher.java | 13 +----- .../newrelic/api/agent/security/Agent.java | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+), 11 deletions(-) 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 02828e76f..adf657f3a 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 @@ -240,16 +240,8 @@ public Object call() throws Exception { } - 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; - } + if (eventBean == null) { + return null; } EventSendPool.getInstance().sendEvent(eventBean); @@ -257,7 +249,6 @@ public Object call() throws Exception { 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()); diff --git a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java index fed2b892f..f9953ef42 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java @@ -777,6 +777,28 @@ private void processStackTrace(AbstractOperation operation) { } } } + if (!VulnerabilityCaseType.FILE_INTEGRITY.equals(operation.getCaseType())) { + boolean deserialisationCheck = true; + if (VulnerabilityCaseType.FILE_OPERATION.equals(operation.getCaseType()) && ((FileOperation) operation).isGetBooleanAttributesCall()) { + deserialisationCheck = false; + } + VulnerabilityCaseType vulnerabilityCaseType = operation.getCaseType(); + String klassName = operation.getStackTrace()[i].getClassName(); + // TODO : check this sequence. Why this is being set from inside Deserialisation check. + 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, operation, klassName); + if (deserialisationCheck) { + deserializationTriggerCheck(i, operation, klassName); + } + } + } if (!markedForRemoval) { newTraceForIdCalc.add(stackTrace[i].hashCode()); @@ -788,6 +810,25 @@ private void processStackTrace(AbstractOperation operation) { setAPIId(operation, newTraceForIdCalc, operation.getCaseType()); } + private void xxeTriggerCheck(int i, AbstractOperation operation, 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))) { + getSecurityMetaData().getMetaData().setTriggerViaXXE(true); + } + } + + private void deserializationTriggerCheck(int index, AbstractOperation operation, 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)) { + getSecurityMetaData().getMetaData().setTriggerViaDeserialisation(true); + } + } + private static void setAPIId(AbstractOperation operation, List traceForIdCalc, VulnerabilityCaseType vulnerabilityCaseType) { try { traceForIdCalc.add(operation.getSourceMethod().hashCode());