n8n-nodes-wapiti
Version:
Wapiti Scan
235 lines • 10.6 kB
JavaScript
;
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