From 16726b1f48b5d0a2e412fae9716c101956ee0f1a Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Wed, 31 Jul 2024 10:07:35 +0000 Subject: [PATCH 01/43] Made base format for new boefje --- boefjes/boefjes/plugins/kat_nikto/__init__.py | 0 .../plugins/kat_nikto/boefje.Dockerfile | 15 +++++++++++ boefjes/boefjes/plugins/kat_nikto/boefje.json | 13 ++++++++++ boefjes/boefjes/plugins/kat_nikto/cover.jpg | Bin 0 -> 62267 bytes .../boefjes/plugins/kat_nikto/description.md | 23 +++++++++++++++++ boefjes/boefjes/plugins/kat_nikto/main.py | 24 ++++++++++++++++++ boefjes/boefjes/plugins/kat_nikto/schema.json | 6 +++++ 7 files changed, 81 insertions(+) create mode 100644 boefjes/boefjes/plugins/kat_nikto/__init__.py create mode 100644 boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile create mode 100644 boefjes/boefjes/plugins/kat_nikto/boefje.json create mode 100644 boefjes/boefjes/plugins/kat_nikto/cover.jpg create mode 100644 boefjes/boefjes/plugins/kat_nikto/description.md create mode 100644 boefjes/boefjes/plugins/kat_nikto/main.py create mode 100644 boefjes/boefjes/plugins/kat_nikto/schema.json diff --git a/boefjes/boefjes/plugins/kat_nikto/__init__.py b/boefjes/boefjes/plugins/kat_nikto/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile new file mode 100644 index 00000000000..0af140a1d0d --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.11-slim + +WORKDIR /app +RUN apt-get update && pip install httpx + +ARG BOEFJE_PATH=./boefjes/plugins/kat_nmap_tcp +ENV PYTHONPATH=/app:$BOEFJE_PATH + +COPY ./images/oci_adapter.py ./ +COPY $BOEFJE_PATH $BOEFJE_PATH + +RUN git clone https://github.com/sullo/nikto +RUN ./nikto/program/nikto.pl -h 46.23.85.171 -o ./output.json + +ENTRYPOINT ["/usr/local/bin/python", "-m", "oci_adapter"] diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.json b/boefjes/boefjes/plugins/kat_nikto/boefje.json new file mode 100644 index 00000000000..12223e76d5c --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.json @@ -0,0 +1,13 @@ +{ + "id": "nikto", + "name": "Nikto", + "description": "Uses Nikto", + "consumes": [ + "IPAddressV4", + "IPAddressV6" + ], + "environment_keys": [], + "scan_level": 3, + "oci_image": "openkat/nikto", + "oci_arguments": [] +} diff --git a/boefjes/boefjes/plugins/kat_nikto/cover.jpg b/boefjes/boefjes/plugins/kat_nikto/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d509564388d68d3189bab55cc28aa5073cc53248 GIT binary patch literal 62267 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 Date: Wed, 7 Aug 2024 04:48:43 +0000 Subject: [PATCH 02/43] Fixed issue of nikto boefje not contacting boefje api --- boefjes/Makefile | 2 +- .../boefjes/plugins/kat_nikto/.dockerignore | 4 + .../plugins/kat_nikto/boefje.Dockerfile | 19 +-- boefjes/boefjes/plugins/kat_nikto/index.js | 118 ++++++++++++++ boefjes/boefjes/plugins/kat_nikto/main.py | 24 --- .../plugins/kat_nikto/package-lock.json | 144 ++++++++++++++++++ .../boefjes/plugins/kat_nikto/package.json | 15 ++ 7 files changed, 292 insertions(+), 34 deletions(-) create mode 100644 boefjes/boefjes/plugins/kat_nikto/.dockerignore create mode 100644 boefjes/boefjes/plugins/kat_nikto/index.js delete mode 100644 boefjes/boefjes/plugins/kat_nikto/main.py create mode 100644 boefjes/boefjes/plugins/kat_nikto/package-lock.json create mode 100644 boefjes/boefjes/plugins/kat_nikto/package.json diff --git a/boefjes/Makefile b/boefjes/Makefile index 579543e3926..afe84575b67 100644 --- a/boefjes/Makefile +++ b/boefjes/Makefile @@ -40,7 +40,7 @@ images: # Build the images for the containerized boefjes # docker build -f images/base.Dockerfile -t ghcr.io/minvws/openkat/dns-records --build-arg BOEFJE_PATH=./boefjes/plugins/kat_dns . docker build -f ./boefjes/plugins/kat_dnssec/boefje.Dockerfile -t ghcr.io/minvws/openkat/dns-sec:latest . docker build -f ./boefjes/plugins/kat_nmap_tcp/boefje.Dockerfile -t ghcr.io/minvws/openkat/nmap:latest . - + docker build -f ./boefjes/plugins/kat_nikto/boefje.Dockerfile -t openkat/nikto . ## ##|------------------------------------------------------------------------| diff --git a/boefjes/boefjes/plugins/kat_nikto/.dockerignore b/boefjes/boefjes/plugins/kat_nikto/.dockerignore new file mode 100644 index 00000000000..476b7d85f6a --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/.dockerignore @@ -0,0 +1,4 @@ +.git +*Dockerfile* +*docker-compose* +node_modules diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile index 0af140a1d0d..ed9308c735e 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile @@ -1,15 +1,16 @@ -FROM python:3.11-slim +FROM node:19-bullseye WORKDIR /app -RUN apt-get update && pip install httpx +RUN apt update +RUN apt install -y git -ARG BOEFJE_PATH=./boefjes/plugins/kat_nmap_tcp -ENV PYTHONPATH=/app:$BOEFJE_PATH - -COPY ./images/oci_adapter.py ./ -COPY $BOEFJE_PATH $BOEFJE_PATH RUN git clone https://github.com/sullo/nikto -RUN ./nikto/program/nikto.pl -h 46.23.85.171 -o ./output.json -ENTRYPOINT ["/usr/local/bin/python", "-m", "oci_adapter"] +ARG BOEFJE_PATH=./boefjes/plugins/kat_nikto +COPY $BOEFJE_PATH ./ + +RUN npm ci + +ENTRYPOINT [ "node", "./" ] +# node ./ "http://localhost:8006/api/v0/tasks/ff208697-c332-4b04-919d-755b014e881d" diff --git a/boefjes/boefjes/plugins/kat_nikto/index.js b/boefjes/boefjes/plugins/kat_nikto/index.js new file mode 100644 index 00000000000..ba2dbcee8a3 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/index.js @@ -0,0 +1,118 @@ +import fs from "node:fs"; +import fetch from "node-fetch"; // npm install node-fetch +import { execSync } from "node:child_process"; + +// Getting information from INPUT_URL: http://boefje:8000/api/v0/tasks/6f08f386-0dfe-4cd4-a1b4-91e95411c883 +// Found boefje input with ooi: 46.23.85.171 +// - ***** TLS/SSL support not available (see docs for SSL install) ***** +// - Nikto v2.5.0 +// --------------------------------------------------------------------------- +// + Target IP: 46.23.85.171 +// + Target Hostname: 46.23.85.171 +// + Target Port: 80 +// + Start Time: 2024-08-05 09:55:56 (GMT0) +// --------------------------------------------------------------------------- +// + Server: nginx/1.18.0 (Ubuntu) +// + /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/ +// + No CGI Directories found (use '-C all' to force check all possible dirs) +// + nginx/1.18.0 appears to be outdated (current is at least 1.25.3). +// + 8108 requests: 0 error(s) and 2 item(s) reported on remote host +// + End Time: 2024-08-05 09:56:14 (GMT0) (18 seconds) +// --------------------------------------------------------------------------- +// + 1 host(s) tested +// Encoding: [{"host":"46.23.85.171","ip":"46.23.85.171","port":"80","banner":"","vulnerabilities":[{"id": "999103","references": "https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/","method":"GET","url":"/","msg":"The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type."},{"id": "600575","method":"HEAD","url":"/","msg":"nginx/1.18.0 appears to be outdated (current is at least 1.25.3)."}]}] +// FINISHING... +// SENDING OUT WITH: +// {"status":"COMPLETED","files":[{"content":"W3siaG9zdCI6IjQ2LjIzLjg1LjE3MSIsImlwIjoiNDYuMjMuODUuMTcxIiwicG9ydCI6IjgwIiwiYmFubmVyIjoiIiwidnVsbmVyYWJpbGl0aWVzIjpbeyJpZCI6ICI5OTkxMDMiLCJyZWZlcmVuY2VzIjogImh0dHBzOi8vd3d3Lm5ldHNwYXJrZXIuY29tL3dlYi12dWxuZXJhYmlsaXR5LXNjYW5uZXIvdnVsbmVyYWJpbGl0aWVzL21pc3NpbmctY29udGVudC10eXBlLWhlYWRlci8iLCJtZXRob2QiOiJHRVQiLCJ1cmwiOiIvIiwibXNnIjoiVGhlIFgtQ29udGVudC1UeXBlLU9wdGlvbnMgaGVhZGVyIGlzIG5vdCBzZXQuIFRoaXMgY291bGQgYWxsb3cgdGhlIHVzZXIgYWdlbnQgdG8gcmVuZGVyIHRoZSBjb250ZW50IG9mIHRoZSBzaXRlIGluIGEgZGlmZmVyZW50IGZhc2hpb24gdG8gdGhlIE1JTUUgdHlwZS4ifSx7ImlkIjogIjYwMDU3NSIsIm1ldGhvZCI6IkhFQUQiLCJ1cmwiOiIvIiwibXNnIjoibmdpbngvMS4xOC4wIGFwcGVhcnMgdG8gYmUgb3V0ZGF0ZWQgKGN1cnJlbnQgaXMgYXQgbGVhc3QgMS4yNS4zKS4ifV19XQ==","tags":[]}]} +// % Total % Received % Xferd Average Speed Time Time Time Current +// Dload Upload Total Spent Left Speed + +// 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 +// 100 903 100 158 100 745 8777 41388 --:--:-- --:--:-- --:--:-- 53117 +// {"detail":[{"type":"json_invalid","loc":["body",1],"msg":"JSON decode error","input":{},"ctx":{"error":"Expecting property name enclosed in double quotes"}}]} +// FINISHED + +function b64encode(inp) { + console.log(`Encoding: ${inp}`); + return Buffer.from(inp).toString("base64"); +} + +let out; +let output_url; + +async function main() { + const input_url = process.argv[process.argv.length - 1]; + console.log(`Getting information from INPUT_URL: ${input_url}`); + try { + var boefje_input = JSON.parse( + execSync(`curl --request GET --url ${input_url} -s`).toString(), + ); + } catch (error) { + console.error("FIRST FETCH WENT WRONG"); + console.error(error); + return; + } + + output_url = boefje_input.output_url; + const ooi = boefje_input.boefje_meta.arguments.input.address; + console.log(`Found boefje input with ooi: ${ooi}`); + + execSync(`./nikto/program/nikto.pl -h ${ooi} -o ./output.json`, { + stdio: "inherit", + }); + + const file_contents = fs.readFileSync("./output.json").toString(); + return { + status: "COMPLETED", + files: [ + { + content: b64encode(file_contents), + tags: [], + }, + ], + }; +} + +main() + .then((value) => { + out = value; + }) + .catch((reason) => { + out = { + status: "FAILED", + files: [ + { + content: b64encode(reason), + tags: ["error/boefje"], + }, + ], + }; + }) + .finally(async () => { + console.log("FINISHING..."); + if (out == undefined) return; + + try { + console.log("SENDING OUT WITH:"); + console.log(JSON.stringify(out)); + console.log(output_url); + const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data ${JSON.stringify( + out, + ).replaceAll('"', '\\"')}`; + console.log(cmd); + try { + const x = execSync(cmd).toString(); + console.log(x); + console.log("FINISHED"); + } catch (error) { + console.error(error.status); // Might be 127 in your example. + console.error(error.message); // Holds the message you typically want. + console.error(error.stderr); // Holds the stderr output. Use `.toString()`. + console.error(error.stdout); // Holds the stdout output. Use `.toString()`. + } + } catch (error) { + console.error("SECOND FETCH WENT WRONG"); + console.error(error); + return; + } + }); diff --git a/boefjes/boefjes/plugins/kat_nikto/main.py b/boefjes/boefjes/plugins/kat_nikto/main.py deleted file mode 100644 index 971f9fddaf2..00000000000 --- a/boefjes/boefjes/plugins/kat_nikto/main.py +++ /dev/null @@ -1,24 +0,0 @@ -import json -import logging -import os - -from pydantic import BaseModel - - -class Vulnerability(BaseModel): - id: str - method: str - msg: str - - -def run(boefje_meta: dict): - file_path = os.path.join("./", "output.json") - if not os.path.isfile(file_path): - raise Exception("output.json file does not exist. Has the kat_nikto image given an error?") - - with open(file_path) as f: - json_data = json.loads(f.read())[0] - found_vulnerabilities = [Vulnerability.model_validate(x) for x in json_data["vulnerabilities"]] - logging.info(found_vulnerabilities) - - return [(set(), "a")] diff --git a/boefjes/boefjes/plugins/kat_nikto/package-lock.json b/boefjes/boefjes/plugins/kat_nikto/package-lock.json new file mode 100644 index 00000000000..5efc27623a6 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/package-lock.json @@ -0,0 +1,144 @@ +{ + "name": "kat-nikto", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "kat-nikto", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "node-fetch": "^3.3.2" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + } + }, + "dependencies": { + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, + "node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==" + } + } +} diff --git a/boefjes/boefjes/plugins/kat_nikto/package.json b/boefjes/boefjes/plugins/kat_nikto/package.json new file mode 100644 index 00000000000..a922f16073b --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/package.json @@ -0,0 +1,15 @@ +{ + "name": "kat-nikto", + "version": "1.0.0", + "description": "", + "type": "module", + "main": "index.js", + "scripts": { + "run": "node index.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "node-fetch": "^3.3.2" + } +} From 09882a6a1c8902cc4e2c06286ed7861632032050 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Tue, 13 Aug 2024 07:52:16 +0000 Subject: [PATCH 03/43] Added `oci_adapter.js` to better mirror the python's implementation --- boefjes/boefjes/plugins/kat_nikto/boefje.json | 3 +- boefjes/boefjes/plugins/kat_nikto/index.js | 118 --------------- boefjes/boefjes/plugins/kat_nikto/main.js | 43 ++++++ .../boefjes/plugins/kat_nikto/oci_adapter.js | 78 ++++++++++ .../plugins/kat_nikto/package-lock.json | 139 +++--------------- .../boefjes/plugins/kat_nikto/package.json | 11 +- 6 files changed, 145 insertions(+), 247 deletions(-) delete mode 100644 boefjes/boefjes/plugins/kat_nikto/index.js create mode 100644 boefjes/boefjes/plugins/kat_nikto/main.js create mode 100644 boefjes/boefjes/plugins/kat_nikto/oci_adapter.js diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.json b/boefjes/boefjes/plugins/kat_nikto/boefje.json index 12223e76d5c..f10f492bb60 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.json +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.json @@ -4,7 +4,8 @@ "description": "Uses Nikto", "consumes": [ "IPAddressV4", - "IPAddressV6" + "IPAddressV6", + "Hostname" ], "environment_keys": [], "scan_level": 3, diff --git a/boefjes/boefjes/plugins/kat_nikto/index.js b/boefjes/boefjes/plugins/kat_nikto/index.js deleted file mode 100644 index ba2dbcee8a3..00000000000 --- a/boefjes/boefjes/plugins/kat_nikto/index.js +++ /dev/null @@ -1,118 +0,0 @@ -import fs from "node:fs"; -import fetch from "node-fetch"; // npm install node-fetch -import { execSync } from "node:child_process"; - -// Getting information from INPUT_URL: http://boefje:8000/api/v0/tasks/6f08f386-0dfe-4cd4-a1b4-91e95411c883 -// Found boefje input with ooi: 46.23.85.171 -// - ***** TLS/SSL support not available (see docs for SSL install) ***** -// - Nikto v2.5.0 -// --------------------------------------------------------------------------- -// + Target IP: 46.23.85.171 -// + Target Hostname: 46.23.85.171 -// + Target Port: 80 -// + Start Time: 2024-08-05 09:55:56 (GMT0) -// --------------------------------------------------------------------------- -// + Server: nginx/1.18.0 (Ubuntu) -// + /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/ -// + No CGI Directories found (use '-C all' to force check all possible dirs) -// + nginx/1.18.0 appears to be outdated (current is at least 1.25.3). -// + 8108 requests: 0 error(s) and 2 item(s) reported on remote host -// + End Time: 2024-08-05 09:56:14 (GMT0) (18 seconds) -// --------------------------------------------------------------------------- -// + 1 host(s) tested -// Encoding: [{"host":"46.23.85.171","ip":"46.23.85.171","port":"80","banner":"","vulnerabilities":[{"id": "999103","references": "https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/","method":"GET","url":"/","msg":"The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type."},{"id": "600575","method":"HEAD","url":"/","msg":"nginx/1.18.0 appears to be outdated (current is at least 1.25.3)."}]}] -// FINISHING... -// SENDING OUT WITH: -// {"status":"COMPLETED","files":[{"content":"W3siaG9zdCI6IjQ2LjIzLjg1LjE3MSIsImlwIjoiNDYuMjMuODUuMTcxIiwicG9ydCI6IjgwIiwiYmFubmVyIjoiIiwidnVsbmVyYWJpbGl0aWVzIjpbeyJpZCI6ICI5OTkxMDMiLCJyZWZlcmVuY2VzIjogImh0dHBzOi8vd3d3Lm5ldHNwYXJrZXIuY29tL3dlYi12dWxuZXJhYmlsaXR5LXNjYW5uZXIvdnVsbmVyYWJpbGl0aWVzL21pc3NpbmctY29udGVudC10eXBlLWhlYWRlci8iLCJtZXRob2QiOiJHRVQiLCJ1cmwiOiIvIiwibXNnIjoiVGhlIFgtQ29udGVudC1UeXBlLU9wdGlvbnMgaGVhZGVyIGlzIG5vdCBzZXQuIFRoaXMgY291bGQgYWxsb3cgdGhlIHVzZXIgYWdlbnQgdG8gcmVuZGVyIHRoZSBjb250ZW50IG9mIHRoZSBzaXRlIGluIGEgZGlmZmVyZW50IGZhc2hpb24gdG8gdGhlIE1JTUUgdHlwZS4ifSx7ImlkIjogIjYwMDU3NSIsIm1ldGhvZCI6IkhFQUQiLCJ1cmwiOiIvIiwibXNnIjoibmdpbngvMS4xOC4wIGFwcGVhcnMgdG8gYmUgb3V0ZGF0ZWQgKGN1cnJlbnQgaXMgYXQgbGVhc3QgMS4yNS4zKS4ifV19XQ==","tags":[]}]} -// % Total % Received % Xferd Average Speed Time Time Time Current -// Dload Upload Total Spent Left Speed - -// 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 -// 100 903 100 158 100 745 8777 41388 --:--:-- --:--:-- --:--:-- 53117 -// {"detail":[{"type":"json_invalid","loc":["body",1],"msg":"JSON decode error","input":{},"ctx":{"error":"Expecting property name enclosed in double quotes"}}]} -// FINISHED - -function b64encode(inp) { - console.log(`Encoding: ${inp}`); - return Buffer.from(inp).toString("base64"); -} - -let out; -let output_url; - -async function main() { - const input_url = process.argv[process.argv.length - 1]; - console.log(`Getting information from INPUT_URL: ${input_url}`); - try { - var boefje_input = JSON.parse( - execSync(`curl --request GET --url ${input_url} -s`).toString(), - ); - } catch (error) { - console.error("FIRST FETCH WENT WRONG"); - console.error(error); - return; - } - - output_url = boefje_input.output_url; - const ooi = boefje_input.boefje_meta.arguments.input.address; - console.log(`Found boefje input with ooi: ${ooi}`); - - execSync(`./nikto/program/nikto.pl -h ${ooi} -o ./output.json`, { - stdio: "inherit", - }); - - const file_contents = fs.readFileSync("./output.json").toString(); - return { - status: "COMPLETED", - files: [ - { - content: b64encode(file_contents), - tags: [], - }, - ], - }; -} - -main() - .then((value) => { - out = value; - }) - .catch((reason) => { - out = { - status: "FAILED", - files: [ - { - content: b64encode(reason), - tags: ["error/boefje"], - }, - ], - }; - }) - .finally(async () => { - console.log("FINISHING..."); - if (out == undefined) return; - - try { - console.log("SENDING OUT WITH:"); - console.log(JSON.stringify(out)); - console.log(output_url); - const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data ${JSON.stringify( - out, - ).replaceAll('"', '\\"')}`; - console.log(cmd); - try { - const x = execSync(cmd).toString(); - console.log(x); - console.log("FINISHED"); - } catch (error) { - console.error(error.status); // Might be 127 in your example. - console.error(error.message); // Holds the message you typically want. - console.error(error.stderr); // Holds the stderr output. Use `.toString()`. - console.error(error.stdout); // Holds the stdout output. Use `.toString()`. - } - } catch (error) { - console.error("SECOND FETCH WENT WRONG"); - console.error(error); - return; - } - }); diff --git a/boefjes/boefjes/plugins/kat_nikto/main.js b/boefjes/boefjes/plugins/kat_nikto/main.js new file mode 100644 index 00000000000..729d4798914 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/main.js @@ -0,0 +1,43 @@ +import fs from "node:fs"; +import { execSync } from "node:child_process"; + +/** + * @param {{}} boefje_meta The string input to base64 encode + * @returns {(string | string[])[][]} + */ +export default function (boefje_meta) { + // Depending on what OOI triggered this task, the hostname / address will be in a different location + const object_type = boefje_meta.arguments.input.object_type; + let ooi = ""; + if (["IPAddressV4", "IPAddressV6"].includes(object_type)) + ooi = boefje_meta.arguments.input.address; + else if (object_type == "Hostname") ooi = boefje_meta.arguments.input.name; + else throw new Error("Unexpected boefje_meta"); + + console.log(`Found boefje input with ooi: ${ooi}`); + + // Running nikto and outputting to a file + try { + execSync(`./nikto/program/nikto.pl -h ${ooi} -o ./output.json`, { + stdio: "inherit", + }); + } catch (e) { + console.error(e); + throw new Error( + "Something went wrong running the nikto command.\n" + e.message, + ); + } + + // Reading the file created by nikto + try { + var file_contents = fs.readFileSync("./output.json").toString(); + } catch (e) { + console.error(e); + throw new Error( + "Something went wrong reading the file from the nikto command.\n" + + e.message, + ); + } + console.log("File contents: " + file_contents); + return [[[], file_contents]]; +} diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js new file mode 100644 index 00000000000..a578bf88b3e --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -0,0 +1,78 @@ +import { execSync } from "node:child_process"; +import run from "./main.js"; + +/** + * @param {string} inp The string input to base64 encode + */ +function b64encode(inp) { + console.log(`Encoding: ${inp}`); + return Buffer.from(inp).toString("base64"); +} + +let out; +let output_url; + +async function main() { + const input_url = process.argv[process.argv.length - 1]; + + // Getting the boefje input + try { + var boefje_input = JSON.parse( + execSync(`curl --request GET --url ${input_url} -s`).toString(), + ); + } catch (error) { + console.error(`Getting boefje input went wrong with URL: ${input_url}`); + throw new Error(error); + } + + output_url = boefje_input.output_url; + const raws = run(boefje_input.boefje_meta); + console.log("RAWS: " + JSON.stringify(raws)); + return { + status: "COMPLETED", + files: raws.map((x) => { + return { + content: b64encode(x[1]), + tags: x[0], + }; + }), + }; +} + +main() + .then((value) => { + out = value; + }) + .catch((reason) => { + out = { + status: "FAILED", + files: [ + { + content: b64encode("main caught an error: " + reason), + tags: ["error/boefje"], + }, + ], + }; + }) + .finally(async () => { + console.log("Finishing with: " + out); + if (out == undefined) return console.error("Somehow `out` was not set."); + + try { + console.log("SENDING OUT WITH: " + JSON.stringify(out)); + const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data ${JSON.stringify( + out, + ).replaceAll('"', '\\"')}`; + console.log(cmd); + try { + execSync(cmd).toString(); + console.log("FINISHED"); + } catch (error) { + console.error( + "Something went wrong outputting to the boefje api: " + error.message, + ); + } + } catch (error) { + console.error("SECOND FETCH WENT WRONG: " + error); + } + }); diff --git a/boefjes/boefjes/plugins/kat_nikto/package-lock.json b/boefjes/boefjes/plugins/kat_nikto/package-lock.json index 5efc27623a6..daa0ba14207 100644 --- a/boefjes/boefjes/plugins/kat_nikto/package-lock.json +++ b/boefjes/boefjes/plugins/kat_nikto/package-lock.json @@ -7,138 +7,37 @@ "": { "name": "kat-nikto", "version": "1.0.0", - "license": "ISC", "dependencies": { - "node-fetch": "^3.3.2" + "@types/node": "^22.1.0" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "node_modules/@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "undici-types": "~6.13.0" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } + "node_modules/undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" } }, "dependencies": { - "data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" - }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "requires": { - "fetch-blob": "^3.1.2" - } - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" - }, - "node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "undici-types": "~6.13.0" } }, - "web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==" + "undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" } } } diff --git a/boefjes/boefjes/plugins/kat_nikto/package.json b/boefjes/boefjes/plugins/kat_nikto/package.json index a922f16073b..890572426c1 100644 --- a/boefjes/boefjes/plugins/kat_nikto/package.json +++ b/boefjes/boefjes/plugins/kat_nikto/package.json @@ -1,15 +1,10 @@ { "name": "kat-nikto", "version": "1.0.0", - "description": "", "type": "module", - "main": "index.js", - "scripts": { - "run": "node index.js" - }, - "author": "", - "license": "ISC", + "main": "oci_adapter.js", + "author": "cynalytics", "dependencies": { - "node-fetch": "^3.3.2" + "@types/node": "^22.1.0" } } From 022ac4e1a86ab8819fc21dd7b5d311ff91ac2b68 Mon Sep 17 00:00:00 2001 From: noamblitz Date: Mon, 19 Aug 2024 12:24:36 +0200 Subject: [PATCH 04/43] generic cve normalier --- .../plugins/kat_cve_normalizer/__init__.py | 0 .../plugins/kat_cve_normalizer/normalize.py | 20 +++++++++++++++++++ .../kat_cve_normalizer/normalizer.json | 10 ++++++++++ 3 files changed, 30 insertions(+) create mode 100644 boefjes/boefjes/plugins/kat_cve_normalizer/__init__.py create mode 100644 boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py create mode 100644 boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/__init__.py b/boefjes/boefjes/plugins/kat_cve_normalizer/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py b/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py new file mode 100644 index 00000000000..faf2e79a7ef --- /dev/null +++ b/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py @@ -0,0 +1,20 @@ +from collections.abc import Iterable + +from boefjes.job_models import NormalizerOutput +from octopoes.models import Reference +from octopoes.models.ooi.findings import CVEFindingType, Finding + + +def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: + ooi = Reference.from_str(input_ooi["primary_key"]) + cve_id = raw.decode() + + if cve_id: + finding_type = CVEFindingType(id=cve_id) + finding = Finding( + finding_type=finding_type.reference, + ooi=ooi, + description=f"CVE {cve_id} is found on this OOI", + ) + yield finding_type + yield finding diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json b/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json new file mode 100644 index 00000000000..cb777e04a7b --- /dev/null +++ b/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json @@ -0,0 +1,10 @@ +{ + "id": "kat_generic_cve_normalize", + "consumes": [ + "cve/id" + ], + "produces": [ + "Finding", + "CVEFindingType" + ] +} From 7572d1e0a474cbfd8f37f34e767ef7769cf3cde9 Mon Sep 17 00:00:00 2001 From: noamblitz Date: Mon, 19 Aug 2024 12:24:57 +0200 Subject: [PATCH 05/43] switch to generic cve normalizer --- .../plugins/kat_cve_2023_34039/main.py | 9 +-------- .../plugins/kat_cve_2023_34039/normalize.py | 19 ------------------- .../kat_cve_2023_34039/normalizer.json | 10 ---------- 3 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 boefjes/boefjes/plugins/kat_cve_2023_34039/normalize.py delete mode 100644 boefjes/boefjes/plugins/kat_cve_2023_34039/normalizer.json diff --git a/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py b/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py index f6e580e1468..4c4642e79ac 100644 --- a/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py +++ b/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py @@ -51,14 +51,7 @@ def run(boefje_meta: BoefjeMeta) -> list[tuple[set, str | bytes]]: coutput = os.system(" ".join(ssh_command)) # noqa: S605 if coutput not in (0, 32512): # 0 = it worked, 32512 = `exit` does not exists but we did connect continue - return [ - ( - set(), - "\n".join( - (str(coutput), f"{key_file} is allowed access to vRealize Network Insight on {ip}:{port}") - ), - ) - ] + return [({"cve/id"}, "CVE-2023-34039")] except Exception: # noqa: S112 continue diff --git a/boefjes/boefjes/plugins/kat_cve_2023_34039/normalize.py b/boefjes/boefjes/plugins/kat_cve_2023_34039/normalize.py deleted file mode 100644 index b379e8158f1..00000000000 --- a/boefjes/boefjes/plugins/kat_cve_2023_34039/normalize.py +++ /dev/null @@ -1,19 +0,0 @@ -from collections.abc import Iterable - -from boefjes.job_models import NormalizerOutput -from octopoes.models import Reference -from octopoes.models.ooi.findings import CVEFindingType, Finding - - -def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: - ooi = Reference.from_str(input_ooi["primary_key"]) - - if "is allowed access to vRealize Network Insight " in raw.decode(): - finding_type = CVEFindingType(id="CVE-2023-34039") - finding = Finding( - finding_type=finding_type.reference, - ooi=ooi, - description="Service is most likely vulnerable to CVE-2023-34039", - ) - yield finding_type - yield finding diff --git a/boefjes/boefjes/plugins/kat_cve_2023_34039/normalizer.json b/boefjes/boefjes/plugins/kat_cve_2023_34039/normalizer.json deleted file mode 100644 index 4cbb1bddda9..00000000000 --- a/boefjes/boefjes/plugins/kat_cve_2023_34039/normalizer.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "kat_cve_2023_normalize", - "consumes": [ - "boefje/CVE-2023-34039" - ], - "produces": [ - "Finding", - "CVEFindingType" - ] -} From a1765f1c65534f94b912329a409ff080474254ba Mon Sep 17 00:00:00 2001 From: noamblitz Date: Mon, 19 Aug 2024 12:35:20 +0200 Subject: [PATCH 06/43] also output orignal boefje output --- boefjes/boefjes/plugins/kat_cve_2023_34039/main.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py b/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py index 4c4642e79ac..63f37a24ef2 100644 --- a/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py +++ b/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py @@ -51,7 +51,15 @@ def run(boefje_meta: BoefjeMeta) -> list[tuple[set, str | bytes]]: coutput = os.system(" ".join(ssh_command)) # noqa: S605 if coutput not in (0, 32512): # 0 = it worked, 32512 = `exit` does not exists but we did connect continue - return [({"cve/id"}, "CVE-2023-34039")] + return [ + ( + set(), + "\n".join( + (str(coutput), f"{key_file} is allowed access to vRealize Network Insight on {ip}:{port}") + ), + ), + ({"cve/id"}, "CVE-2023-34039"), + ] except Exception: # noqa: S112 continue From 6f84904d1fb2323bbfe3b134a78a680bad0b8e0c Mon Sep 17 00:00:00 2001 From: noamblitz Date: Mon, 19 Aug 2024 13:08:02 +0200 Subject: [PATCH 07/43] update docs on generic cve normalizer --- .../development_tutorial/creating_a_boefje.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md b/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md index 719c885c7de..f55e831a3f8 100644 --- a/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md +++ b/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md @@ -126,6 +126,8 @@ def run(boefje_meta: dict) -> list[tuple[set, bytes | str]]: The most important part is the return value we send back. This is what will be used by our normalizer to create our new OOIs. +For ease of development, we added a generic CVE normalizer. When we just want to create a CVE finding on the input OOI, we can return the CVE ID as a string with `cve/id` as mime-type. + --- The final task of creating a boefje is specifying what DockerFile our boefje should use. We can do this inside the file located in `boefjes/Makefile`. From 0e057bb017f3ad490d6e64b4637d5c75e5abfa61 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Thu, 22 Aug 2024 09:26:33 +0000 Subject: [PATCH 08/43] Cleaned up code --- boefjes/boefjes/plugins/kat_nikto/oci_adapter.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js index a578bf88b3e..d1cd586f164 100644 --- a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -2,7 +2,8 @@ import { execSync } from "node:child_process"; import run from "./main.js"; /** - * @param {string} inp The string input to base64 encode + * @param {string} inp The string input to base64 + * @returns {string} */ function b64encode(inp) { console.log(`Encoding: ${inp}`); @@ -30,12 +31,10 @@ async function main() { console.log("RAWS: " + JSON.stringify(raws)); return { status: "COMPLETED", - files: raws.map((x) => { - return { - content: b64encode(x[1]), - tags: x[0], - }; - }), + files: raws.map((x) => ({ + content: b64encode(x[1]), + tags: x[0], + })), }; } @@ -56,7 +55,7 @@ main() }) .finally(async () => { console.log("Finishing with: " + out); - if (out == undefined) return console.error("Somehow `out` was not set."); + if (out == undefined) return console.error("`out` is undefined."); try { console.log("SENDING OUT WITH: " + JSON.stringify(out)); From 50e85aeb0e69aca1bc5a58fec4c2a47d30c39d1c Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Thu, 22 Aug 2024 11:57:09 +0000 Subject: [PATCH 09/43] Added normalizer to kat_nikto boefje --- .../boefjes/plugins/kat_nikto/normalize.py | 28 +++++++++++++++++++ .../boefjes/plugins/kat_nikto/normalizer.json | 10 +++++++ 2 files changed, 38 insertions(+) create mode 100644 boefjes/boefjes/plugins/kat_nikto/normalize.py create mode 100644 boefjes/boefjes/plugins/kat_nikto/normalizer.json diff --git a/boefjes/boefjes/plugins/kat_nikto/normalize.py b/boefjes/boefjes/plugins/kat_nikto/normalize.py new file mode 100644 index 00000000000..f16c571c895 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/normalize.py @@ -0,0 +1,28 @@ +import json +import logging +from collections.abc import Iterable + +from boefjes.job_models import NormalizerOutput +from octopoes.models import Reference +from octopoes.models.ooi.software import Software, SoftwareInstance + + +def scan_outdated_software(data: dict, ooi_ref): + for scan in data: + for vulnerability in scan["vulnerabilities"]: + # If the scanned vulnerability has to do with outdated software + if vulnerability["id"].startswith("6"): + software_name, found_version = vulnerability["msg"].split()[0].split("/") + + software = Software(name=software_name, version=found_version) + yield software + yield SoftwareInstance(ooi=ooi_ref, software=software.reference) + + +def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: + logging.info(input_ooi) + data = json.loads(raw) + + ooi_ref = Reference.from_str(input_ooi["primary_key"]) + + yield from scan_outdated_software(data, ooi_ref) diff --git a/boefjes/boefjes/plugins/kat_nikto/normalizer.json b/boefjes/boefjes/plugins/kat_nikto/normalizer.json new file mode 100644 index 00000000000..7e9e2f5ae09 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/normalizer.json @@ -0,0 +1,10 @@ +{ + "id": "kat_nikto_normalize", + "consumes": [ + "boefje/nikto" + ], + "produces": [ + "Software", + "SoftwareInstance" + ] +} From 6af750e7eb72fc742054793b0600478afe80f7f9 Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:18:38 +0200 Subject: [PATCH 10/43] Update boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json Co-authored-by: Jan Klopper --- boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json b/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json index cb777e04a7b..e58247fb5f2 100644 --- a/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json +++ b/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json @@ -1,7 +1,7 @@ { "id": "kat_generic_cve_normalize", "consumes": [ - "cve/id" + "openkat/finding" ], "produces": [ "Finding", From 7b62c257e7b408c234c2fbdcc92506de343e3a53 Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:18:46 +0200 Subject: [PATCH 11/43] Update boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json Co-authored-by: Jan Klopper --- boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json b/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json index e58247fb5f2..ec7e54b209c 100644 --- a/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json +++ b/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json @@ -1,5 +1,5 @@ { - "id": "kat_generic_cve_normalize", + "id": "kat_generic_finding_normalize", "consumes": [ "openkat/finding" ], From 45c000f5ff5f34fa3f689be5dd25da0091e28d02 Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:18:53 +0200 Subject: [PATCH 12/43] Update docs/source/developer_documentation/development_tutorial/creating_a_boefje.md Co-authored-by: Jan Klopper --- .../development_tutorial/creating_a_boefje.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md b/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md index f55e831a3f8..23894b9bbd2 100644 --- a/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md +++ b/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md @@ -126,7 +126,7 @@ def run(boefje_meta: dict) -> list[tuple[set, bytes | str]]: The most important part is the return value we send back. This is what will be used by our normalizer to create our new OOIs. -For ease of development, we added a generic CVE normalizer. When we just want to create a CVE finding on the input OOI, we can return the CVE ID as a string with `cve/id` as mime-type. +For ease of development, we added a generic finding normalizer. When we just want to create a CVE or other type of finding on the input OOI, we can return the CVE ID, CWE ID or KAT ID as a string with `openkat/finding` as mime-type. --- From ac6ca62da74d4e4d4a31f2a5bd8978003354e36d Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:18:59 +0200 Subject: [PATCH 13/43] Update boefjes/boefjes/plugins/kat_cve_2023_34039/main.py Co-authored-by: Jan Klopper --- boefjes/boefjes/plugins/kat_cve_2023_34039/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py b/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py index 63f37a24ef2..d5bd7f4795a 100644 --- a/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py +++ b/boefjes/boefjes/plugins/kat_cve_2023_34039/main.py @@ -58,7 +58,7 @@ def run(boefje_meta: BoefjeMeta) -> list[tuple[set, str | bytes]]: (str(coutput), f"{key_file} is allowed access to vRealize Network Insight on {ip}:{port}") ), ), - ({"cve/id"}, "CVE-2023-34039"), + ({"openkat/finding"}, "CVE-2023-34039"), ] except Exception: # noqa: S112 From 5ae981e376888fb40ecbb36f33e38c205908fc78 Mon Sep 17 00:00:00 2001 From: noamblitz Date: Thu, 22 Aug 2024 14:29:02 +0200 Subject: [PATCH 14/43] allow comma seperated list of all findingtypes --- .../plugins/kat_cve_normalizer/normalize.py | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py b/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py index faf2e79a7ef..256fda3a8c0 100644 --- a/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py +++ b/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py @@ -1,20 +1,38 @@ +import re from collections.abc import Iterable from boefjes.job_models import NormalizerOutput from octopoes.models import Reference -from octopoes.models.ooi.findings import CVEFindingType, Finding +from octopoes.models.ooi.findings import CVEFindingType, Finding, KATFindingType, RetireJSFindingType, SnykFindingType def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: ooi = Reference.from_str(input_ooi["primary_key"]) - cve_id = raw.decode() + finding_ids_str = raw.decode() + finding_ids_list = [fid.strip().upper() for fid in finding_ids_str.split(",")] - if cve_id: - finding_type = CVEFindingType(id=cve_id) - finding = Finding( - finding_type=finding_type.reference, - ooi=ooi, - description=f"CVE {cve_id} is found on this OOI", - ) - yield finding_type - yield finding + # Validating CVE format (e.g., CVE-YYYY-NNNNN) + cve_pattern = re.compile(r"CVE-\d{4}-\d{4,7}") + + finding_type_mapping = { + "CVE-": CVEFindingType, + "KAT-": KATFindingType, + "SNYK-": SnykFindingType, + "RETIREJS-": RetireJSFindingType, + } + + for finding_id in finding_ids_list: + if finding_id.startswith("CVE-") and not cve_pattern.match(finding_id): + continue # skip incorrect cves + + for prefix, FindingTypeClass in finding_type_mapping.items(): + if finding_id.startswith(prefix): + finding_type = FindingTypeClass(id=finding_id) + finding = Finding( + finding_type=finding_type.reference, + ooi=ooi, + description=f"{finding_id} is found on this OOI", + ) + yield finding_type + yield finding + break From 09ea726393e4f5ff0b9df364be365ba1b2be46c4 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 23 Aug 2024 09:38:32 +0000 Subject: [PATCH 15/43] Added new OOI that has information about outdated software --- boefjes/boefjes/plugins/kat_nikto/normalize.py | 17 +++++++++++++++-- octopoes/octopoes/models/ooi/software.py | 16 ++++++++++++++++ octopoes/octopoes/models/types.py | 4 ++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/normalize.py b/boefjes/boefjes/plugins/kat_nikto/normalize.py index f16c571c895..49a06eb7d7d 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalize.py +++ b/boefjes/boefjes/plugins/kat_nikto/normalize.py @@ -1,10 +1,11 @@ import json import logging +import re from collections.abc import Iterable from boefjes.job_models import NormalizerOutput from octopoes.models import Reference -from octopoes.models.ooi.software import Software, SoftwareInstance +from octopoes.models.ooi.software import OutdatedSoftwareInstance, Software, SoftwareInstance def scan_outdated_software(data: dict, ooi_ref): @@ -14,9 +15,21 @@ def scan_outdated_software(data: dict, ooi_ref): if vulnerability["id"].startswith("6"): software_name, found_version = vulnerability["msg"].split()[0].split("/") + # REGEX: get the text between "least " and ")" to get the latest version + match = re.search(r"least (.*)\)", vulnerability["msg"]) + if match is None: + logging.error("No version number found on supposedly outdated software") + continue + newest_version = match.group(1) software = Software(name=software_name, version=found_version) + software_instance = SoftwareInstance(ooi=ooi_ref, software=software.reference) yield software - yield SoftwareInstance(ooi=ooi_ref, software=software.reference) + yield software_instance + yield OutdatedSoftwareInstance( + ooi=ooi_ref, + software_instance=software_instance.reference, + newest_version=newest_version, + ) def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: diff --git a/octopoes/octopoes/models/ooi/software.py b/octopoes/octopoes/models/ooi/software.py index 91a7fbddf47..cfc0357e2e7 100644 --- a/octopoes/octopoes/models/ooi/software.py +++ b/octopoes/octopoes/models/ooi/software.py @@ -43,3 +43,19 @@ def format_reference_human_readable(cls, reference: Reference) -> str: ooi_reference = Reference.from_str("|".join(parts[0:-4])) software_reference = Reference.from_str("|".join(parts[-4:])) return f"{software_reference.human_readable} @ {ooi_reference.human_readable}" + + +class OutdatedSoftwareInstance(OOI): + object_type: Literal["OutdatedSoftwareInstance"] = "OutdatedSoftwareInstance" + + _natural_key_attrs = ["ooi", "software", "newest_version"] + + ooi: Reference = ReferenceField(OOI, max_issue_scan_level=0, max_inherit_scan_level=1) + software_instance: Reference = ReferenceField(SoftwareInstance, max_issue_scan_level=1, max_inherit_scan_level=0) + newest_version: str | None = None + + @classmethod + def format_reference_human_readable(cls, reference: Reference) -> str: + return reference.human_readable + + # TODO: create `format_reference_human_readable` to include `newest_version` diff --git a/octopoes/octopoes/models/types.py b/octopoes/octopoes/models/types.py index aa99b0f1399..4137b692eb1 100644 --- a/octopoes/octopoes/models/types.py +++ b/octopoes/octopoes/models/types.py @@ -60,7 +60,7 @@ from octopoes.models.ooi.question import Question from octopoes.models.ooi.reports import Report, ReportData from octopoes.models.ooi.service import IPService, Service, TLSCipher -from octopoes.models.ooi.software import Software, SoftwareInstance +from octopoes.models.ooi.software import OutdatedSoftwareInstance, Software, SoftwareInstance from octopoes.models.ooi.web import ( RESTAPI, URL, @@ -107,7 +107,7 @@ ConcreteNetworkType = Network | IPAddressV4 | IPAddressV6 | AutonomousSystem | IPV4NetBlock | IPV6NetBlock | IPPort NetworkType = ConcreteNetworkType | IPAddress ServiceType = Service | IPService | TLSCipher -SoftwareType = Software | SoftwareInstance +SoftwareType = Software | SoftwareInstance | OutdatedSoftwareInstance WebType = ( Website | URL From 1322be6d1190e2d283de4ff756b6407005869bf6 Mon Sep 17 00:00:00 2001 From: noamblitz Date: Fri, 23 Aug 2024 12:32:03 +0200 Subject: [PATCH 16/43] use direct mapping --- .../plugins/kat_cve_normalizer/normalize.py | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py b/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py index 256fda3a8c0..0cc68c03f71 100644 --- a/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py +++ b/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py @@ -5,34 +5,34 @@ from octopoes.models import Reference from octopoes.models.ooi.findings import CVEFindingType, Finding, KATFindingType, RetireJSFindingType, SnykFindingType +CVE_PATTERN = re.compile(r"CVE-\d{4}-\d{4,7}") + def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: ooi = Reference.from_str(input_ooi["primary_key"]) finding_ids_str = raw.decode() finding_ids_list = [fid.strip().upper() for fid in finding_ids_str.split(",")] - # Validating CVE format (e.g., CVE-YYYY-NNNNN) - cve_pattern = re.compile(r"CVE-\d{4}-\d{4,7}") - finding_type_mapping = { - "CVE-": CVEFindingType, - "KAT-": KATFindingType, - "SNYK-": SnykFindingType, - "RETIREJS-": RetireJSFindingType, + "CVE": CVEFindingType, + "KAT": KATFindingType, + "SNYK": SnykFindingType, + "RETIREJS": RetireJSFindingType, } for finding_id in finding_ids_list: - if finding_id.startswith("CVE-") and not cve_pattern.match(finding_id): - continue # skip incorrect cves - - for prefix, FindingTypeClass in finding_type_mapping.items(): - if finding_id.startswith(prefix): - finding_type = FindingTypeClass(id=finding_id) - finding = Finding( - finding_type=finding_type.reference, - ooi=ooi, - description=f"{finding_id} is found on this OOI", - ) - yield finding_type - yield finding - break + parts = finding_id.split("-") + prefix = parts[0] + + if prefix in finding_type_mapping: + if prefix == "CVE" and not CVE_PATTERN.match(finding_id): + continue # skip incorrect cves + + finding_type = finding_type_mapping[prefix](id=finding_id) + finding = Finding( + finding_type=finding_type.reference, + ooi=ooi, + description=f"{finding_id} is found on this OOI", + ) + yield finding_type + yield finding From d57565a151f9b2c6720b31ec432ac7ad90b10c01 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 23 Aug 2024 11:17:30 +0000 Subject: [PATCH 17/43] Rewrote `oci_adapter.js` to work like `oci_adapter.py` does --- .../boefjes/plugins/kat_nikto/oci_adapter.js | 74 ++++++++----------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js index d1cd586f164..18c7d8fb73f 100644 --- a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -10,10 +10,7 @@ function b64encode(inp) { return Buffer.from(inp).toString("base64"); } -let out; -let output_url; - -async function main() { +function main() { const input_url = process.argv[process.argv.length - 1]; // Getting the boefje input @@ -26,52 +23,41 @@ async function main() { throw new Error(error); } - output_url = boefje_input.output_url; - const raws = run(boefje_input.boefje_meta); - console.log("RAWS: " + JSON.stringify(raws)); - return { - status: "COMPLETED", - files: raws.map((x) => ({ - content: b64encode(x[1]), - tags: x[0], - })), - }; -} - -main() - .then((value) => { - out = value; - }) - .catch((reason) => { + let out = undefined; + let output_url = boefje_input.output_url; + try { + // Getting the raw files + const raws = run(boefje_input.boefje_meta); + out = { + status: "COMPLETED", + files: raws.map((x) => ({ + content: b64encode(x[1]), + tags: x[0], + })), + }; + } catch (error) { out = { status: "FAILED", files: [ { - content: b64encode("main caught an error: " + reason), + content: b64encode("Boefje caught an error: " + error.message), tags: ["error/boefje"], }, ], }; - }) - .finally(async () => { - console.log("Finishing with: " + out); - if (out == undefined) return console.error("`out` is undefined."); + } + + // Example command + /* + curl --request POST \ + --url http://boefje/api/v0/tasks/7342e8dd-b945-4185-aaec-787205b7b664 \ + --header 'Content-Type: application/json' \ + --data '{"status":"COMPLETED","files":[{"content":"BASE_64_ENCODED_CONTENT","tags":[]}]}' + */ + const out_json = JSON.stringify(out); + const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data '${out_json}'`; + + execSync(cmd); +} - try { - console.log("SENDING OUT WITH: " + JSON.stringify(out)); - const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data ${JSON.stringify( - out, - ).replaceAll('"', '\\"')}`; - console.log(cmd); - try { - execSync(cmd).toString(); - console.log("FINISHED"); - } catch (error) { - console.error( - "Something went wrong outputting to the boefje api: " + error.message, - ); - } - } catch (error) { - console.error("SECOND FETCH WENT WRONG: " + error); - } - }); +main(); From 0712f4de1b5dc8426a0ebab9adbad8fb1b78c774 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 23 Aug 2024 11:31:28 +0000 Subject: [PATCH 18/43] Fixed example url --- boefjes/boefjes/plugins/kat_nikto/oci_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js index 18c7d8fb73f..2ab82c478f1 100644 --- a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -50,7 +50,7 @@ function main() { // Example command /* curl --request POST \ - --url http://boefje/api/v0/tasks/7342e8dd-b945-4185-aaec-787205b7b664 \ + --url http://boefje:8000/api/v0/tasks/7342e8dd-b945-4185-aaec-787205b7b664 \ --header 'Content-Type: application/json' \ --data '{"status":"COMPLETED","files":[{"content":"BASE_64_ENCODED_CONTENT","tags":[]}]}' */ From b3a32526800afbecd53ba20f24044a15a302919a Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Wed, 31 Jul 2024 10:07:35 +0000 Subject: [PATCH 19/43] Made base format for new boefje --- boefjes/boefjes/plugins/kat_nikto/__init__.py | 0 .../plugins/kat_nikto/boefje.Dockerfile | 15 +++++++++++ boefjes/boefjes/plugins/kat_nikto/boefje.json | 13 ++++++++++ boefjes/boefjes/plugins/kat_nikto/cover.jpg | Bin 0 -> 62267 bytes .../boefjes/plugins/kat_nikto/description.md | 23 +++++++++++++++++ boefjes/boefjes/plugins/kat_nikto/main.py | 24 ++++++++++++++++++ boefjes/boefjes/plugins/kat_nikto/schema.json | 6 +++++ 7 files changed, 81 insertions(+) create mode 100644 boefjes/boefjes/plugins/kat_nikto/__init__.py create mode 100644 boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile create mode 100644 boefjes/boefjes/plugins/kat_nikto/boefje.json create mode 100644 boefjes/boefjes/plugins/kat_nikto/cover.jpg create mode 100644 boefjes/boefjes/plugins/kat_nikto/description.md create mode 100644 boefjes/boefjes/plugins/kat_nikto/main.py create mode 100644 boefjes/boefjes/plugins/kat_nikto/schema.json diff --git a/boefjes/boefjes/plugins/kat_nikto/__init__.py b/boefjes/boefjes/plugins/kat_nikto/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile new file mode 100644 index 00000000000..0af140a1d0d --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.11-slim + +WORKDIR /app +RUN apt-get update && pip install httpx + +ARG BOEFJE_PATH=./boefjes/plugins/kat_nmap_tcp +ENV PYTHONPATH=/app:$BOEFJE_PATH + +COPY ./images/oci_adapter.py ./ +COPY $BOEFJE_PATH $BOEFJE_PATH + +RUN git clone https://github.com/sullo/nikto +RUN ./nikto/program/nikto.pl -h 46.23.85.171 -o ./output.json + +ENTRYPOINT ["/usr/local/bin/python", "-m", "oci_adapter"] diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.json b/boefjes/boefjes/plugins/kat_nikto/boefje.json new file mode 100644 index 00000000000..12223e76d5c --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.json @@ -0,0 +1,13 @@ +{ + "id": "nikto", + "name": "Nikto", + "description": "Uses Nikto", + "consumes": [ + "IPAddressV4", + "IPAddressV6" + ], + "environment_keys": [], + "scan_level": 3, + "oci_image": "openkat/nikto", + "oci_arguments": [] +} diff --git a/boefjes/boefjes/plugins/kat_nikto/cover.jpg b/boefjes/boefjes/plugins/kat_nikto/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d509564388d68d3189bab55cc28aa5073cc53248 GIT binary patch literal 62267 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 Date: Wed, 7 Aug 2024 04:48:43 +0000 Subject: [PATCH 20/43] Fixed issue of nikto boefje not contacting boefje api --- boefjes/Makefile | 2 +- .../boefjes/plugins/kat_nikto/.dockerignore | 4 + .../plugins/kat_nikto/boefje.Dockerfile | 19 +-- boefjes/boefjes/plugins/kat_nikto/index.js | 118 ++++++++++++++ boefjes/boefjes/plugins/kat_nikto/main.py | 24 --- .../plugins/kat_nikto/package-lock.json | 144 ++++++++++++++++++ .../boefjes/plugins/kat_nikto/package.json | 15 ++ 7 files changed, 292 insertions(+), 34 deletions(-) create mode 100644 boefjes/boefjes/plugins/kat_nikto/.dockerignore create mode 100644 boefjes/boefjes/plugins/kat_nikto/index.js delete mode 100644 boefjes/boefjes/plugins/kat_nikto/main.py create mode 100644 boefjes/boefjes/plugins/kat_nikto/package-lock.json create mode 100644 boefjes/boefjes/plugins/kat_nikto/package.json diff --git a/boefjes/Makefile b/boefjes/Makefile index 09e5fc21b47..e9e3e08906e 100644 --- a/boefjes/Makefile +++ b/boefjes/Makefile @@ -40,7 +40,7 @@ images: # Build the images for the containerized boefjes # docker build -f images/base.Dockerfile -t ghcr.io/minvws/openkat/dns-records --build-arg BOEFJE_PATH=./boefjes/plugins/kat_dns . docker build -f ./boefjes/plugins/kat_dnssec/boefje.Dockerfile -t ghcr.io/minvws/openkat/dns-sec:latest . docker build -f ./boefjes/plugins/kat_nmap_tcp/boefje.Dockerfile -t ghcr.io/minvws/openkat/nmap:latest . - + docker build -f ./boefjes/plugins/kat_nikto/boefje.Dockerfile -t openkat/nikto . ## ##|------------------------------------------------------------------------| diff --git a/boefjes/boefjes/plugins/kat_nikto/.dockerignore b/boefjes/boefjes/plugins/kat_nikto/.dockerignore new file mode 100644 index 00000000000..476b7d85f6a --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/.dockerignore @@ -0,0 +1,4 @@ +.git +*Dockerfile* +*docker-compose* +node_modules diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile index 0af140a1d0d..ed9308c735e 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile @@ -1,15 +1,16 @@ -FROM python:3.11-slim +FROM node:19-bullseye WORKDIR /app -RUN apt-get update && pip install httpx +RUN apt update +RUN apt install -y git -ARG BOEFJE_PATH=./boefjes/plugins/kat_nmap_tcp -ENV PYTHONPATH=/app:$BOEFJE_PATH - -COPY ./images/oci_adapter.py ./ -COPY $BOEFJE_PATH $BOEFJE_PATH RUN git clone https://github.com/sullo/nikto -RUN ./nikto/program/nikto.pl -h 46.23.85.171 -o ./output.json -ENTRYPOINT ["/usr/local/bin/python", "-m", "oci_adapter"] +ARG BOEFJE_PATH=./boefjes/plugins/kat_nikto +COPY $BOEFJE_PATH ./ + +RUN npm ci + +ENTRYPOINT [ "node", "./" ] +# node ./ "http://localhost:8006/api/v0/tasks/ff208697-c332-4b04-919d-755b014e881d" diff --git a/boefjes/boefjes/plugins/kat_nikto/index.js b/boefjes/boefjes/plugins/kat_nikto/index.js new file mode 100644 index 00000000000..ba2dbcee8a3 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/index.js @@ -0,0 +1,118 @@ +import fs from "node:fs"; +import fetch from "node-fetch"; // npm install node-fetch +import { execSync } from "node:child_process"; + +// Getting information from INPUT_URL: http://boefje:8000/api/v0/tasks/6f08f386-0dfe-4cd4-a1b4-91e95411c883 +// Found boefje input with ooi: 46.23.85.171 +// - ***** TLS/SSL support not available (see docs for SSL install) ***** +// - Nikto v2.5.0 +// --------------------------------------------------------------------------- +// + Target IP: 46.23.85.171 +// + Target Hostname: 46.23.85.171 +// + Target Port: 80 +// + Start Time: 2024-08-05 09:55:56 (GMT0) +// --------------------------------------------------------------------------- +// + Server: nginx/1.18.0 (Ubuntu) +// + /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/ +// + No CGI Directories found (use '-C all' to force check all possible dirs) +// + nginx/1.18.0 appears to be outdated (current is at least 1.25.3). +// + 8108 requests: 0 error(s) and 2 item(s) reported on remote host +// + End Time: 2024-08-05 09:56:14 (GMT0) (18 seconds) +// --------------------------------------------------------------------------- +// + 1 host(s) tested +// Encoding: [{"host":"46.23.85.171","ip":"46.23.85.171","port":"80","banner":"","vulnerabilities":[{"id": "999103","references": "https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/","method":"GET","url":"/","msg":"The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type."},{"id": "600575","method":"HEAD","url":"/","msg":"nginx/1.18.0 appears to be outdated (current is at least 1.25.3)."}]}] +// FINISHING... +// SENDING OUT WITH: +// {"status":"COMPLETED","files":[{"content":"W3siaG9zdCI6IjQ2LjIzLjg1LjE3MSIsImlwIjoiNDYuMjMuODUuMTcxIiwicG9ydCI6IjgwIiwiYmFubmVyIjoiIiwidnVsbmVyYWJpbGl0aWVzIjpbeyJpZCI6ICI5OTkxMDMiLCJyZWZlcmVuY2VzIjogImh0dHBzOi8vd3d3Lm5ldHNwYXJrZXIuY29tL3dlYi12dWxuZXJhYmlsaXR5LXNjYW5uZXIvdnVsbmVyYWJpbGl0aWVzL21pc3NpbmctY29udGVudC10eXBlLWhlYWRlci8iLCJtZXRob2QiOiJHRVQiLCJ1cmwiOiIvIiwibXNnIjoiVGhlIFgtQ29udGVudC1UeXBlLU9wdGlvbnMgaGVhZGVyIGlzIG5vdCBzZXQuIFRoaXMgY291bGQgYWxsb3cgdGhlIHVzZXIgYWdlbnQgdG8gcmVuZGVyIHRoZSBjb250ZW50IG9mIHRoZSBzaXRlIGluIGEgZGlmZmVyZW50IGZhc2hpb24gdG8gdGhlIE1JTUUgdHlwZS4ifSx7ImlkIjogIjYwMDU3NSIsIm1ldGhvZCI6IkhFQUQiLCJ1cmwiOiIvIiwibXNnIjoibmdpbngvMS4xOC4wIGFwcGVhcnMgdG8gYmUgb3V0ZGF0ZWQgKGN1cnJlbnQgaXMgYXQgbGVhc3QgMS4yNS4zKS4ifV19XQ==","tags":[]}]} +// % Total % Received % Xferd Average Speed Time Time Time Current +// Dload Upload Total Spent Left Speed + +// 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 +// 100 903 100 158 100 745 8777 41388 --:--:-- --:--:-- --:--:-- 53117 +// {"detail":[{"type":"json_invalid","loc":["body",1],"msg":"JSON decode error","input":{},"ctx":{"error":"Expecting property name enclosed in double quotes"}}]} +// FINISHED + +function b64encode(inp) { + console.log(`Encoding: ${inp}`); + return Buffer.from(inp).toString("base64"); +} + +let out; +let output_url; + +async function main() { + const input_url = process.argv[process.argv.length - 1]; + console.log(`Getting information from INPUT_URL: ${input_url}`); + try { + var boefje_input = JSON.parse( + execSync(`curl --request GET --url ${input_url} -s`).toString(), + ); + } catch (error) { + console.error("FIRST FETCH WENT WRONG"); + console.error(error); + return; + } + + output_url = boefje_input.output_url; + const ooi = boefje_input.boefje_meta.arguments.input.address; + console.log(`Found boefje input with ooi: ${ooi}`); + + execSync(`./nikto/program/nikto.pl -h ${ooi} -o ./output.json`, { + stdio: "inherit", + }); + + const file_contents = fs.readFileSync("./output.json").toString(); + return { + status: "COMPLETED", + files: [ + { + content: b64encode(file_contents), + tags: [], + }, + ], + }; +} + +main() + .then((value) => { + out = value; + }) + .catch((reason) => { + out = { + status: "FAILED", + files: [ + { + content: b64encode(reason), + tags: ["error/boefje"], + }, + ], + }; + }) + .finally(async () => { + console.log("FINISHING..."); + if (out == undefined) return; + + try { + console.log("SENDING OUT WITH:"); + console.log(JSON.stringify(out)); + console.log(output_url); + const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data ${JSON.stringify( + out, + ).replaceAll('"', '\\"')}`; + console.log(cmd); + try { + const x = execSync(cmd).toString(); + console.log(x); + console.log("FINISHED"); + } catch (error) { + console.error(error.status); // Might be 127 in your example. + console.error(error.message); // Holds the message you typically want. + console.error(error.stderr); // Holds the stderr output. Use `.toString()`. + console.error(error.stdout); // Holds the stdout output. Use `.toString()`. + } + } catch (error) { + console.error("SECOND FETCH WENT WRONG"); + console.error(error); + return; + } + }); diff --git a/boefjes/boefjes/plugins/kat_nikto/main.py b/boefjes/boefjes/plugins/kat_nikto/main.py deleted file mode 100644 index 971f9fddaf2..00000000000 --- a/boefjes/boefjes/plugins/kat_nikto/main.py +++ /dev/null @@ -1,24 +0,0 @@ -import json -import logging -import os - -from pydantic import BaseModel - - -class Vulnerability(BaseModel): - id: str - method: str - msg: str - - -def run(boefje_meta: dict): - file_path = os.path.join("./", "output.json") - if not os.path.isfile(file_path): - raise Exception("output.json file does not exist. Has the kat_nikto image given an error?") - - with open(file_path) as f: - json_data = json.loads(f.read())[0] - found_vulnerabilities = [Vulnerability.model_validate(x) for x in json_data["vulnerabilities"]] - logging.info(found_vulnerabilities) - - return [(set(), "a")] diff --git a/boefjes/boefjes/plugins/kat_nikto/package-lock.json b/boefjes/boefjes/plugins/kat_nikto/package-lock.json new file mode 100644 index 00000000000..5efc27623a6 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/package-lock.json @@ -0,0 +1,144 @@ +{ + "name": "kat-nikto", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "kat-nikto", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "node-fetch": "^3.3.2" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + } + }, + "dependencies": { + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, + "node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==" + } + } +} diff --git a/boefjes/boefjes/plugins/kat_nikto/package.json b/boefjes/boefjes/plugins/kat_nikto/package.json new file mode 100644 index 00000000000..a922f16073b --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/package.json @@ -0,0 +1,15 @@ +{ + "name": "kat-nikto", + "version": "1.0.0", + "description": "", + "type": "module", + "main": "index.js", + "scripts": { + "run": "node index.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "node-fetch": "^3.3.2" + } +} From 4d790c75427b45fd72900a4b410a4bb6d19f5ee0 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Tue, 13 Aug 2024 07:52:16 +0000 Subject: [PATCH 21/43] Added `oci_adapter.js` to better mirror the python's implementation --- boefjes/boefjes/plugins/kat_nikto/boefje.json | 3 +- boefjes/boefjes/plugins/kat_nikto/index.js | 118 --------------- boefjes/boefjes/plugins/kat_nikto/main.js | 43 ++++++ .../boefjes/plugins/kat_nikto/oci_adapter.js | 78 ++++++++++ .../plugins/kat_nikto/package-lock.json | 139 +++--------------- .../boefjes/plugins/kat_nikto/package.json | 11 +- 6 files changed, 145 insertions(+), 247 deletions(-) delete mode 100644 boefjes/boefjes/plugins/kat_nikto/index.js create mode 100644 boefjes/boefjes/plugins/kat_nikto/main.js create mode 100644 boefjes/boefjes/plugins/kat_nikto/oci_adapter.js diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.json b/boefjes/boefjes/plugins/kat_nikto/boefje.json index 12223e76d5c..f10f492bb60 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.json +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.json @@ -4,7 +4,8 @@ "description": "Uses Nikto", "consumes": [ "IPAddressV4", - "IPAddressV6" + "IPAddressV6", + "Hostname" ], "environment_keys": [], "scan_level": 3, diff --git a/boefjes/boefjes/plugins/kat_nikto/index.js b/boefjes/boefjes/plugins/kat_nikto/index.js deleted file mode 100644 index ba2dbcee8a3..00000000000 --- a/boefjes/boefjes/plugins/kat_nikto/index.js +++ /dev/null @@ -1,118 +0,0 @@ -import fs from "node:fs"; -import fetch from "node-fetch"; // npm install node-fetch -import { execSync } from "node:child_process"; - -// Getting information from INPUT_URL: http://boefje:8000/api/v0/tasks/6f08f386-0dfe-4cd4-a1b4-91e95411c883 -// Found boefje input with ooi: 46.23.85.171 -// - ***** TLS/SSL support not available (see docs for SSL install) ***** -// - Nikto v2.5.0 -// --------------------------------------------------------------------------- -// + Target IP: 46.23.85.171 -// + Target Hostname: 46.23.85.171 -// + Target Port: 80 -// + Start Time: 2024-08-05 09:55:56 (GMT0) -// --------------------------------------------------------------------------- -// + Server: nginx/1.18.0 (Ubuntu) -// + /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/ -// + No CGI Directories found (use '-C all' to force check all possible dirs) -// + nginx/1.18.0 appears to be outdated (current is at least 1.25.3). -// + 8108 requests: 0 error(s) and 2 item(s) reported on remote host -// + End Time: 2024-08-05 09:56:14 (GMT0) (18 seconds) -// --------------------------------------------------------------------------- -// + 1 host(s) tested -// Encoding: [{"host":"46.23.85.171","ip":"46.23.85.171","port":"80","banner":"","vulnerabilities":[{"id": "999103","references": "https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/","method":"GET","url":"/","msg":"The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type."},{"id": "600575","method":"HEAD","url":"/","msg":"nginx/1.18.0 appears to be outdated (current is at least 1.25.3)."}]}] -// FINISHING... -// SENDING OUT WITH: -// {"status":"COMPLETED","files":[{"content":"W3siaG9zdCI6IjQ2LjIzLjg1LjE3MSIsImlwIjoiNDYuMjMuODUuMTcxIiwicG9ydCI6IjgwIiwiYmFubmVyIjoiIiwidnVsbmVyYWJpbGl0aWVzIjpbeyJpZCI6ICI5OTkxMDMiLCJyZWZlcmVuY2VzIjogImh0dHBzOi8vd3d3Lm5ldHNwYXJrZXIuY29tL3dlYi12dWxuZXJhYmlsaXR5LXNjYW5uZXIvdnVsbmVyYWJpbGl0aWVzL21pc3NpbmctY29udGVudC10eXBlLWhlYWRlci8iLCJtZXRob2QiOiJHRVQiLCJ1cmwiOiIvIiwibXNnIjoiVGhlIFgtQ29udGVudC1UeXBlLU9wdGlvbnMgaGVhZGVyIGlzIG5vdCBzZXQuIFRoaXMgY291bGQgYWxsb3cgdGhlIHVzZXIgYWdlbnQgdG8gcmVuZGVyIHRoZSBjb250ZW50IG9mIHRoZSBzaXRlIGluIGEgZGlmZmVyZW50IGZhc2hpb24gdG8gdGhlIE1JTUUgdHlwZS4ifSx7ImlkIjogIjYwMDU3NSIsIm1ldGhvZCI6IkhFQUQiLCJ1cmwiOiIvIiwibXNnIjoibmdpbngvMS4xOC4wIGFwcGVhcnMgdG8gYmUgb3V0ZGF0ZWQgKGN1cnJlbnQgaXMgYXQgbGVhc3QgMS4yNS4zKS4ifV19XQ==","tags":[]}]} -// % Total % Received % Xferd Average Speed Time Time Time Current -// Dload Upload Total Spent Left Speed - -// 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 -// 100 903 100 158 100 745 8777 41388 --:--:-- --:--:-- --:--:-- 53117 -// {"detail":[{"type":"json_invalid","loc":["body",1],"msg":"JSON decode error","input":{},"ctx":{"error":"Expecting property name enclosed in double quotes"}}]} -// FINISHED - -function b64encode(inp) { - console.log(`Encoding: ${inp}`); - return Buffer.from(inp).toString("base64"); -} - -let out; -let output_url; - -async function main() { - const input_url = process.argv[process.argv.length - 1]; - console.log(`Getting information from INPUT_URL: ${input_url}`); - try { - var boefje_input = JSON.parse( - execSync(`curl --request GET --url ${input_url} -s`).toString(), - ); - } catch (error) { - console.error("FIRST FETCH WENT WRONG"); - console.error(error); - return; - } - - output_url = boefje_input.output_url; - const ooi = boefje_input.boefje_meta.arguments.input.address; - console.log(`Found boefje input with ooi: ${ooi}`); - - execSync(`./nikto/program/nikto.pl -h ${ooi} -o ./output.json`, { - stdio: "inherit", - }); - - const file_contents = fs.readFileSync("./output.json").toString(); - return { - status: "COMPLETED", - files: [ - { - content: b64encode(file_contents), - tags: [], - }, - ], - }; -} - -main() - .then((value) => { - out = value; - }) - .catch((reason) => { - out = { - status: "FAILED", - files: [ - { - content: b64encode(reason), - tags: ["error/boefje"], - }, - ], - }; - }) - .finally(async () => { - console.log("FINISHING..."); - if (out == undefined) return; - - try { - console.log("SENDING OUT WITH:"); - console.log(JSON.stringify(out)); - console.log(output_url); - const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data ${JSON.stringify( - out, - ).replaceAll('"', '\\"')}`; - console.log(cmd); - try { - const x = execSync(cmd).toString(); - console.log(x); - console.log("FINISHED"); - } catch (error) { - console.error(error.status); // Might be 127 in your example. - console.error(error.message); // Holds the message you typically want. - console.error(error.stderr); // Holds the stderr output. Use `.toString()`. - console.error(error.stdout); // Holds the stdout output. Use `.toString()`. - } - } catch (error) { - console.error("SECOND FETCH WENT WRONG"); - console.error(error); - return; - } - }); diff --git a/boefjes/boefjes/plugins/kat_nikto/main.js b/boefjes/boefjes/plugins/kat_nikto/main.js new file mode 100644 index 00000000000..729d4798914 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/main.js @@ -0,0 +1,43 @@ +import fs from "node:fs"; +import { execSync } from "node:child_process"; + +/** + * @param {{}} boefje_meta The string input to base64 encode + * @returns {(string | string[])[][]} + */ +export default function (boefje_meta) { + // Depending on what OOI triggered this task, the hostname / address will be in a different location + const object_type = boefje_meta.arguments.input.object_type; + let ooi = ""; + if (["IPAddressV4", "IPAddressV6"].includes(object_type)) + ooi = boefje_meta.arguments.input.address; + else if (object_type == "Hostname") ooi = boefje_meta.arguments.input.name; + else throw new Error("Unexpected boefje_meta"); + + console.log(`Found boefje input with ooi: ${ooi}`); + + // Running nikto and outputting to a file + try { + execSync(`./nikto/program/nikto.pl -h ${ooi} -o ./output.json`, { + stdio: "inherit", + }); + } catch (e) { + console.error(e); + throw new Error( + "Something went wrong running the nikto command.\n" + e.message, + ); + } + + // Reading the file created by nikto + try { + var file_contents = fs.readFileSync("./output.json").toString(); + } catch (e) { + console.error(e); + throw new Error( + "Something went wrong reading the file from the nikto command.\n" + + e.message, + ); + } + console.log("File contents: " + file_contents); + return [[[], file_contents]]; +} diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js new file mode 100644 index 00000000000..a578bf88b3e --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -0,0 +1,78 @@ +import { execSync } from "node:child_process"; +import run from "./main.js"; + +/** + * @param {string} inp The string input to base64 encode + */ +function b64encode(inp) { + console.log(`Encoding: ${inp}`); + return Buffer.from(inp).toString("base64"); +} + +let out; +let output_url; + +async function main() { + const input_url = process.argv[process.argv.length - 1]; + + // Getting the boefje input + try { + var boefje_input = JSON.parse( + execSync(`curl --request GET --url ${input_url} -s`).toString(), + ); + } catch (error) { + console.error(`Getting boefje input went wrong with URL: ${input_url}`); + throw new Error(error); + } + + output_url = boefje_input.output_url; + const raws = run(boefje_input.boefje_meta); + console.log("RAWS: " + JSON.stringify(raws)); + return { + status: "COMPLETED", + files: raws.map((x) => { + return { + content: b64encode(x[1]), + tags: x[0], + }; + }), + }; +} + +main() + .then((value) => { + out = value; + }) + .catch((reason) => { + out = { + status: "FAILED", + files: [ + { + content: b64encode("main caught an error: " + reason), + tags: ["error/boefje"], + }, + ], + }; + }) + .finally(async () => { + console.log("Finishing with: " + out); + if (out == undefined) return console.error("Somehow `out` was not set."); + + try { + console.log("SENDING OUT WITH: " + JSON.stringify(out)); + const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data ${JSON.stringify( + out, + ).replaceAll('"', '\\"')}`; + console.log(cmd); + try { + execSync(cmd).toString(); + console.log("FINISHED"); + } catch (error) { + console.error( + "Something went wrong outputting to the boefje api: " + error.message, + ); + } + } catch (error) { + console.error("SECOND FETCH WENT WRONG: " + error); + } + }); diff --git a/boefjes/boefjes/plugins/kat_nikto/package-lock.json b/boefjes/boefjes/plugins/kat_nikto/package-lock.json index 5efc27623a6..daa0ba14207 100644 --- a/boefjes/boefjes/plugins/kat_nikto/package-lock.json +++ b/boefjes/boefjes/plugins/kat_nikto/package-lock.json @@ -7,138 +7,37 @@ "": { "name": "kat-nikto", "version": "1.0.0", - "license": "ISC", "dependencies": { - "node-fetch": "^3.3.2" + "@types/node": "^22.1.0" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "node_modules/@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "undici-types": "~6.13.0" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } + "node_modules/undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" } }, "dependencies": { - "data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" - }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "requires": { - "fetch-blob": "^3.1.2" - } - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" - }, - "node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "undici-types": "~6.13.0" } }, - "web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==" + "undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" } } } diff --git a/boefjes/boefjes/plugins/kat_nikto/package.json b/boefjes/boefjes/plugins/kat_nikto/package.json index a922f16073b..890572426c1 100644 --- a/boefjes/boefjes/plugins/kat_nikto/package.json +++ b/boefjes/boefjes/plugins/kat_nikto/package.json @@ -1,15 +1,10 @@ { "name": "kat-nikto", "version": "1.0.0", - "description": "", "type": "module", - "main": "index.js", - "scripts": { - "run": "node index.js" - }, - "author": "", - "license": "ISC", + "main": "oci_adapter.js", + "author": "cynalytics", "dependencies": { - "node-fetch": "^3.3.2" + "@types/node": "^22.1.0" } } From d4f92b7a7919a14933053b952bbfa177fc0f45f5 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Thu, 22 Aug 2024 09:26:33 +0000 Subject: [PATCH 22/43] Cleaned up code --- boefjes/boefjes/plugins/kat_nikto/oci_adapter.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js index a578bf88b3e..d1cd586f164 100644 --- a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -2,7 +2,8 @@ import { execSync } from "node:child_process"; import run from "./main.js"; /** - * @param {string} inp The string input to base64 encode + * @param {string} inp The string input to base64 + * @returns {string} */ function b64encode(inp) { console.log(`Encoding: ${inp}`); @@ -30,12 +31,10 @@ async function main() { console.log("RAWS: " + JSON.stringify(raws)); return { status: "COMPLETED", - files: raws.map((x) => { - return { - content: b64encode(x[1]), - tags: x[0], - }; - }), + files: raws.map((x) => ({ + content: b64encode(x[1]), + tags: x[0], + })), }; } @@ -56,7 +55,7 @@ main() }) .finally(async () => { console.log("Finishing with: " + out); - if (out == undefined) return console.error("Somehow `out` was not set."); + if (out == undefined) return console.error("`out` is undefined."); try { console.log("SENDING OUT WITH: " + JSON.stringify(out)); From 6d39582fae569777c145128c1a40c0faa776aa5c Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Thu, 22 Aug 2024 11:57:09 +0000 Subject: [PATCH 23/43] Added normalizer to kat_nikto boefje --- .../boefjes/plugins/kat_nikto/normalize.py | 28 +++++++++++++++++++ .../boefjes/plugins/kat_nikto/normalizer.json | 10 +++++++ 2 files changed, 38 insertions(+) create mode 100644 boefjes/boefjes/plugins/kat_nikto/normalize.py create mode 100644 boefjes/boefjes/plugins/kat_nikto/normalizer.json diff --git a/boefjes/boefjes/plugins/kat_nikto/normalize.py b/boefjes/boefjes/plugins/kat_nikto/normalize.py new file mode 100644 index 00000000000..f16c571c895 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/normalize.py @@ -0,0 +1,28 @@ +import json +import logging +from collections.abc import Iterable + +from boefjes.job_models import NormalizerOutput +from octopoes.models import Reference +from octopoes.models.ooi.software import Software, SoftwareInstance + + +def scan_outdated_software(data: dict, ooi_ref): + for scan in data: + for vulnerability in scan["vulnerabilities"]: + # If the scanned vulnerability has to do with outdated software + if vulnerability["id"].startswith("6"): + software_name, found_version = vulnerability["msg"].split()[0].split("/") + + software = Software(name=software_name, version=found_version) + yield software + yield SoftwareInstance(ooi=ooi_ref, software=software.reference) + + +def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: + logging.info(input_ooi) + data = json.loads(raw) + + ooi_ref = Reference.from_str(input_ooi["primary_key"]) + + yield from scan_outdated_software(data, ooi_ref) diff --git a/boefjes/boefjes/plugins/kat_nikto/normalizer.json b/boefjes/boefjes/plugins/kat_nikto/normalizer.json new file mode 100644 index 00000000000..7e9e2f5ae09 --- /dev/null +++ b/boefjes/boefjes/plugins/kat_nikto/normalizer.json @@ -0,0 +1,10 @@ +{ + "id": "kat_nikto_normalize", + "consumes": [ + "boefje/nikto" + ], + "produces": [ + "Software", + "SoftwareInstance" + ] +} From 723fd55e0f5a0e298d7c8b7c1a4ceb4570ba8652 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 23 Aug 2024 09:38:32 +0000 Subject: [PATCH 24/43] Added new OOI that has information about outdated software --- boefjes/boefjes/plugins/kat_nikto/normalize.py | 17 +++++++++++++++-- octopoes/octopoes/models/ooi/software.py | 16 ++++++++++++++++ octopoes/octopoes/models/types.py | 4 ++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/normalize.py b/boefjes/boefjes/plugins/kat_nikto/normalize.py index f16c571c895..49a06eb7d7d 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalize.py +++ b/boefjes/boefjes/plugins/kat_nikto/normalize.py @@ -1,10 +1,11 @@ import json import logging +import re from collections.abc import Iterable from boefjes.job_models import NormalizerOutput from octopoes.models import Reference -from octopoes.models.ooi.software import Software, SoftwareInstance +from octopoes.models.ooi.software import OutdatedSoftwareInstance, Software, SoftwareInstance def scan_outdated_software(data: dict, ooi_ref): @@ -14,9 +15,21 @@ def scan_outdated_software(data: dict, ooi_ref): if vulnerability["id"].startswith("6"): software_name, found_version = vulnerability["msg"].split()[0].split("/") + # REGEX: get the text between "least " and ")" to get the latest version + match = re.search(r"least (.*)\)", vulnerability["msg"]) + if match is None: + logging.error("No version number found on supposedly outdated software") + continue + newest_version = match.group(1) software = Software(name=software_name, version=found_version) + software_instance = SoftwareInstance(ooi=ooi_ref, software=software.reference) yield software - yield SoftwareInstance(ooi=ooi_ref, software=software.reference) + yield software_instance + yield OutdatedSoftwareInstance( + ooi=ooi_ref, + software_instance=software_instance.reference, + newest_version=newest_version, + ) def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: diff --git a/octopoes/octopoes/models/ooi/software.py b/octopoes/octopoes/models/ooi/software.py index 91a7fbddf47..cfc0357e2e7 100644 --- a/octopoes/octopoes/models/ooi/software.py +++ b/octopoes/octopoes/models/ooi/software.py @@ -43,3 +43,19 @@ def format_reference_human_readable(cls, reference: Reference) -> str: ooi_reference = Reference.from_str("|".join(parts[0:-4])) software_reference = Reference.from_str("|".join(parts[-4:])) return f"{software_reference.human_readable} @ {ooi_reference.human_readable}" + + +class OutdatedSoftwareInstance(OOI): + object_type: Literal["OutdatedSoftwareInstance"] = "OutdatedSoftwareInstance" + + _natural_key_attrs = ["ooi", "software", "newest_version"] + + ooi: Reference = ReferenceField(OOI, max_issue_scan_level=0, max_inherit_scan_level=1) + software_instance: Reference = ReferenceField(SoftwareInstance, max_issue_scan_level=1, max_inherit_scan_level=0) + newest_version: str | None = None + + @classmethod + def format_reference_human_readable(cls, reference: Reference) -> str: + return reference.human_readable + + # TODO: create `format_reference_human_readable` to include `newest_version` diff --git a/octopoes/octopoes/models/types.py b/octopoes/octopoes/models/types.py index 2bc1acc9af9..91d49d99df4 100644 --- a/octopoes/octopoes/models/types.py +++ b/octopoes/octopoes/models/types.py @@ -62,7 +62,7 @@ from octopoes.models.ooi.reports import Report, ReportData from octopoes.models.ooi.scans import ExternalScan from octopoes.models.ooi.service import IPService, Service, TLSCipher -from octopoes.models.ooi.software import Software, SoftwareInstance +from octopoes.models.ooi.software import OutdatedSoftwareInstance, Software, SoftwareInstance from octopoes.models.ooi.web import ( RESTAPI, URL, @@ -109,7 +109,7 @@ ConcreteNetworkType = Network | IPAddressV4 | IPAddressV6 | AutonomousSystem | IPV4NetBlock | IPV6NetBlock | IPPort NetworkType = ConcreteNetworkType | IPAddress ServiceType = Service | IPService | TLSCipher -SoftwareType = Software | SoftwareInstance +SoftwareType = Software | SoftwareInstance | OutdatedSoftwareInstance WebType = ( Website | URL From 13ca4de73fd4577e40807a2e4c44763808215634 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 23 Aug 2024 11:17:30 +0000 Subject: [PATCH 25/43] Rewrote `oci_adapter.js` to work like `oci_adapter.py` does --- .../boefjes/plugins/kat_nikto/oci_adapter.js | 74 ++++++++----------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js index d1cd586f164..18c7d8fb73f 100644 --- a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -10,10 +10,7 @@ function b64encode(inp) { return Buffer.from(inp).toString("base64"); } -let out; -let output_url; - -async function main() { +function main() { const input_url = process.argv[process.argv.length - 1]; // Getting the boefje input @@ -26,52 +23,41 @@ async function main() { throw new Error(error); } - output_url = boefje_input.output_url; - const raws = run(boefje_input.boefje_meta); - console.log("RAWS: " + JSON.stringify(raws)); - return { - status: "COMPLETED", - files: raws.map((x) => ({ - content: b64encode(x[1]), - tags: x[0], - })), - }; -} - -main() - .then((value) => { - out = value; - }) - .catch((reason) => { + let out = undefined; + let output_url = boefje_input.output_url; + try { + // Getting the raw files + const raws = run(boefje_input.boefje_meta); + out = { + status: "COMPLETED", + files: raws.map((x) => ({ + content: b64encode(x[1]), + tags: x[0], + })), + }; + } catch (error) { out = { status: "FAILED", files: [ { - content: b64encode("main caught an error: " + reason), + content: b64encode("Boefje caught an error: " + error.message), tags: ["error/boefje"], }, ], }; - }) - .finally(async () => { - console.log("Finishing with: " + out); - if (out == undefined) return console.error("`out` is undefined."); + } + + // Example command + /* + curl --request POST \ + --url http://boefje/api/v0/tasks/7342e8dd-b945-4185-aaec-787205b7b664 \ + --header 'Content-Type: application/json' \ + --data '{"status":"COMPLETED","files":[{"content":"BASE_64_ENCODED_CONTENT","tags":[]}]}' + */ + const out_json = JSON.stringify(out); + const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data '${out_json}'`; + + execSync(cmd); +} - try { - console.log("SENDING OUT WITH: " + JSON.stringify(out)); - const cmd = `curl --request POST --url ${output_url} --header "Content-Type: application/json" --data ${JSON.stringify( - out, - ).replaceAll('"', '\\"')}`; - console.log(cmd); - try { - execSync(cmd).toString(); - console.log("FINISHED"); - } catch (error) { - console.error( - "Something went wrong outputting to the boefje api: " + error.message, - ); - } - } catch (error) { - console.error("SECOND FETCH WENT WRONG: " + error); - } - }); +main(); From cb8d13627b0c2cfd210a5bac4a648178a7cf36e7 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 23 Aug 2024 11:31:28 +0000 Subject: [PATCH 26/43] Fixed example url --- boefjes/boefjes/plugins/kat_nikto/oci_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js index 18c7d8fb73f..2ab82c478f1 100644 --- a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -50,7 +50,7 @@ function main() { // Example command /* curl --request POST \ - --url http://boefje/api/v0/tasks/7342e8dd-b945-4185-aaec-787205b7b664 \ + --url http://boefje:8000/api/v0/tasks/7342e8dd-b945-4185-aaec-787205b7b664 \ --header 'Content-Type: application/json' \ --data '{"status":"COMPLETED","files":[{"content":"BASE_64_ENCODED_CONTENT","tags":[]}]}' */ From 2d96eff610f3bae402aeffc32858fc2a8a8ac918 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 23 Aug 2024 13:48:00 +0000 Subject: [PATCH 27/43] cleaned up dockerfiles to remove comments --- boefjes/boefjes/plugins/kat_nikto/.dockerignore | 1 - boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile | 1 - 2 files changed, 2 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/.dockerignore b/boefjes/boefjes/plugins/kat_nikto/.dockerignore index 476b7d85f6a..e0da5c735a0 100644 --- a/boefjes/boefjes/plugins/kat_nikto/.dockerignore +++ b/boefjes/boefjes/plugins/kat_nikto/.dockerignore @@ -1,4 +1,3 @@ .git *Dockerfile* *docker-compose* -node_modules diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile index ed9308c735e..feac3fd7a6b 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile @@ -13,4 +13,3 @@ COPY $BOEFJE_PATH ./ RUN npm ci ENTRYPOINT [ "node", "./" ] -# node ./ "http://localhost:8006/api/v0/tasks/ff208697-c332-4b04-919d-755b014e881d" From b050735d85c9aa0cb933e7385997779b2174c587 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Tue, 27 Aug 2024 10:20:27 +0000 Subject: [PATCH 28/43] Removed new OOI type and sent the nikto message straight to the finding --- .../boefjes/plugins/kat_nikto/normalize.py | 23 +++++++++---------- octopoes/octopoes/models/ooi/software.py | 16 ------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/normalize.py b/boefjes/boefjes/plugins/kat_nikto/normalize.py index 49a06eb7d7d..5bc3eb95420 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalize.py +++ b/boefjes/boefjes/plugins/kat_nikto/normalize.py @@ -1,11 +1,11 @@ import json import logging -import re from collections.abc import Iterable from boefjes.job_models import NormalizerOutput from octopoes.models import Reference -from octopoes.models.ooi.software import OutdatedSoftwareInstance, Software, SoftwareInstance +from octopoes.models.ooi.findings import Finding, KATFindingType +from octopoes.models.ooi.software import Software, SoftwareInstance def scan_outdated_software(data: dict, ooi_ref): @@ -13,22 +13,21 @@ def scan_outdated_software(data: dict, ooi_ref): for vulnerability in scan["vulnerabilities"]: # If the scanned vulnerability has to do with outdated software if vulnerability["id"].startswith("6"): + # Example of `vulnerability["msg"]` + # @SOFTWARE/@RUNNING_VER appears to be outdated (current is at least @CURRENT_VER) software_name, found_version = vulnerability["msg"].split()[0].split("/") - # REGEX: get the text between "least " and ")" to get the latest version - match = re.search(r"least (.*)\)", vulnerability["msg"]) - if match is None: - logging.error("No version number found on supposedly outdated software") - continue - newest_version = match.group(1) software = Software(name=software_name, version=found_version) software_instance = SoftwareInstance(ooi=ooi_ref, software=software.reference) yield software yield software_instance - yield OutdatedSoftwareInstance( - ooi=ooi_ref, - software_instance=software_instance.reference, - newest_version=newest_version, + + finding_type = KATFindingType(id="KAT-VERIFIED-VULNERABILITY") + yield finding_type + yield Finding( + finding_type=finding_type.reference, + ooi=software_instance.reference, + description=vulnerability["msg"], ) diff --git a/octopoes/octopoes/models/ooi/software.py b/octopoes/octopoes/models/ooi/software.py index cfc0357e2e7..91a7fbddf47 100644 --- a/octopoes/octopoes/models/ooi/software.py +++ b/octopoes/octopoes/models/ooi/software.py @@ -43,19 +43,3 @@ def format_reference_human_readable(cls, reference: Reference) -> str: ooi_reference = Reference.from_str("|".join(parts[0:-4])) software_reference = Reference.from_str("|".join(parts[-4:])) return f"{software_reference.human_readable} @ {ooi_reference.human_readable}" - - -class OutdatedSoftwareInstance(OOI): - object_type: Literal["OutdatedSoftwareInstance"] = "OutdatedSoftwareInstance" - - _natural_key_attrs = ["ooi", "software", "newest_version"] - - ooi: Reference = ReferenceField(OOI, max_issue_scan_level=0, max_inherit_scan_level=1) - software_instance: Reference = ReferenceField(SoftwareInstance, max_issue_scan_level=1, max_inherit_scan_level=0) - newest_version: str | None = None - - @classmethod - def format_reference_human_readable(cls, reference: Reference) -> str: - return reference.human_readable - - # TODO: create `format_reference_human_readable` to include `newest_version` From 9954e6284a74bc4aaff917506011b5ced96dbcbf Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Tue, 27 Aug 2024 11:24:29 +0000 Subject: [PATCH 29/43] Removed unused variable --- octopoes/octopoes/models/types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/octopoes/octopoes/models/types.py b/octopoes/octopoes/models/types.py index 91d49d99df4..2bc1acc9af9 100644 --- a/octopoes/octopoes/models/types.py +++ b/octopoes/octopoes/models/types.py @@ -62,7 +62,7 @@ from octopoes.models.ooi.reports import Report, ReportData from octopoes.models.ooi.scans import ExternalScan from octopoes.models.ooi.service import IPService, Service, TLSCipher -from octopoes.models.ooi.software import OutdatedSoftwareInstance, Software, SoftwareInstance +from octopoes.models.ooi.software import Software, SoftwareInstance from octopoes.models.ooi.web import ( RESTAPI, URL, @@ -109,7 +109,7 @@ ConcreteNetworkType = Network | IPAddressV4 | IPAddressV6 | AutonomousSystem | IPV4NetBlock | IPV6NetBlock | IPPort NetworkType = ConcreteNetworkType | IPAddress ServiceType = Service | IPService | TLSCipher -SoftwareType = Software | SoftwareInstance | OutdatedSoftwareInstance +SoftwareType = Software | SoftwareInstance WebType = ( Website | URL From 0ace647633fffbcf5f763e82d9281202a956c62c Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Tue, 27 Aug 2024 13:22:29 +0000 Subject: [PATCH 30/43] Added new finding type and use this one instead for nikto boefje --- .../kat_finding_types.json | 6 ++++++ boefjes/boefjes/plugins/kat_nikto/main.js | 18 ++++++++++++++++-- boefjes/boefjes/plugins/kat_nikto/normalize.py | 2 +- .../boefjes/plugins/kat_nikto/normalizer.json | 2 +- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json index 31ff5bed15b..35773f19567 100644 --- a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json +++ b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json @@ -486,5 +486,11 @@ "source": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers", "impact": "Nonstandard headers may not be supported by all browsers and may not provide the security that is expected.", "recommendation": "Remove the nonstandard headers from the response." + }, + "KAT-OUTDATED-SOFTWARE": { + "description": "A newer version of existing software has been found.", + "risk": "recommendation", + "impact": "Depending on what software is outdated this can be critical.", + "recommendation": "Inspect the software version, determine if additional measures need to be taken and install updates to reduce the attack surface." } } diff --git a/boefjes/boefjes/plugins/kat_nikto/main.js b/boefjes/boefjes/plugins/kat_nikto/main.js index 729d4798914..f714aaf4acd 100644 --- a/boefjes/boefjes/plugins/kat_nikto/main.js +++ b/boefjes/boefjes/plugins/kat_nikto/main.js @@ -28,16 +28,30 @@ export default function (boefje_meta) { ); } + const raws = []; + // Reading the file created by nikto try { var file_contents = fs.readFileSync("./output.json").toString(); + raws.push([["boefje/nikto-output"], file_contents]); } catch (e) { - console.error(e); + console.error(e.message); throw new Error( "Something went wrong reading the file from the nikto command.\n" + e.message, ); } + + // Looking if outdated software has been found + try { + const data = JSON.parse(file_contents); + for (const vulnerability of data["vulnerabilities"]) + if (vulnerability["id"].startsWith("6")) + raws.push([["openkat/finding"], "KAT-OUTDATED-SOFTWARE"]); + } catch (e) { + console.error(e.message); + } + console.log("File contents: " + file_contents); - return [[[], file_contents]]; + return raws; } diff --git a/boefjes/boefjes/plugins/kat_nikto/normalize.py b/boefjes/boefjes/plugins/kat_nikto/normalize.py index 5bc3eb95420..7e9a3e9f82f 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalize.py +++ b/boefjes/boefjes/plugins/kat_nikto/normalize.py @@ -22,7 +22,7 @@ def scan_outdated_software(data: dict, ooi_ref): yield software yield software_instance - finding_type = KATFindingType(id="KAT-VERIFIED-VULNERABILITY") + finding_type = KATFindingType(id="KAT-OUTDATED-SOFTWARE") yield finding_type yield Finding( finding_type=finding_type.reference, diff --git a/boefjes/boefjes/plugins/kat_nikto/normalizer.json b/boefjes/boefjes/plugins/kat_nikto/normalizer.json index 7e9e2f5ae09..d6e8ca4fe87 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalizer.json +++ b/boefjes/boefjes/plugins/kat_nikto/normalizer.json @@ -1,7 +1,7 @@ { "id": "kat_nikto_normalize", "consumes": [ - "boefje/nikto" + "boefje/nikto-output" ], "produces": [ "Software", From 491247da4d3a0f20d2de0ad14f7dec85cfee2d99 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Wed, 28 Aug 2024 08:30:02 +0000 Subject: [PATCH 31/43] Fixed merging mistake --- .../plugins/kat_cve_normalizer/__init__.py | 0 .../plugins/kat_cve_normalizer/normalize.py | 38 ------------------- .../kat_cve_normalizer/normalizer.json | 10 ----- 3 files changed, 48 deletions(-) delete mode 100644 boefjes/boefjes/plugins/kat_cve_normalizer/__init__.py delete mode 100644 boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py delete mode 100644 boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/__init__.py b/boefjes/boefjes/plugins/kat_cve_normalizer/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py b/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py deleted file mode 100644 index 0cc68c03f71..00000000000 --- a/boefjes/boefjes/plugins/kat_cve_normalizer/normalize.py +++ /dev/null @@ -1,38 +0,0 @@ -import re -from collections.abc import Iterable - -from boefjes.job_models import NormalizerOutput -from octopoes.models import Reference -from octopoes.models.ooi.findings import CVEFindingType, Finding, KATFindingType, RetireJSFindingType, SnykFindingType - -CVE_PATTERN = re.compile(r"CVE-\d{4}-\d{4,7}") - - -def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: - ooi = Reference.from_str(input_ooi["primary_key"]) - finding_ids_str = raw.decode() - finding_ids_list = [fid.strip().upper() for fid in finding_ids_str.split(",")] - - finding_type_mapping = { - "CVE": CVEFindingType, - "KAT": KATFindingType, - "SNYK": SnykFindingType, - "RETIREJS": RetireJSFindingType, - } - - for finding_id in finding_ids_list: - parts = finding_id.split("-") - prefix = parts[0] - - if prefix in finding_type_mapping: - if prefix == "CVE" and not CVE_PATTERN.match(finding_id): - continue # skip incorrect cves - - finding_type = finding_type_mapping[prefix](id=finding_id) - finding = Finding( - finding_type=finding_type.reference, - ooi=ooi, - description=f"{finding_id} is found on this OOI", - ) - yield finding_type - yield finding diff --git a/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json b/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json deleted file mode 100644 index ec7e54b209c..00000000000 --- a/boefjes/boefjes/plugins/kat_cve_normalizer/normalizer.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "kat_generic_finding_normalize", - "consumes": [ - "openkat/finding" - ], - "produces": [ - "Finding", - "CVEFindingType" - ] -} From ef25331df433f2a1d6ddaba5769b5122e1c4d56f Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Wed, 28 Aug 2024 08:45:50 +0000 Subject: [PATCH 32/43] =?UTF-8?q?Updated=20dev's=20cat'=20=F0=9F=98=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- boefjes/boefjes/plugins/kat_nikto/cover.jpg | Bin 62267 -> 49649 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/cover.jpg b/boefjes/boefjes/plugins/kat_nikto/cover.jpg index d509564388d68d3189bab55cc28aa5073cc53248..02d906baa8329b40800bb10685c94e11eee14eb4 100644 GIT binary patch literal 49649 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 Date: Wed, 28 Aug 2024 09:53:49 +0000 Subject: [PATCH 33/43] Added tests for nikto normalizer --- .../tests/examples/raw/nikto-example.com.json | 23 +++++++++++ .../examples/raw/nikto-non-existing.com.json | 16 ++++++++ boefjes/tests/test_nikto_normalizer.py | 41 +++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 boefjes/tests/examples/raw/nikto-example.com.json create mode 100644 boefjes/tests/examples/raw/nikto-non-existing.com.json create mode 100644 boefjes/tests/test_nikto_normalizer.py diff --git a/boefjes/tests/examples/raw/nikto-example.com.json b/boefjes/tests/examples/raw/nikto-example.com.json new file mode 100644 index 00000000000..264320b0cb8 --- /dev/null +++ b/boefjes/tests/examples/raw/nikto-example.com.json @@ -0,0 +1,23 @@ +[ + { + "host": "example.com", + "ip": "178.128.108.228", + "port": "80", + "banner": "", + "vulnerabilities": [ + { + "id": "600575", + "method": "HEAD", + "url": "/", + "msg": "nginx/1.18.0 appears to be outdated (current is at least 1.25.3)." + }, + { + "id": "999103", + "references": "https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/", + "method": "GET", + "url": "/", + "msg": "The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type." + } + ] + } +] diff --git a/boefjes/tests/examples/raw/nikto-non-existing.com.json b/boefjes/tests/examples/raw/nikto-non-existing.com.json new file mode 100644 index 00000000000..ce45231ff33 --- /dev/null +++ b/boefjes/tests/examples/raw/nikto-non-existing.com.json @@ -0,0 +1,16 @@ +[ + { + "host": "non-existing.com", + "ip": "2.1.3.5", + "port": "6667", + "banner": "", + "vulnerabilities": [ + { + "id": "0", + "method": "GET", + "url": "/", + "msg": "Unable to connect to non-existing.com." + } + ] + } +] diff --git a/boefjes/tests/test_nikto_normalizer.py b/boefjes/tests/test_nikto_normalizer.py new file mode 100644 index 00000000000..e2a3fa1ce11 --- /dev/null +++ b/boefjes/tests/test_nikto_normalizer.py @@ -0,0 +1,41 @@ +from unittest import TestCase + +from boefjes.plugins.kat_nikto.normalize import run +from octopoes.models import Reference +from octopoes.models.ooi.findings import KATFindingType +from octopoes.models.ooi.software import Software, SoftwareInstance +from octopoes.models.types import Finding +from tests.loading import get_dummy_data + + +class CVETest(TestCase): + def test_outdated_found(self): + input_ooi = {"primary_key": "Hostname|internet|example.com"} + ooi_ref = Reference.from_str(input_ooi["primary_key"]) + + oois = list(run(input_ooi, get_dummy_data("raw/nikto-example.com.json"))) + + software = Software(name="nginx", version="1.18.0") + finding_type = KATFindingType(id="KAT-OUTDATED-SOFTWARE") + software_instance = SoftwareInstance(ooi=ooi_ref, software=software.reference) + finding = Finding( + finding_type=finding_type.reference, + ooi=software_instance.reference, + description="nginx/1.18.0 appears to be outdated (current is at least 1.25.3).", + ) + + expected = [ + software, + software_instance, + finding_type, + finding, + ] + + self.assertEqual(expected, oois) + + def test_nothing_found(self): + input_ooi = {"primary_key": "Hostname|internet|non-existing.com"} + + oois = list(run(input_ooi, get_dummy_data("raw/nikto-non-existing.com.json"))) + + self.assertEqual([], oois) From c6647da60354fe61d29bc528d6d98989076b9394 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Wed, 28 Aug 2024 10:07:59 +0000 Subject: [PATCH 34/43] Refactored code --- boefjes/boefjes/plugins/kat_nikto/.dockerignore | 3 --- boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile | 1 - boefjes/boefjes/plugins/kat_nikto/description.md | 10 +--------- boefjes/boefjes/plugins/kat_nikto/main.js | 3 --- boefjes/boefjes/plugins/kat_nikto/normalize.py | 4 +--- boefjes/boefjes/plugins/kat_nikto/oci_adapter.js | 3 +-- 6 files changed, 3 insertions(+), 21 deletions(-) delete mode 100644 boefjes/boefjes/plugins/kat_nikto/.dockerignore diff --git a/boefjes/boefjes/plugins/kat_nikto/.dockerignore b/boefjes/boefjes/plugins/kat_nikto/.dockerignore deleted file mode 100644 index e0da5c735a0..00000000000 --- a/boefjes/boefjes/plugins/kat_nikto/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -.git -*Dockerfile* -*docker-compose* diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile index feac3fd7a6b..f852b54f71a 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile @@ -4,7 +4,6 @@ WORKDIR /app RUN apt update RUN apt install -y git - RUN git clone https://github.com/sullo/nikto ARG BOEFJE_PATH=./boefjes/plugins/kat_nikto diff --git a/boefjes/boefjes/plugins/kat_nikto/description.md b/boefjes/boefjes/plugins/kat_nikto/description.md index 30000258ee6..e2e1d3c27e0 100644 --- a/boefjes/boefjes/plugins/kat_nikto/description.md +++ b/boefjes/boefjes/plugins/kat_nikto/description.md @@ -10,14 +10,6 @@ Nikto expects an IpAddress or a Hostname OOI. ### Output OOIs -Nikto outputs the following OOIs: - -| OOI type | Description | -| -------- | ----------- | -| | | -| | | -| | | -| | | -| | | +Nikto outputs the following the found outdated software and a finding explaining that the software is outdated. **Cat name**: Kitty diff --git a/boefjes/boefjes/plugins/kat_nikto/main.js b/boefjes/boefjes/plugins/kat_nikto/main.js index f714aaf4acd..9916ef54246 100644 --- a/boefjes/boefjes/plugins/kat_nikto/main.js +++ b/boefjes/boefjes/plugins/kat_nikto/main.js @@ -14,8 +14,6 @@ export default function (boefje_meta) { else if (object_type == "Hostname") ooi = boefje_meta.arguments.input.name; else throw new Error("Unexpected boefje_meta"); - console.log(`Found boefje input with ooi: ${ooi}`); - // Running nikto and outputting to a file try { execSync(`./nikto/program/nikto.pl -h ${ooi} -o ./output.json`, { @@ -52,6 +50,5 @@ export default function (boefje_meta) { console.error(e.message); } - console.log("File contents: " + file_contents); return raws; } diff --git a/boefjes/boefjes/plugins/kat_nikto/normalize.py b/boefjes/boefjes/plugins/kat_nikto/normalize.py index 7e9a3e9f82f..f5153f026e5 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalize.py +++ b/boefjes/boefjes/plugins/kat_nikto/normalize.py @@ -1,5 +1,4 @@ import json -import logging from collections.abc import Iterable from boefjes.job_models import NormalizerOutput @@ -8,7 +7,7 @@ from octopoes.models.ooi.software import Software, SoftwareInstance -def scan_outdated_software(data: dict, ooi_ref): +def scan_outdated_software(data: dict, ooi_ref: Reference) -> Iterable[NormalizerOutput]: for scan in data: for vulnerability in scan["vulnerabilities"]: # If the scanned vulnerability has to do with outdated software @@ -32,7 +31,6 @@ def scan_outdated_software(data: dict, ooi_ref): def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: - logging.info(input_ooi) data = json.loads(raw) ooi_ref = Reference.from_str(input_ooi["primary_key"]) diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js index 2ab82c478f1..1d98e515055 100644 --- a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -6,7 +6,6 @@ import run from "./main.js"; * @returns {string} */ function b64encode(inp) { - console.log(`Encoding: ${inp}`); return Buffer.from(inp).toString("base64"); } @@ -20,7 +19,7 @@ function main() { ); } catch (error) { console.error(`Getting boefje input went wrong with URL: ${input_url}`); - throw new Error(error); + throw new Error(error.message); } let out = undefined; From 0c169ba1ecae06fe6c3a30ddee6b2dc406f1955e Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 30 Aug 2024 09:03:44 +0000 Subject: [PATCH 35/43] Made nikto boefje run on `HostnameHTTPURL` Nikto boefje now consumes `HostnameHTTPURL` Fixed issue of perl not being able to handle https requests --- .../plugins/kat_nikto/boefje.Dockerfile | 5 ++-- boefjes/boefjes/plugins/kat_nikto/boefje.json | 4 +-- boefjes/boefjes/plugins/kat_nikto/main.js | 27 ++++++++++--------- .../boefjes/plugins/kat_nikto/oci_adapter.js | 4 +-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile index f852b54f71a..ea75a179336 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.Dockerfile @@ -1,14 +1,13 @@ -FROM node:19-bullseye +FROM perl:5.40 WORKDIR /app RUN apt update RUN apt install -y git +RUN apt install -y nodejs RUN git clone https://github.com/sullo/nikto ARG BOEFJE_PATH=./boefjes/plugins/kat_nikto COPY $BOEFJE_PATH ./ -RUN npm ci - ENTRYPOINT [ "node", "./" ] diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.json b/boefjes/boefjes/plugins/kat_nikto/boefje.json index f10f492bb60..406ac61f34a 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.json +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.json @@ -3,9 +3,7 @@ "name": "Nikto", "description": "Uses Nikto", "consumes": [ - "IPAddressV4", - "IPAddressV6", - "Hostname" + "HostnameHTTPURL" ], "environment_keys": [], "scan_level": 3, diff --git a/boefjes/boefjes/plugins/kat_nikto/main.js b/boefjes/boefjes/plugins/kat_nikto/main.js index 9916ef54246..3cf6f397843 100644 --- a/boefjes/boefjes/plugins/kat_nikto/main.js +++ b/boefjes/boefjes/plugins/kat_nikto/main.js @@ -1,29 +1,32 @@ import fs from "node:fs"; import { execSync } from "node:child_process"; - /** - * @param {{}} boefje_meta The string input to base64 encode + * @param {Object} boefje_meta Information about the task + * @param {Object} boefje_meta.arguments + * @param {Object} boefje_meta.arguments.input + * @param {string} boefje_meta.arguments.input.object_type + * @param {"http" | "https"} boefje_meta.arguments.input.scheme + * @param {number} boefje_meta.arguments.input.port + * @param {Object} boefje_meta.arguments.input.netloc + * @param {string} boefje_meta.arguments.input.netloc.name * @returns {(string | string[])[][]} */ export default function (boefje_meta) { // Depending on what OOI triggered this task, the hostname / address will be in a different location - const object_type = boefje_meta.arguments.input.object_type; - let ooi = ""; - if (["IPAddressV4", "IPAddressV6"].includes(object_type)) - ooi = boefje_meta.arguments.input.address; - else if (object_type == "Hostname") ooi = boefje_meta.arguments.input.name; - else throw new Error("Unexpected boefje_meta"); + const hostname = boefje_meta.arguments.input.netloc.name; + const scheme = boefje_meta.arguments.input.scheme; + + let command = `./nikto/program/nikto.pl -h ${hostname} -o ./output.json -404code=301,302,307,308`; + if (scheme == "https") command += " -ssl"; // Running nikto and outputting to a file try { - execSync(`./nikto/program/nikto.pl -h ${ooi} -o ./output.json`, { + execSync(command, { stdio: "inherit", }); } catch (e) { console.error(e); - throw new Error( - "Something went wrong running the nikto command.\n" + e.message, - ); + throw new Error("Something went wrong running the nikto command.\n"); } const raws = []; diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js index 1d98e515055..5b585db510b 100644 --- a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -15,11 +15,11 @@ function main() { // Getting the boefje input try { var boefje_input = JSON.parse( - execSync(`curl --request GET --url ${input_url} -s`).toString(), + execSync(`curl --request GET --url ${input_url}`).toString(), ); } catch (error) { console.error(`Getting boefje input went wrong with URL: ${input_url}`); - throw new Error(error.message); + throw new Error(error); } let out = undefined; From 346e170f3b136e2bc9df664e782ef7bab1058c03 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Wed, 4 Sep 2024 08:52:57 +0000 Subject: [PATCH 36/43] Added env variables to nikto boefje --- boefjes/boefjes/plugins/kat_nikto/boefje.json | 8 +++- boefjes/boefjes/plugins/kat_nikto/main.js | 44 +++++++++++++++---- .../boefjes/plugins/kat_nikto/oci_adapter.js | 2 + boefjes/boefjes/plugins/kat_nikto/schema.json | 28 +++++++++++- 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.json b/boefjes/boefjes/plugins/kat_nikto/boefje.json index 406ac61f34a..e4cd50cf81a 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.json +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.json @@ -5,7 +5,13 @@ "consumes": [ "HostnameHTTPURL" ], - "environment_keys": [], + "environment_keys": [ + "PROXYHOST", + "PROXYPORT", + "PROXYUSER", + "PROXYPASS", + "USERAGENT" + ], "scan_level": 3, "oci_image": "openkat/nikto", "oci_arguments": [] diff --git a/boefjes/boefjes/plugins/kat_nikto/main.js b/boefjes/boefjes/plugins/kat_nikto/main.js index 3cf6f397843..414cf7401e7 100644 --- a/boefjes/boefjes/plugins/kat_nikto/main.js +++ b/boefjes/boefjes/plugins/kat_nikto/main.js @@ -1,5 +1,6 @@ import fs from "node:fs"; import { execSync } from "node:child_process"; + /** * @param {Object} boefje_meta Information about the task * @param {Object} boefje_meta.arguments @@ -15,18 +16,45 @@ export default function (boefje_meta) { // Depending on what OOI triggered this task, the hostname / address will be in a different location const hostname = boefje_meta.arguments.input.netloc.name; const scheme = boefje_meta.arguments.input.scheme; + const IS_USING_PROXY = !!process.env.PROXYHOST; + + // Setup config file + try { + let config_contents = + "PROMPTS=no\nUPDATES=no\nCLIOPTS=-404code=301,302,307,308 -o ./output.json"; + + // CLI OPTIONS + if (scheme == "https") config_contents += " -ssl"; + if (IS_USING_PROXY) config_contents += " -useproxy"; + config_contents += "\n"; + + if (IS_USING_PROXY) { + const PROXY_HOST = process.env.PROXYHOST; + const PROXY_PORT = process.env.PROXYPORT || "8080"; + const PROXY_USER = process.env.PROXYUSER || ""; + const PROXY_PASS = process.env.PROXYPASS || ""; + + config_contents += `PROXYHOST=${PROXY_HOST}\n`; + config_contents += `PROXYPORT=${PROXY_PORT}\n`; + config_contents += `PROXYUSER=${PROXY_USER}\n`; + config_contents += `PROXYPASS=${PROXY_PASS}\n`; + } - let command = `./nikto/program/nikto.pl -h ${hostname} -o ./output.json -404code=301,302,307,308`; - if (scheme == "https") command += " -ssl"; + if (process.env.USERAGENT) + config_contents += `USERAGENT=${process.env.USERAGENT}\n`; + + fs.writeFileSync("./nikto.conf", config_contents); + } catch (e) { + console.error("Something went wrong writing to the config file.\n" + e); + } // Running nikto and outputting to a file try { - execSync(command, { + execSync(`./nikto/program/nikto.pl -h ${hostname} -config ./nikto.conf`, { stdio: "inherit", }); } catch (e) { - console.error(e); - throw new Error("Something went wrong running the nikto command.\n"); + throw new Error("Something went wrong running the nikto command.\n" + e); } const raws = []; @@ -36,10 +64,8 @@ export default function (boefje_meta) { var file_contents = fs.readFileSync("./output.json").toString(); raws.push([["boefje/nikto-output"], file_contents]); } catch (e) { - console.error(e.message); throw new Error( - "Something went wrong reading the file from the nikto command.\n" + - e.message, + "Something went wrong reading the file from the nikto command.\n" + e, ); } @@ -50,7 +76,7 @@ export default function (boefje_meta) { if (vulnerability["id"].startsWith("6")) raws.push([["openkat/finding"], "KAT-OUTDATED-SOFTWARE"]); } catch (e) { - console.error(e.message); + console.error(e); } return raws; diff --git a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js index 5b585db510b..83ae47927f1 100644 --- a/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js +++ b/boefjes/boefjes/plugins/kat_nikto/oci_adapter.js @@ -22,6 +22,8 @@ function main() { throw new Error(error); } + Object.assign(process.env, boefje_input["boefje_meta"]["environment"]); + let out = undefined; let output_url = boefje_input.output_url; try { diff --git a/boefjes/boefjes/plugins/kat_nikto/schema.json b/boefjes/boefjes/plugins/kat_nikto/schema.json index defe43d5eb9..9286d2e6ac5 100644 --- a/boefjes/boefjes/plugins/kat_nikto/schema.json +++ b/boefjes/boefjes/plugins/kat_nikto/schema.json @@ -1,6 +1,32 @@ { "title": "Arguments", "type": "object", - "properties": {}, + "properties": { + "PROXYHOST": { + "title": "PROXYHOST", + "maxLength": 256, + "type": "string" + }, + "PROXYPORT": { + "title": "PROXYPORT", + "maxLength": 256, + "type": "string" + }, + "PROXYUSER": { + "title": "PROXYUSER", + "maxLength": 256, + "type": "string" + }, + "PROXYPASS": { + "title": "PROXYPASS", + "maxLength": 256, + "type": "string" + }, + "USERAGENT": { + "title": "USERAGENT", + "maxLength": 256, + "type": "string" + } + }, "required": [] } From 8d5cba0fd39283aa7cc4175d21453d10a69c1b9c Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Wed, 4 Sep 2024 10:58:09 +0000 Subject: [PATCH 37/43] Moved config file creation to a seperate function --- boefjes/boefjes/plugins/kat_nikto/main.js | 49 +++++++++++++++-------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/main.js b/boefjes/boefjes/plugins/kat_nikto/main.js index 414cf7401e7..e9bf0da4484 100644 --- a/boefjes/boefjes/plugins/kat_nikto/main.js +++ b/boefjes/boefjes/plugins/kat_nikto/main.js @@ -2,20 +2,10 @@ import fs from "node:fs"; import { execSync } from "node:child_process"; /** - * @param {Object} boefje_meta Information about the task - * @param {Object} boefje_meta.arguments - * @param {Object} boefje_meta.arguments.input - * @param {string} boefje_meta.arguments.input.object_type - * @param {"http" | "https"} boefje_meta.arguments.input.scheme - * @param {number} boefje_meta.arguments.input.port - * @param {Object} boefje_meta.arguments.input.netloc - * @param {string} boefje_meta.arguments.input.netloc.name - * @returns {(string | string[])[][]} + * @param {string} scheme + * @returns {string} */ -export default function (boefje_meta) { - // Depending on what OOI triggered this task, the hostname / address will be in a different location - const hostname = boefje_meta.arguments.input.netloc.name; - const scheme = boefje_meta.arguments.input.scheme; +function get_config_content(scheme) { const IS_USING_PROXY = !!process.env.PROXYHOST; // Setup config file @@ -23,7 +13,6 @@ export default function (boefje_meta) { let config_contents = "PROMPTS=no\nUPDATES=no\nCLIOPTS=-404code=301,302,307,308 -o ./output.json"; - // CLI OPTIONS if (scheme == "https") config_contents += " -ssl"; if (IS_USING_PROXY) config_contents += " -useproxy"; config_contents += "\n"; @@ -43,10 +32,31 @@ export default function (boefje_meta) { if (process.env.USERAGENT) config_contents += `USERAGENT=${process.env.USERAGENT}\n`; - fs.writeFileSync("./nikto.conf", config_contents); + return config_contents; } catch (e) { - console.error("Something went wrong writing to the config file.\n" + e); + throw new Error("Something went wrong writing to the config file.\n" + e); } +} + +/** + * @param {Object} boefje_meta Information about the task + * @param {Object} boefje_meta.arguments + * @param {Object} boefje_meta.arguments.input + * @param {string} boefje_meta.arguments.input.object_type + * @param {"http" | "https"} boefje_meta.arguments.input.scheme + * @param {number} boefje_meta.arguments.input.port + * @param {Object} boefje_meta.arguments.input.netloc + * @param {string} boefje_meta.arguments.input.netloc.name + * @returns {(string | string[])[][]} + */ +export default function (boefje_meta) { + // Depending on what OOI triggered this task, the hostname / address will be in a different location + const hostname = boefje_meta.arguments.input.netloc.name; + + const config_contents = get_config_content( + boefje_meta.arguments.input.scheme, + ); + fs.writeFileSync("./nikto.conf", config_contents); // Running nikto and outputting to a file try { @@ -54,7 +64,12 @@ export default function (boefje_meta) { stdio: "inherit", }); } catch (e) { - throw new Error("Something went wrong running the nikto command.\n" + e); + throw new Error( + "Something went wrong running the nikto command.\n" + + e + + "\n" + + config_contents, + ); } const raws = []; From e6cf37020fc8d4971827afb526ce6dfd9190610f Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 4 Oct 2024 11:32:33 +0000 Subject: [PATCH 38/43] Boefje uses env variable `HTTP_PROXY` instead of split version as suggested in https://github.com/minvws/nl-kat-coordination/pull/3409#discussion_r1780106683 --- boefjes/boefjes/plugins/kat_nikto/boefje.json | 5 +--- boefjes/boefjes/plugins/kat_nikto/main.js | 11 +++++---- boefjes/boefjes/plugins/kat_nikto/schema.json | 24 ++++--------------- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/boefje.json b/boefjes/boefjes/plugins/kat_nikto/boefje.json index e4cd50cf81a..6cd39ab1765 100644 --- a/boefjes/boefjes/plugins/kat_nikto/boefje.json +++ b/boefjes/boefjes/plugins/kat_nikto/boefje.json @@ -6,10 +6,7 @@ "HostnameHTTPURL" ], "environment_keys": [ - "PROXYHOST", - "PROXYPORT", - "PROXYUSER", - "PROXYPASS", + "HTTP_PROXY", "USERAGENT" ], "scan_level": 3, diff --git a/boefjes/boefjes/plugins/kat_nikto/main.js b/boefjes/boefjes/plugins/kat_nikto/main.js index e9bf0da4484..111764a2257 100644 --- a/boefjes/boefjes/plugins/kat_nikto/main.js +++ b/boefjes/boefjes/plugins/kat_nikto/main.js @@ -6,7 +6,7 @@ import { execSync } from "node:child_process"; * @returns {string} */ function get_config_content(scheme) { - const IS_USING_PROXY = !!process.env.PROXYHOST; + const IS_USING_PROXY = !!process.env.HTTP_PROXY; // Setup config file try { @@ -18,10 +18,11 @@ function get_config_content(scheme) { config_contents += "\n"; if (IS_USING_PROXY) { - const PROXY_HOST = process.env.PROXYHOST; - const PROXY_PORT = process.env.PROXYPORT || "8080"; - const PROXY_USER = process.env.PROXYUSER || ""; - const PROXY_PASS = process.env.PROXYPASS || ""; + const PROXY = new URL(process.env.HTTP_PROXY); + const PROXY_HOST = PROXY.hostname; + const PROXY_PORT = PROXY.port || "8080"; + const PROXY_USER = PROXY.username || ""; + const PROXY_PASS = PROXY.password || ""; config_contents += `PROXYHOST=${PROXY_HOST}\n`; config_contents += `PROXYPORT=${PROXY_PORT}\n`; diff --git a/boefjes/boefjes/plugins/kat_nikto/schema.json b/boefjes/boefjes/plugins/kat_nikto/schema.json index 9286d2e6ac5..f5b3b917eee 100644 --- a/boefjes/boefjes/plugins/kat_nikto/schema.json +++ b/boefjes/boefjes/plugins/kat_nikto/schema.json @@ -2,25 +2,11 @@ "title": "Arguments", "type": "object", "properties": { - "PROXYHOST": { - "title": "PROXYHOST", - "maxLength": 256, - "type": "string" - }, - "PROXYPORT": { - "title": "PROXYPORT", - "maxLength": 256, - "type": "string" - }, - "PROXYUSER": { - "title": "PROXYUSER", - "maxLength": 256, - "type": "string" - }, - "PROXYPASS": { - "title": "PROXYPASS", - "maxLength": 256, - "type": "string" + "HTTP_PROXY": { + "title": "HTTP_PROXY", + "maxLength": 512, + "type": "string", + "description": "The full URL for the proxy.\nE.g. \"http://user:pass@127.0.0.1:8080/\"" }, "USERAGENT": { "title": "USERAGENT", From 0f65563404a08e4562e5c3aecf12c4a91eaa8cab Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 4 Oct 2024 13:24:51 +0000 Subject: [PATCH 39/43] Added name to normalizer --- boefjes/boefjes/plugins/kat_nikto/normalizer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/boefjes/boefjes/plugins/kat_nikto/normalizer.json b/boefjes/boefjes/plugins/kat_nikto/normalizer.json index d6e8ca4fe87..20d00245b13 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalizer.json +++ b/boefjes/boefjes/plugins/kat_nikto/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_nikto_normalize", + "name": "Nikto", "consumes": [ "boefje/nikto-output" ], From eb2e35cf399a7d6dd72d742cd5ad83d53a2c01bf Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Wed, 11 Dec 2024 16:39:01 +0100 Subject: [PATCH 40/43] Nikto now also warns about missing headers --- .../boefjes/plugins/kat_nikto/normalize.py | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/normalize.py b/boefjes/boefjes/plugins/kat_nikto/normalize.py index f5153f026e5..be76ab9d09e 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalize.py +++ b/boefjes/boefjes/plugins/kat_nikto/normalize.py @@ -1,17 +1,28 @@ import json from collections.abc import Iterable +from typing import Any from boefjes.job_models import NormalizerOutput from octopoes.models import Reference from octopoes.models.ooi.findings import Finding, KATFindingType from octopoes.models.ooi.software import Software, SoftwareInstance +MISSING_HEADER_TO_KAT_FINDING_TYPE = { + "strict-transport-security": "KAT-HSTS-VULNERABILITIES", + "x-content-type-options": "KAT-NO-X-CONTENT-TYPE-OPTIONS", + "content-security-policy": "KAT-CSP-VULNERABILITIES", + "referrer-policy": "KAT-NO-REFERRER-POLICY", + "permissions-policy": "KAT-NO-PERMISSIONS-POLICY", +} -def scan_outdated_software(data: dict, ooi_ref: Reference) -> Iterable[NormalizerOutput]: + +def scan_outdated_software(data: list[dict[str, Any]], ooi_ref: Reference) -> Iterable[NormalizerOutput]: for scan in data: for vulnerability in scan["vulnerabilities"]: + vulnerability_id: str = vulnerability["id"] + # If the scanned vulnerability has to do with outdated software - if vulnerability["id"].startswith("6"): + if vulnerability_id.startswith("6"): # Example of `vulnerability["msg"]` # @SOFTWARE/@RUNNING_VER appears to be outdated (current is at least @CURRENT_VER) software_name, found_version = vulnerability["msg"].split()[0].split("/") @@ -29,6 +40,21 @@ def scan_outdated_software(data: dict, ooi_ref: Reference) -> Iterable[Normalize description=vulnerability["msg"], ) + # If the scanned vulnerability has to do with security headers missing + elif vulnerability_id == "013587": + missing_header = vulnerability["msg"].split()[-1].strip(".") + + kat_finding_type_id = MISSING_HEADER_TO_KAT_FINDING_TYPE.get(missing_header) + if kat_finding_type_id is None: + kat_finding_type_id = "KAT-MISSING-HEADER" + finding_type = KATFindingType(id=kat_finding_type_id) + yield finding_type + yield Finding(finding_type=finding_type.reference, ooi=ooi_ref, description=vulnerability["msg"]) + # if the site uses TLS and the Strict-Transport-Security HTTP header is not defined + elif vulnerability_id == "999970": + finding_type = KATFindingType(id="KAT-HSTS-VULNERABILITIES") + yield Finding(finding_type=finding_type.reference, ooi=ooi_ref, description=vulnerability["msg"]) + def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: data = json.loads(raw) From 9e28381ee6ce3f871b73e1290657f798574152f5 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 10 Jan 2025 15:00:54 +0100 Subject: [PATCH 41/43] Update Nikto plugin documentation and rename normalizer function --- boefjes/boefjes/plugins/kat_nikto/description.md | 7 ++++--- boefjes/boefjes/plugins/kat_nikto/normalize.py | 4 ++-- boefjes/boefjes/plugins/kat_nikto/normalizer.json | 4 +++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nikto/description.md b/boefjes/boefjes/plugins/kat_nikto/description.md index e2e1d3c27e0..0336056dd49 100644 --- a/boefjes/boefjes/plugins/kat_nikto/description.md +++ b/boefjes/boefjes/plugins/kat_nikto/description.md @@ -1,15 +1,16 @@ # Nikto Nikto 2.5 is an Open Source (GPL) web server scanner which performs comprehensive tests against web servers for multiple items, including over 7,000 potentially dangerous files/programs, checks for outdated versions of over 1250 servers, and version specific problems on over 270 servers. It also checks for server configuration items such as the presence of multiple index files, HTTP server options, and will attempt to identify installed web servers and software. Scan items and plugins are frequently updated and can be automatically updated. - (taken from [CIRT.net](https://cirt.net/Nikto2)) +This boefje has been developed by Soufyan Abdellati from Cynalytics, with help from Edward Hasekamp from IP-Zorg. ♥ + ### Input OOIs -Nikto expects an IpAddress or a Hostname OOI. +Nikto expects an HostnameHTTPURL OOI. ### Output OOIs -Nikto outputs the following the found outdated software and a finding explaining that the software is outdated. +This boefje outputs found outdated software and findings about the HostnameHTTPURL. **Cat name**: Kitty diff --git a/boefjes/boefjes/plugins/kat_nikto/normalize.py b/boefjes/boefjes/plugins/kat_nikto/normalize.py index be76ab9d09e..5c543a667b5 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalize.py +++ b/boefjes/boefjes/plugins/kat_nikto/normalize.py @@ -16,7 +16,7 @@ } -def scan_outdated_software(data: list[dict[str, Any]], ooi_ref: Reference) -> Iterable[NormalizerOutput]: +def scan_nikto_output(data: list[dict[str, Any]], ooi_ref: Reference) -> Iterable[NormalizerOutput]: for scan in data: for vulnerability in scan["vulnerabilities"]: vulnerability_id: str = vulnerability["id"] @@ -61,4 +61,4 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: ooi_ref = Reference.from_str(input_ooi["primary_key"]) - yield from scan_outdated_software(data, ooi_ref) + yield from scan_nikto_output(data, ooi_ref) diff --git a/boefjes/boefjes/plugins/kat_nikto/normalizer.json b/boefjes/boefjes/plugins/kat_nikto/normalizer.json index 20d00245b13..78c0e4c4379 100644 --- a/boefjes/boefjes/plugins/kat_nikto/normalizer.json +++ b/boefjes/boefjes/plugins/kat_nikto/normalizer.json @@ -6,6 +6,8 @@ ], "produces": [ "Software", - "SoftwareInstance" + "SoftwareInstance", + "Finding", + "KATFindingType" ] } From bb6da9578e3330ba07690719d1ab2e622be628de Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 10 Jan 2025 15:15:58 +0100 Subject: [PATCH 42/43] Made new pre-commit rule happy --- boefjes/tests/test_nikto_normalizer.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/boefjes/tests/test_nikto_normalizer.py b/boefjes/tests/test_nikto_normalizer.py index e2a3fa1ce11..2ad15368166 100644 --- a/boefjes/tests/test_nikto_normalizer.py +++ b/boefjes/tests/test_nikto_normalizer.py @@ -24,12 +24,7 @@ def test_outdated_found(self): description="nginx/1.18.0 appears to be outdated (current is at least 1.25.3).", ) - expected = [ - software, - software_instance, - finding_type, - finding, - ] + expected = [software, software_instance, finding_type, finding] self.assertEqual(expected, oois) From 1f86fd6073c201b74aa47d09b536902f6c85bec5 Mon Sep 17 00:00:00 2001 From: Soufyan Abdellati Date: Fri, 10 Jan 2025 15:18:31 +0100 Subject: [PATCH 43/43] Made test happy with a new plugin --- boefjes/tests/integration/test_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boefjes/tests/integration/test_api.py b/boefjes/tests/integration/test_api.py index 6c2ae495f47..b7c45c0a95d 100644 --- a/boefjes/tests/integration/test_api.py +++ b/boefjes/tests/integration/test_api.py @@ -130,7 +130,7 @@ def test_add_normalizer(test_client, organisation): assert response.status_code == 201 response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/?plugin_type=normalizer") - assert len(response.json()) == 57 + assert len(response.json()) == 58 response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/test_normalizer") assert response.json() == normalizer.model_dump()