@hclsoftware/secagent
Version:
IAST agent
717 lines (712 loc) • 16.8 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
const CONSTRUCTOR_NAME = require('../Hooks/HookValues').CONSTRUCTOR_NAME
/**
* These hooks which are read by setRequireHook Function, to return origModule from require() call, after replacing the methods with proxy.
* See instructions for adding a new hook in Hooks.js.
* @see HookParser.setRequireHook
*/
const requireHooks = {
bcrypt: [
{
methodName: ['hash', 'hashSync', 'compareSync'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0', '1']
}
]
},
{
methodName: ['compare'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: 'all'
}
]
}
],
bcryptjs: [
{
methodName: ['hash', 'hashSync', 'compareSync'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0', '1']
}
]
},
{
methodName: ['compare'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: 'all'
}
]
}
],
mongodb: [
{
scopes: ['Collection', 'prototype'],
methodName: 'find',
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { return: CONSTRUCTOR_NAME, that: 'mongodb.Collection' }
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.SQL_INJECTION
}
]
}
],
sequelize: [
{
scopes: ['prototype'],
methodName: 'query',
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'sequelize' }
}
],
rules: [
{
type: HookType.SEQUELIZE_SINK,
from: '0',
vulnerability: Vulnerability.SQL_INJECTION
}
]
},
{
scopes: ['Model'],
methodName: ['create'],
taintCondition: ['args'],
beforeRules: [
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'Sequelize.Model' }
}
],
rules: [
{
type: HookType.SINK,
from: 'args',
vulnerability : Vulnerability.PASSWORD_LEAKAGE_DB
}
]
}
],
child_process: [
{
methodName: ['exec','execSync'],
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { return: CONSTRUCTOR_NAME, that: 'child_process' }
}
],
rules: [
{
type: HookType.COMMAND_INJECTION_CHECK_ARGS_SINK,
from: '0',
vulnerability: Vulnerability.COMMAND_INJECTION
}
]
},
{
methodName: ['spawn', 'spawnSync'],
taintCondition: ['args'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { return: CONSTRUCTOR_NAME, that: 'child_process' }
}
],
rules: [
{
type: HookType.COMMAND_INJECTION_CHECK_ARGS_SINK,
from: 'args',
vulnerability: Vulnerability.COMMAND_INJECTION
}
]
}
],
sqlite3: [
{
scopes: ['Database', 'prototype'],
methodName: ['run','each','get','all'],
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.ARG_OBJECTS_TO_STRING,
applyFor: ['1']
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.SQL_INJECTION
}
]
},
{
scopes: ['Database', 'prototype'],
methodName: 'prepare',
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.SQL_INJECTION
}
]
}
],
path: [
{
methodName: ['join', 'resolve'],
taintCondition: ['args'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: 'all'
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'path' }
}
],
rules: [
{
type: HookType.PROPAGATOR_ARRAY_SOURCE,
from: 'args',
to: 'return'
}
]
},
{
methodName: ['basename', 'dirname', 'normalize', 'parse', 'extname', 'toNameSpacePath'],
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: 'all' // to cover also optional basename argument 'ext'
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'path' }
}
],
rules: [
{
type: HookType.PROPAGATOR,
from: '0',
to : 'return'
}
]
}
],
fs: [
// to string on index 0
{
methodName: ['access', 'accessSync', 'lstat', 'lstatSync', 'lutimes', 'lutimesSync', 'stat',
'statSync', 'unwatchFile', 'utimes', 'utimesSync', 'watchFile'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
]
},
{
methodName: ['existsSync', 'join'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: 'all'
}
]
},
// sink and to_string for index 0
{
methodName: ['appendFile', 'appendFileSync', 'chmod', 'chmodSync', 'chown', 'chownSync', 'createReadStream',
'createWriteStream', 'lchmod', 'lchmodSync', 'lchown', 'lchownSync', 'mkdir', 'mkdirSync', 'open', 'openSync',
'readFile', 'readFileSync', 'readdir', 'readdirSync', 'opendir', 'opendirSync', 'readlink', 'readlinkSync',
'rmdir', 'rmdirSync', 'rm', 'rmSync', 'truncate', 'truncateSync', 'unlink', 'unlinkSync', 'writeFileSync'],
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'fs' }
}],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.PATH_TRAVERSAL
}]
},
// sink for indix 0 and to_string for indices 0, 1:
{
methodName: ['writeFile'],
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0', '1']
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: {that: 'fs'}
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.PATH_TRAVERSAL
}
]
},
// sink and to_string for indices 0, 1
{
methodName: ['rename', 'renameSync',
'symlink', 'symlinkSync',
'copyFile', 'copyFileSync',
'link', 'linkSync'],
taintCondition: ['0', '1'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0', '1']
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: {that: 'fs'}
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.PATH_TRAVERSAL
},
{
type: HookType.SINK,
from: '1',
vulnerability: Vulnerability.PATH_TRAVERSAL
}
]
},
// fs propagators
{
methodName: ['realpathSync'],
taintCondition: ['0'],
rules: [
{
type: HookType.PROPAGATOR,
from: '0',
to: 'return'
}
]
},
// realpath returns the resolved path to a callback that gets two arguments (err, resolvedPath)
{
methodName: ['realpath'],
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.WRAP_CALLBACK_REALPATH
}
],
callbackRules: [
{
type: HookType.PROPAGATOR,
from: '0',
to: 'callbackArg'
}
]
},
// to string on index 0 for fsPromises
{
scopes: ['promises'],
methodName: ['access', 'lstat', 'lutimes', 'stat', 'utimes'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}]
},
// sink and to_string for index 0 for fs.promises
{
scopes: ['promises'],
methodName: ['appendFile', 'chmod','chown', 'lchmod', 'lchown', 'mkdir', 'open', 'readFile',
'readdir', 'readlink', 'rmdir', 'truncate', 'unlink', 'writeFile', 'opendir', 'rm'],
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'fs' }
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.PATH_TRAVERSAL
}
]
},
// sink and to_string for index 1 for fs.promises
{
scopes: ['promises'],
methodName: ['copyFile', 'link', 'rename', 'symlink'],
taintCondition: ['0', '1'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['1']
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'fs' }
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.PATH_TRAVERSAL
},
{
type: HookType.SINK,
from: '1',
vulnerability: Vulnerability.PATH_TRAVERSAL
}
]
}
],
url: [
{
methodName: 'URL', // we need both this hook and the one in Hooks.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: ['Url', 'prototype'],
methodName: 'parse',
taintCondition: ['0'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
],
rules: [
{
type: HookType.PROPAGATOR,
from: '0',
to: 'return'
}
]
}
],
xpath: [
{
methodName: ['select', 'useNamespaces'],
beforeRules: [
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { return: 'NodeElement', 1 : 'Document'}
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.XPATH_INJECTION
}
]
}
],
http: [
{
scopes: ['ClientRequest', 'prototype'], //maybe hook OutgoingMessage (the base class) instead of ClientRequest
methodName: ['end', 'write'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
],
}
],
jsonwebtoken:[
{
methodName: 'sign',
beforeRules: [
{
type: BeforeType.ARG_OBJECTS_TO_STRING,
applyFor: ['0', '1']
}
],
rules: [
{
type: HookType.PROPAGATOR,
from: '0',
to: 'return',
}
]
},
{
methodName: 'decode',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0'],
}
],
rules: [
{
type: HookType.PROPAGATOR,
from: '0',
to: 'return',
}
]
},
{
methodName: 'verify',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0','1'],
}
],
rules: [
{
type: HookType.PROPAGATOR,
from: '0',
to: 'return',
}
]
},
],
stream: [
{
scopes: ['Transform', '__proto__', 'prototype'],
methodName: 'write',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
],
},
{
scopes: ['Writable', 'prototype'],
methodName: 'write',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0']
}
],
},
],
libxmljs: [
{
methodName: ['parseXmlString', 'parseXml'],
rules: [
{
type: HookType.XXE_SINK,
from: '0'
}]
}
],
ldapjs: [
{
scopes: ['Client', 'prototype'],
methodName: ['search'],
beforeRules: [
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'Client'}
}
],
rules: [
{
type: HookType.SINK,
from: '0',
vulnerability: Vulnerability.LDAP_INJECTION
}]
}
],
axios: [
{
scopes: ['Axios', 'prototype'],
methodName: ['_request'], // _request does not exist in old versions of axios (e.g "0.20.0"). Consider change to 'request' instead
beforeRules: [
{
type: BeforeType.ARG_OBJECTS_TO_STRING,
applyFor: 'all',
},
{
type: BeforeType.CLONE_HOOKS_VALUES,
},
{
type: BeforeType.AXIOS_SINK,
from: 'args',
},
{
type: BeforeType.AXIOS_SINK,
from: 'that',
},
{
type: BeforeType.AXIOS_GET_TAGS_FROM_FIELDS,
},
{
type: BeforeType.AXIOS_SENDER,
from: 'that',
},
],
rules: [
{
type: HookType.AXIOS_SOURCE,
to: 'return',
},
]
}
],
"./lib/callback_model": [
{
scopes: ['Channel', 'prototype'],
methodName: 'publish',
beforeRules: [
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'RabbitMQ.Channel'}
},
{
type: BeforeType.RABBITMQ_SENDER,
},
],
},
{
scopes: ['Channel', 'prototype'],
methodName: 'assertQueue',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0'],
}
]
}
],
"./lib/channel_model": [
{
scopes: ['Channel', 'prototype'],
methodName: 'publish',
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0'],
},
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'RabbitMQ.Channel'}
},
{
type: BeforeType.RABBITMQ_SENDER,
},
],
},
{
scopes: ['Channel', 'prototype'],
methodName: ['assertQueue'],
beforeRules: [
{
type: BeforeType.ARGS_TO_STRING,
applyFor: ['0'],
}
]
}
],
"./channel": [
{
scopes: ['BaseChannel', 'prototype'],
methodName: 'handleDelivery',
beforeRules: [
{
type: BeforeType.ADD_HOOK_VALUE_NAMES,
hookValueNames: { that: 'RabbitMQ.BaseChannel'}
},
{
type: BeforeType.REGISTER_TAINT_ON_RABBITMQ_MESSAGE,
},
{
type: BeforeType.RABBITMQ_RECEIVER,
}
]
}
]
}
module.exports = requireHooks