@hclsoftware/secagent
Version:
IAST agent
93 lines (84 loc) • 4.38 kB
JavaScript
//IASTIGNORE
/*
* ****************************************************
* Licensed Materials - Property of HCL.
* (c) Copyright HCL Technologies Ltd. 2017, 2025.
* Note to U.S. Government Users *Restricted Rights.
* ****************************************************
*/
const VerificationTracker = require('../Verification/VerificationTracker')
const Vulnerability = require('../Vulnerability')
const SinkTask = require('./SinkTask')
const TaskType = require('./TaskType')
const IastLogger = require('../Logger/IastLogger')
const logger = IastLogger.eventLog
const TaintTracker = require('../TaintTracker')
const {ParameterUnderTest} = require('./ParameterUnderTest')
const SinkTaskInfo = require("./SinkInfo/SinkTaskInfo")
const ContextType = require("./ContextType");
const {SinkInfoStringGenerator} = require("./SinkInfo/SinkInfoStringGenerator")
const AdditionalInfo = require("../AdditionalInfo")
class PathTraversalSinkTask extends SinkTask.SinkTask {
constructor(source, vulnerability, stack, parameters, obj){
super(source, vulnerability, stack, parameters)
this.taskType = TaskType.PATH_TRAVERSAL
this.sinkStr = obj
}
performAction() {
const parameterUnderTest = new ParameterUnderTest(this.taintedObjectFlow.entity.value, this.taintedObjectFlow.taskList)
// check control
const source = parameterUnderTest.originalProcessedParam
const sinkWithSlash = this.sinkStr + "/"
const sinkWithoutExtension = this.removeExtension(this.sinkStr)
let vulnerabilitySanitized = true
let exploitExample = null
let sinkTaskInfo = null
const signature = this.getTasksInfo()
const verified = VerificationTracker.getVerifiedState(signature, this.vulnerability)
if (verified == null) {
logger.debug(`Checking vulnerability ${Vulnerability} for signature ${signature}`)
for (const currExploit of exploits) {
const processingResult = parameterUnderTest.getMutatedProcessedParam(currExploit)
const processedLegitimateExploitForCodePath = processingResult.afterProcessing
if( processedLegitimateExploitForCodePath !=null && (processedLegitimateExploitForCodePath.origStringIncludes('..\\') || processedLegitimateExploitForCodePath.origStringIncludes('../'))){
vulnerabilitySanitized = false
exploitExample = currExploit
break
}
}
if (vulnerabilitySanitized){
logger.debug(`Signature ${signature} is verified as a sanitizer`)
} else {
logger.debug(`Signature ${signature} is verified as vulnerable`)
}
sinkTaskInfo = new SinkTaskInfo(exploitExample, [ContextType["PATH"].contextTypeName], exploits, this.vulnerability)
VerificationTracker.setSignatureAsVerified(signature, this.vulnerability, vulnerabilitySanitized, sinkTaskInfo)
} else {
logger.debug(`Signature ${signature} was already verified`)
sinkTaskInfo = verified.sinkInfo
vulnerabilitySanitized = verified.verifiedOk
}
if(vulnerabilitySanitized) {
this.taintedObjectFlow.sanitize(this.vulnerability)
} else {
let additionalInfoEntry =
source != null && !(this.sinkStr.origEndsWith(source) || sinkWithSlash.origEndsWith(source) || sinkWithoutExtension.origEndsWith(source)) ? {[AdditionalInfo.keys.PATH_TRAVERSAL_PARTIAL_CONTROL]:"Note that this issue is partial path traversal, end of path is out of user control" } : null
TaintTracker.sinkTaskTrigger(this.taintedObjectFlow, this.vulnerability, new SinkInfoStringGenerator(sinkTaskInfo), true, this.stack, this.parameters, additionalInfoEntry)
}
return !vulnerabilitySanitized
}
removeExtension(filename){
let index = filename.origLastIndexOf(".")
return (index === -1) ? filename : filename.origSlice(0,index)
}
}
// "..\\", "../", "..././", "...\\.\\", "%2e%2e%2f", "%252e%252e%252f", "%252e%252e%255c", "\u002e\u002e\u2215", "\uff0e\uff0e\u2215", "\uff0e\uff0e\u2216"
const exploits =
[
"..\\",
"../",
"..././",
"...\\.\\"
]
module.exports = PathTraversalSinkTask