@hclsoftware/secagent
Version:
IAST agent
637 lines (630 loc) • 14.2 kB
JavaScript
//IASTIGNORE
/*
* ****************************************************
* Licensed Materials - Property of HCL.
* (c) Copyright HCL Technologies Ltd. 2017, 2025.
* Note to U.S. Government Users *Restricted Rights.
* ****************************************************
*/
const { Vulnerability } = require('../TaintTracker')
const HookType = require('../Rules/HookRules/HookRuleFactory').Type
const BeforeType = require('../Rules/BeforeRules/BeforeRuleFactory').Type
/*
For adding a new hook for some function:
1. The module name which is the input of require() method will be your key.
2. check if this key is already exists in the hooks object. If not, you should add it as a new key.
3. add a new object inside the list and fill the relevant properties.
Example: suppose we want to add a hook for url.format.
1. In order to use format we need to get it from url: 'require('url')', so the key is url.
2. Assume that this is the first time we use url key in hooks object, then we assign url key a new list:
hooks = { .... "url : []" }
3. we add a new object in this list and fill the relevant properties:
url: [{
methodName: 'format',
taintCondition: '0',
rules: [...]
}
]
* in this example we didn't need to use scopes property since format method is fetched directly from url module: url.format.
* But assume we want to fetch substring method, then we should add 'scopes': ['String', 'prototype'] since substring is not located directly in
the required module (in this case global), but in Global.String.prototype.
Refer to BeforeRule.js for documentation for beforeRules field in the hook.
*/
const hooks = {
global: [
{
scopes: ['String', 'prototype'],
methodName: 'substring',
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: 'substr',
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: 'toLowerCase',
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: 'toUpperCase',
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: 'concat',
taintCondition: ['that', 'args'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
},
{
type: HookType.PROPAGATOR_ARRAY_SOURCE,
from: 'args',
to: "return"
}
]
},
{
scopes: ['String', 'prototype'],
methodName: 'replaceAll',
taintCondition: ['that', '1'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
},
{
type: HookType.SANITIZER_BY_REGEX_ON_STRING,
from: 'return'
},
{
type: HookType.PROPAGATOR,
from: '1',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: 'replace',
taintCondition: ['that', '1'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
},
{
type: HookType.SANITIZER_BY_REGEX_ON_STRING,
from: 'return'
},
{
type: HookType.PROPAGATOR,
from: '1',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: 'match',
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR_TO_OBJECT_ONLY,
from: 'that',
to: 'return'
},
{
type: HookType.REPORT_VERIFICATION_BY_STRING
}
]
},
{
scopes: ['String', 'prototype'],
methodName: ['includes','startsWith','endsWith'],
taintCondition: ['that'],
rules: [
{
type: HookType.REPORT_VERIFICATION_BY_VALIDATORS
}
]
},
{
scopes: ['String', 'prototype'],
methodName: 'slice',
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: ['trim', 'trimStart', 'trimEnd'],
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: ['repeat'],
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
},
{
type: HookType.SANITIZE_ALL_FOR_PARAM_ZERO,
from: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: ['padStart','padEnd'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
},
{
optional: true,
type: HookType.PROPAGATOR,
from: '1',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: ['split'],
rules: [
{
type: HookType.PROPAGATOR_ARRAY_TARGET,
from: 'that',
to: 'return'
}
]
},
{
scopes: ['String', 'prototype'],
methodName: ['indexOf'],
rules: [
{
type: HookType.REPORT_VERIFICATION_BY_INDEXOF,
}
]
},
{
scopes: ['RegExp', 'prototype'],
methodName: ['test'],
taintCondition: ['0'],
rules: [
{
type: HookType.REPORT_VERIFICATION_BY_REGEXTEST,
from : '0',
}
]
},
{
scopes: ['Array', 'prototype'],
methodName: 'join',
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR_ARRAY_SOURCE,
from: 'that',
to: "return"
}
]
},
{
scopes: ['Array', 'prototype'],
methodName: 'includes',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.THAT_ELEMENTS_TO_STRING,
}
]
},
{
scopes: ['Array', 'prototype'],
methodName: 'indexOf',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.THAT_ELEMENTS_TO_STRING,
}
]
},
{
scopes: ['Array', 'prototype'],
methodName: 'lastIndexOf',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.THAT_ELEMENTS_TO_STRING,
}
]
},
{
methodName: 'isNaN',
taintCondition: ['0'],
rules: [
{
type: HookType.SANITIZER_FOR_ALL_FALSE_RET,
from: '0'
}
]
},
{
scopes: ['Buffer', 'prototype'],
methodName: 'includes',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
{
scopes: ['Buffer', 'prototype'],
methodName: 'fill',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0', '1', '2']
}
]
},
{
scopes: ['Buffer', 'prototype'],
methodName: 'indexOf',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
{
scopes: ['Buffer', 'prototype'],
methodName: 'lastIndexOf',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
{
scopes: ['Buffer', 'prototype'],
methodName: 'write',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
{
scopes: ['Buffer'],
methodName: ['from'],
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
],
rules: [
{
type: HookType.PROPAGATOR,
from: '0',
to: 'return'
}
]
},
{
scopes: ['Buffer'],
methodName: ['byteLength'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
{
scopes: ['Buffer', 'prototype'],
methodName: ['toString'],
taintCondition: ['that'],
rules: [
{
type: HookType.PROPAGATOR,
from: 'that',
to: 'return'
}
]
},
{
scopes: ['JSON'],
methodName: 'stringify',
taintCondition: ['0'],
rules: [
{
type: HookType.PROPAGATOR_FROM_OBJECT,
from: '0',
to: 'return'
}
]
},
{
scopes: ['JSON'],
methodName: 'parse',
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.TO_BUFFER,
applyFor: ['0']
}
],
rules: [
{
type: HookType.PROPAGATOR,
from: '0',
to: 'return'
}
]
},
{
scopes: ['Math'],
methodName: 'random',
rules: [
{
type: HookType.EXPLOIT,
from: 'that',
vulnerability: Vulnerability.WEAK_RANDOM
}
]
},
{
scopes: ['console'],
methodName: ['log', 'info', 'warn', 'debug', 'trace', 'error', 'table'],
taintCondition: ['args'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: 'all'
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'console' }
}
],
rules: [
{
type: HookType.SINK,
from: 'args',
vulnerability: Vulnerability.PASSWORD_LEAKAGE_SENT_DATA
}
]
},
{
scopes: ['process', 'stdout'],
methodName: 'write',
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'process.stdout' }
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.PASSWORD_LEAKAGE_SENT_DATA
}
]
},
{
scopes: ['process', 'stderr'],
methodName: 'write',
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'process.stderr' }
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.PASSWORD_LEAKAGE_SENT_DATA
}
]
},
{
methodName: 'Error',
rules: [
{
optional: true,
type: HookType.PROPAGATOR_TO_OBJECT_ONLY,
from: '0',
to: 'return'
},
{
optional: true,
type: HookType.PROPAGATOR_TO_PROPERTIES,
from: '0',
targetProperties: ['message', 'stack']
}
]
},
{
methodName: 'URL', // we need both this hook and the one in RequireHooks.js file for URL constructor.
rules: [
{
type: HookType.PROPAGATOR_ARRAY_SOURCE,
from: 'args',
to: 'return'
},
{
type: HookType.PROPAGATOR_ON_GETTERS,
targetProperties: ['host', 'hostname', 'href', 'origin', 'pathname', 'search']
},
{
type: HookType.PROPAGATOR_ON_SETTERS,
targetProperties: ['host', 'hostname', 'href', 'pathname', 'search']
}
]
},
{
scopes: ['Object'],
methodName: 'is',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: 'all'
}
]
},
],
crypto: [
{
scopes: ['Hash', 'prototype'],
methodName: 'update',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
{
scopes: ['Hmac', 'prototype'],
methodName: 'update',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
{
methodName: ['createCipheriv'],
rules: [
{
type: HookType.EXPLOIT,
from: '0',
vulnerability: Vulnerability.WEAK_CRYPTO
}]
},
{
methodName: ['createHmac', 'createSign', 'createVerify'],
rules: [
{
type: HookType.EXPLOIT,
from: '0',
vulnerability: Vulnerability.WEAK_HASH
}]
},
{
scopes: ['Verify', 'prototype'],
methodName: 'update',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
{
scopes: ['Verify', 'prototype'],
methodName: 'verify',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['1']
}
]
},
{
scopes: ['Sign', 'prototype'],
methodName: 'update',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
]
}
module.exports = hooks