UNPKG

n8n-nodes-wapiti

Version:
235 lines 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Wapiti = void 0; const n8n_workflow_1 = require("n8n-workflow"); const ShellUtils_1 = require("./utils/ShellUtils"); const uuid_1 = require("uuid"); class Wapiti { constructor() { this.description = { displayName: 'Wapiti Scan', name: 'wapiti', icon: 'file:WapitiLogo.svg', group: ['output'], version: 1, triggerPanel: false, subtitle: '={{$parameter["operation"]}}', description: 'Scan with Wapiti', defaults: { name: 'Wapiti Scan', }, inputs: ["main"], outputs: ["main"], credentials: [ { displayName: 'Cloudflare Access', name: 'cloudflareAccessAPI', required: false, }, ], properties: [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, options: [ { name: 'Quick Scan Wapiti', value: 'quick_scan', description: 'Quick scan a website with wapiti', action: 'Quick scan a website with wapiti', }, { name: 'Full Scan Wapiti', value: 'full_scan', description: 'Full scan a website with wapiti', action: 'Full scan a website with wapiti', }, { name: 'Text Report Wapiti', value: 'report_txt', description: 'Get text report from wapiti', action: 'Get text report from wapiti', }, ], default: 'quick_scan', }, { displayName: 'Target Website', name: 'website', type: 'string', required: true, default: '', placeholder: 'https://www.zubial.net', description: 'Define the target website', }, { displayName: 'Options', name: 'options', type: 'collection', placeholder: 'Add option', default: {}, options: [ { displayName: 'Depth', name: 'depth', type: 'number', default: 3, description: 'Maximum link depth to crawl from the starting URL', }, { displayName: 'Modules', name: 'modules', type: 'string', default: 'backup,blindsql,brute_login_form,buster,cookieflags,crlf,csp,csrf,exec,file,htaccess,http_headers,methods,nikto,permanentxss,redirect,shellshock,sql,ssrf,wapp,xss,xxe', description: 'The list of modules', }, { displayName: 'Put Result in Field', name: 'result_field', type: 'string', default: 'wapiti', description: 'The name of the output field to put the data in', }, { displayName: 'Scope', name: 'scope', type: 'options', options: [ { name: 'Domain', value: 'domain', description: 'Domain scope', }, { name: 'Folder', value: 'folder', description: 'Folder scope', }, { name: 'Page', value: 'page', description: 'Page scope', }, { name: 'Punk', value: 'punk', description: 'Punk scope', }, { name: 'URL', value: 'url', description: 'URL scope', }, ], default: 'domain', description: 'The scan scope', }, { displayName: 'SOCKS Proxy', name: 'socks_proxy', type: 'string', default: '127.0.0.1:9050', placeholder: '127.0.0.1:9050', description: 'Route traffic through a SOCKS proxy (e.g. Tor at 127.0.0.1:9050)', }, { displayName: 'Use Cloudflare Access', name: 'use_cf_access', type: 'boolean', default: false, description: 'Enable Cloudflare Access headers using the selected credential', }, ], }, ], }; } async execute() { var _a; const items = this.getInputData(); let item; const returnItems = []; for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { item = { ...items[itemIndex] }; const newItem = { json: item.json, pairedItem: { item: itemIndex, }, }; const operation = this.getNodeParameter('operation', itemIndex); const website = this.getNodeParameter('website', itemIndex); const options = this.getNodeParameter('options', itemIndex); const scope = options.scope || 'domain'; const depth = options.depth || 3; const modules = options.modules || 'backup,blindsql,brute_login_form,buster,cookieflags,crlf,csp,csrf,exec,file,htaccess,http_headers,methods,nikto,permanentxss,redirect,shellshock,sql,ssrf,wapp,xss,xxe'; const socks_proxy = options.socks_proxy || ''; const use_cf_access = (_a = options.use_cf_access) !== null && _a !== void 0 ? _a : false; const result_field = options.result_field || 'wapiti'; const shellUtils = new ShellUtils_1.ShellUtils(); let outputFile; let command = `wapiti -help`; if (operation === 'quick_scan') { outputFile = await shellUtils.resolveHomeFolder(`~/${(0, uuid_1.v4)()}_wapiti.json`); command = `wapiti -u ${website} --scope ${scope} -f json -o ${outputFile} --flush-session`; } else if (operation === 'full_scan') { outputFile = await shellUtils.resolveHomeFolder(`~/${(0, uuid_1.v4)()}_wapiti.json`); command = `wapiti -u ${website} --scope ${scope} -m "${modules}" -f json -o ${outputFile} --flush-session`; } else if (operation === 'report_txt') { outputFile = await shellUtils.resolveHomeFolder(`~/${(0, uuid_1.v4)()}_wapiti.txt`); command = `wapiti -u ${website} --scope ${scope} -m "${modules}" -f txt -o ${outputFile} --flush-session`; } if (depth) { command += ` -d ${depth}`; } let cfAccess = null; if (use_cf_access) { try { cfAccess = (await this.getCredentials('cloudflareAccessAPI')); if ((cfAccess === null || cfAccess === void 0 ? void 0 : cfAccess.clientId) && (cfAccess === null || cfAccess === void 0 ? void 0 : cfAccess.clientSecret)) { command += ` -H "CF-Access-Client-Id: ${cfAccess.clientId}" -H "CF-Access-Client-Secret: ${cfAccess.clientSecret}"`; } } catch (e) { cfAccess = null; } } if (socks_proxy && socks_proxy !== '') { command += ` --proxy socks://${socks_proxy}`; } const workingDirectory = await shellUtils.resolveHomeFolder('~/'); await shellUtils .command(command, workingDirectory) .then((output) => { console.log(`Wapiti Scan done ${command}`); }) .catch((e) => { throw new n8n_workflow_1.NodeOperationError(this.getNode(), e); }); let readOutputCommand = `cat ${outputFile} 2>/dev/null || echo ""`; await shellUtils .command(readOutputCommand, workingDirectory) .then((output) => { if (operation === 'quick_scan' || operation === 'full_scan') { newItem.json[result_field] = (0, n8n_workflow_1.jsonParse)(output); returnItems.push(newItem); } else if (operation === 'report_txt') { newItem.json[result_field] = output; returnItems.push(newItem); } }) .catch((e) => { throw new n8n_workflow_1.NodeOperationError(this.getNode(), e); }); } return [returnItems]; } } exports.Wapiti = Wapiti; //# sourceMappingURL=Wapiti.node.js.map