diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 82bcbef0e4..65bc690705 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -260,6 +260,7 @@ jobs: matrix: parser: - amass + - angularjs-csti-scanner - git-repo-scanner - gitleaks - kube-hunter @@ -332,6 +333,7 @@ jobs: strategy: matrix: scanner: + - angularjs-csti-scanner - gitleaks - kube-hunter - kubeaudit diff --git a/scanners/angularjs-csti-scanner/.helmignore b/scanners/angularjs-csti-scanner/.helmignore new file mode 100644 index 0000000000..bfc32a880c --- /dev/null +++ b/scanners/angularjs-csti-scanner/.helmignore @@ -0,0 +1,6 @@ +.DS_Store + +parser/ +scanner/ +examples/ + diff --git a/scanners/angularjs-csti-scanner/Chart.yaml b/scanners/angularjs-csti-scanner/Chart.yaml new file mode 100644 index 0000000000..3387cc2cd1 --- /dev/null +++ b/scanners/angularjs-csti-scanner/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +name: angularja-csti-scanner +description: A Helm chart for the angularja csti scanner that integrates with the secureCodeBox. + +type: application +# version - gets automatically set to the secureCodeBox release version when the helm charts gets published +version: latest +appVersion: 3.0.6 +kubeVersion: ">=v1.11.0-0" + +keywords: + - security + - acstis + - scanner + - secureCodeBox +home: https://docs.securecodebox.io/docs/scanners/angularja-csti-scanner +icon: https://docs.securecodebox.io/img/integrationIcons/Acstis.svg +sources: + - https://github.com/secureCodeBox/secureCodeBox +maintainers: + - name: iteratec GmbH + email: secureCodeBox@iteratec.com + diff --git a/scanners/angularjs-csti-scanner/README.md b/scanners/angularjs-csti-scanner/README.md new file mode 100644 index 0000000000..c7eeefa98a --- /dev/null +++ b/scanners/angularjs-csti-scanner/README.md @@ -0,0 +1,149 @@ +--- +title: "Angularjs CSTI Scanner" +category: "scanner" +type: "Repository" +state: "in progress" +usecase: "Find AngularJS websites vulnerable to template injections" +--- + +![acstis logo](https://rawgit.com/tijme/angularjs-csti-scanner/master/.github/logo.svg?pypi=png.from.svg) + +AngularJS Client-Side Template Injection Scanner (acstis) is a open source scanner for +finding possible template injection vulnerabilities on websites using AngularJS. + +For more information visit the projects github site + +## Deployment + +The gitleaks scanner can be deployed with helm: + +```bash +helm upgrade --install acstis secureCodeBox/acstis +``` + +## Scanner configuration + +The only mandatory parameter is: +- `-d`: The url to scan (e.g. https://angularjs.org/). + +Optional arguments: + +```bash +-c, --crawl use the crawler to scan all the entire domain +-vp, --verify-payload use a javascript engine to verify if the payload was executed (otherwise false positives may occur) +-av ANGULAR_VERSION, --angular-version ANGULAR_VERSION manually pass the angular version (e.g. 1.4.2) if the automatic check doesn't work +-vrl VULNERABLE_REQUESTS_LOG, --vulnerable-requests-log VULNERABLE_REQUESTS_LOG log all vulnerable requests to this file (e.g. /var/logs/acstis.log or urls.log) +-siv, --stop-if-vulnerable (crawler option) stop scanning if a vulnerability was found +-pmm, --protocol-must-match (crawler option) only scan pages with the same protocol as the startpoint (e.g. only https) +-sos, --scan-other-subdomains (crawler option) also scan pages that have another subdomain than the startpoint +-soh, --scan-other-hostnames (crawler option) also scan pages that have another hostname than the startpoint +-sot, --scan-other-tlds (crawler option) also scan pages that have another tld than the startpoint +-md MAX_DEPTH, --max-depth MAX_DEPTH (crawler option) the maximum search depth (default is unlimited) +-mt MAX_THREADS, --max-threads MAX_THREADS (crawler option) the maximum amount of simultaneous threads to use (default is 20) +-iic, --ignore-invalid-certificates (crawler option) ignore invalid ssl certificates +``` + +**Do not** override the option `-vrl` or `--vulnerable-requests-log`. It is already configured for automatic findings parsing. + +### Request configuration + +Because *acstis* does not provide provide command line arguments for configuring the sent requests, +you have to mount a config map into the scan container on a specific location. Your additional config map should be + mounted to `/acstis/config/acstis-config.py`. For example create a config map: + + ```bash +kubectl create configmap --from-file /path/to/my/acstis-config.py acstis-config +``` + + And mount it into the container: + + ```yaml + volumes: + - name: "acstis-config" + configMap: + name: "acstis-config" + volumeMounts: + - name: "acstis-config" + mountPath: "/acstis/config/" +``` + +#### Configuration options in *acstis-config.py* + +Add the following snippets to the *acstis-config.py* file to enable further options. +The options are python code which will be injected into the *acstis* script before execution. + +**Basic Authentication** +```text +options.identity.auth = HTTPBasicAuth("username", "password") +``` + +**Cookies** +```text +options.identity.cookies.set(name='tasty_cookie', value='yum', domain='finnwea.com', path='/cookies') +options.identity.cookies.set(name='gross_cookie', value='blech', domain='finnwea.com', path='/elsewhere') +``` + +**Headers** +```text +options.identity.headers.update({ + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", + "Authorization": "Bearer ey3jafoe.2jefo..." +}) +``` + +**Proxies** +```text +options.identity.proxies = { + # No authentication + # 'http': 'http://host:port', + # 'https': 'http://host:port', + + # Basic authentication + # 'http': 'http://user:pass@host:port', + # 'https': 'https://user:pass@host:port', + + # SOCKS + 'http': 'socks5://user:pass@host:port', + 'https': 'socks5://user:pass@host:port' +} +``` + +**Scope options** +```text +options.scope.protocol_must_match = False + +options.scope.subdomain_must_match = True + +options.scope.hostname_must_match = True + +options.scope.tld_must_match = True + +options.scope.max_depth = None + +options.scope.request_methods = [ + Request.METHOD_GET, + Request.METHOD_POST, + Request.METHOD_PUT, + Request.METHOD_DELETE, + Request.METHOD_OPTIONS, + Request.METHOD_HEAD +] +``` + +## Chart Configuration + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| image.repository | string | `"docker.io/securecodebox/scanner-acstis"` | Container Image to run the scan | +| image.tag | string | `nil` | defaults to the charts version | +| parseJob.ttlSecondsAfterFinished | string | `nil` | seconds after which the kubernetes job for the parser will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ | +| parserImage.repository | string | `"docker.io/securecodebox/parser-acstis"` | Parser image repository | +| parserImage.tag | string | defaults to the charts version | Parser image tag | +| scannerJob.env | list | `[]` | Optional environment variables mapped into each scanJob (see: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) | +| scannerJob.extraContainers | list | `[]` | Optional additional Containers started with each scanJob (see: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) | +| scannerJob.extraVolumeMounts | list | `[]` | Optional VolumeMounts mapped into each scanJob (see: https://kubernetes.io/docs/concepts/storage/volumes/) | +| scannerJob.extraVolumes | list | `[]` | Optional Volumes mapped into each scanJob (see: https://kubernetes.io/docs/concepts/storage/volumes/) | +| scannerJob.resources | object | `{}` | CPU/memory resource requests/limits (see: https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/, https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/) | +| scannerJob.securityContext | object | `{}` | Optional securityContext set on scanner container (see: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) | +| scannerJob.ttlSecondsAfterFinished | string | `nil` | seconds after which the kubernetes job for the scanner will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ | + diff --git a/scanners/angularjs-csti-scanner/README.md.gotmpl b/scanners/angularjs-csti-scanner/README.md.gotmpl new file mode 100644 index 0000000000..d397cf5a48 --- /dev/null +++ b/scanners/angularjs-csti-scanner/README.md.gotmpl @@ -0,0 +1,136 @@ +--- +title: "Angularjs CSTI Scanner" +category: "scanner" +type: "Repository" +state: "in progress" +usecase: "Find AngularJS websites vulnerable to template injections" +--- + +![acstis logo](https://rawgit.com/tijme/angularjs-csti-scanner/master/.github/logo.svg?pypi=png.from.svg) + +AngularJS Client-Side Template Injection Scanner (acstis) is a open source scanner for +finding possible template injection vulnerabilities on websites using AngularJS. + +For more information visit the projects github site + +## Deployment + +The gitleaks scanner can be deployed with helm: + +```bash +helm upgrade --install acstis secureCodeBox/acstis +``` + +## Scanner configuration + +The only mandatory parameter is: +- `-d`: The url to scan (e.g. https://angularjs.org/). + +Optional arguments: + +```bash +-c, --crawl use the crawler to scan all the entire domain +-vp, --verify-payload use a javascript engine to verify if the payload was executed (otherwise false positives may occur) +-av ANGULAR_VERSION, --angular-version ANGULAR_VERSION manually pass the angular version (e.g. 1.4.2) if the automatic check doesn't work +-vrl VULNERABLE_REQUESTS_LOG, --vulnerable-requests-log VULNERABLE_REQUESTS_LOG log all vulnerable requests to this file (e.g. /var/logs/acstis.log or urls.log) +-siv, --stop-if-vulnerable (crawler option) stop scanning if a vulnerability was found +-pmm, --protocol-must-match (crawler option) only scan pages with the same protocol as the startpoint (e.g. only https) +-sos, --scan-other-subdomains (crawler option) also scan pages that have another subdomain than the startpoint +-soh, --scan-other-hostnames (crawler option) also scan pages that have another hostname than the startpoint +-sot, --scan-other-tlds (crawler option) also scan pages that have another tld than the startpoint +-md MAX_DEPTH, --max-depth MAX_DEPTH (crawler option) the maximum search depth (default is unlimited) +-mt MAX_THREADS, --max-threads MAX_THREADS (crawler option) the maximum amount of simultaneous threads to use (default is 20) +-iic, --ignore-invalid-certificates (crawler option) ignore invalid ssl certificates +``` + +**Do not** override the option `-vrl` or `--vulnerable-requests-log`. It is already configured for automatic findings parsing. + +### Request configuration + +Because *acstis* does not provide provide command line arguments for configuring the sent requests, +you have to mount a config map into the scan container on a specific location. Your additional config map should be + mounted to `/acstis/config/acstis-config.py`. For example create a config map: + + ```bash +kubectl create configmap --from-file /path/to/my/acstis-config.py acstis-config +``` + + And mount it into the container: + + ```yaml + volumes: + - name: "acstis-config" + configMap: + name: "acstis-config" + volumeMounts: + - name: "acstis-config" + mountPath: "/acstis/config/" +``` + +#### Configuration options in *acstis-config.py* + +Add the following snippets to the *acstis-config.py* file to enable further options. +The options are python code which will be injected into the *acstis* script before execution. + +**Basic Authentication** +```text +options.identity.auth = HTTPBasicAuth("username", "password") +``` + +**Cookies** +```text +options.identity.cookies.set(name='tasty_cookie', value='yum', domain='finnwea.com', path='/cookies') +options.identity.cookies.set(name='gross_cookie', value='blech', domain='finnwea.com', path='/elsewhere') +``` + +**Headers** +```text +options.identity.headers.update({ + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", + "Authorization": "Bearer ey3jafoe.2jefo..." +}) +``` + +**Proxies** +```text +options.identity.proxies = { + # No authentication + # 'http': 'http://host:port', + # 'https': 'http://host:port', + + # Basic authentication + # 'http': 'http://user:pass@host:port', + # 'https': 'https://user:pass@host:port', + + # SOCKS + 'http': 'socks5://user:pass@host:port', + 'https': 'socks5://user:pass@host:port' +} +``` + +**Scope options** +```text +options.scope.protocol_must_match = False + +options.scope.subdomain_must_match = True + +options.scope.hostname_must_match = True + +options.scope.tld_must_match = True + +options.scope.max_depth = None + +options.scope.request_methods = [ + Request.METHOD_GET, + Request.METHOD_POST, + Request.METHOD_PUT, + Request.METHOD_DELETE, + Request.METHOD_OPTIONS, + Request.METHOD_HEAD +] +``` + +## Chart Configuration + +{{ template "chart.valuesTable" . }} + diff --git a/scanners/angularjs-csti-scanner/examples/scan-single-url/README.md b/scanners/angularjs-csti-scanner/examples/scan-single-url/README.md new file mode 100644 index 0000000000..6e309b4ca6 --- /dev/null +++ b/scanners/angularjs-csti-scanner/examples/scan-single-url/README.md @@ -0,0 +1 @@ +This example scans a single URL. diff --git a/scanners/angularjs-csti-scanner/examples/scan-single-url/scan.yaml b/scanners/angularjs-csti-scanner/examples/scan-single-url/scan.yaml new file mode 100644 index 0000000000..88154ce53e --- /dev/null +++ b/scanners/angularjs-csti-scanner/examples/scan-single-url/scan.yaml @@ -0,0 +1,9 @@ +apiVersion: "execution.securecodebox.io/v1" +kind: Scan +metadata: + name: "scan-single-url" +spec: + scanType: "angularjs-csti-scanner" + parameters: + - "-d" + - "https://example.com" diff --git a/scanners/angularjs-csti-scanner/examples/scan-website-with-options/README.md b/scanners/angularjs-csti-scanner/examples/scan-website-with-options/README.md new file mode 100644 index 0000000000..0486823f75 --- /dev/null +++ b/scanners/angularjs-csti-scanner/examples/scan-website-with-options/README.md @@ -0,0 +1,15 @@ +To add some headers to the scanners requests create a file called *acstis-config.py* with the following content: + +```text +options.identity.headers.update({ + "Authorization": "Bearer " +}) +``` + +Then create a config map from this file: + +```bash +kubectl create configmap --from-file /path/to/my/acstis-config.py acstis-config +``` + +After mounting the config map to the specified path you can execute your scan. diff --git a/scanners/angularjs-csti-scanner/examples/scan-website-with-options/scan.yaml b/scanners/angularjs-csti-scanner/examples/scan-website-with-options/scan.yaml new file mode 100644 index 0000000000..a68335cec0 --- /dev/null +++ b/scanners/angularjs-csti-scanner/examples/scan-website-with-options/scan.yaml @@ -0,0 +1,20 @@ +apiVersion: "execution.securecodebox.io/v1" +kind: Scan +metadata: + name: "scan-website-with-jwt" +spec: + scanType: "angularjs-csti-scanner" + parameters: + - "-d" + - "https://example.com" + - "-c" + # you should always specify a max depth when crawling + - "-md" + - "3" + volumes: + - name: "acstis-config" + configMap: + name: "acstis-config" + volumeMounts: + - name: "acstis-config" + mountPath: "/acstis/config/" diff --git a/scanners/angularjs-csti-scanner/helm2.Chart.yaml b/scanners/angularjs-csti-scanner/helm2.Chart.yaml new file mode 100644 index 0000000000..4cc44ac19c --- /dev/null +++ b/scanners/angularjs-csti-scanner/helm2.Chart.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +name: angularja-csti-scanner +description: A Helm chart for the angularja csti scanner that integrates with the secureCodeBox. + +type: application +# version - gets automatically set to the secureCodeBox release version when the helm charts gets published +version: latest +kubeVersion: ">=v1.11.0-0" + +keywords: + - security + - acstis + - scanner + - secureCodeBox +home: https://docs.securecodebox.io/docs/scanners/angularja-csti-scanner +icon: https://docs.securecodebox.io/img/integrationIcons/Acstis.svg +sources: + - https://github.com/secureCodeBox/secureCodeBox +maintainers: + - name: iteratec GmbH + email: secureCodeBox@iteratec.com + diff --git a/scanners/angularjs-csti-scanner/parser/Dockerfile b/scanners/angularjs-csti-scanner/parser/Dockerfile new file mode 100644 index 0000000000..5925068437 --- /dev/null +++ b/scanners/angularjs-csti-scanner/parser/Dockerfile @@ -0,0 +1,4 @@ +ARG baseImageTag +FROM securecodebox/parser-sdk-nodejs:${baseImageTag:-latest} +WORKDIR /home/app/parser-wrapper/parser/ +COPY --chown=app:app ./parser.js ./parser.js diff --git a/scanners/angularjs-csti-scanner/parser/__testFiles__/acstis-test-empty-findings.txt b/scanners/angularjs-csti-scanner/parser/__testFiles__/acstis-test-empty-findings.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scanners/angularjs-csti-scanner/parser/__testFiles__/acstis-test-findings.txt b/scanners/angularjs-csti-scanner/parser/__testFiles__/acstis-test-findings.txt new file mode 100644 index 0000000000..917b3a1009 --- /dev/null +++ b/scanners/angularjs-csti-scanner/parser/__testFiles__/acstis-test-findings.txt @@ -0,0 +1,2 @@ +POST(string={{a=toString().constructor.prototype;a.charAt=a.trim;$eval('a,alert(1),a')}}): https://www.google.com/test/ +GET(category={{alert('test')}}): http://localhost:5000/home?category={{alert('test')}} diff --git a/scanners/angularjs-csti-scanner/parser/parser.js b/scanners/angularjs-csti-scanner/parser/parser.js new file mode 100644 index 0000000000..c4f76ac0cf --- /dev/null +++ b/scanners/angularjs-csti-scanner/parser/parser.js @@ -0,0 +1,51 @@ +async function parse(fileContent) { + + if (fileContent.length === 0) { + return [] + } + + const lines = fileContent.split('\n') + lines.splice(-1, 1) + + return lines.map(line => { + const method = parseMethod(line) + const url = parseUrl(line) + const data = parseData(line, method.length) + let parameter = null + let injectedTemplate = null + if (data.length > 5) { + parameter = data.substring(0, data.indexOf('=')) + injectedTemplate = data.substring(data.indexOf('=') + 1) + } + + return { + name: 'AngularJS template injection', + description: 'The given in this finding URL is vulnerable to AngularJS template injection which can lead to XSS', + osi_layer: 'APPLICATION', + severity: 'HIGH', + category: 'Template Injection', + attributes: { + url: url, + method: method, + parameter: parameter, + injectedTemplate: injectedTemplate, + } + } + }) +} + +function parseMethod(line) { + return line.substring(0, line.indexOf('(')) +} + +function parseUrl(line) { + console.log(line) + return line.match(/http[s]?:\/\/[^\n ]+/g)[0] +} + +function parseData(line, start) { + return line.substring(start + 1, line.indexOf('): ')) +} + + +module.exports.parse = parse diff --git a/scanners/angularjs-csti-scanner/parser/parser.test.js b/scanners/angularjs-csti-scanner/parser/parser.test.js new file mode 100644 index 0000000000..c4cfc5a4fc --- /dev/null +++ b/scanners/angularjs-csti-scanner/parser/parser.test.js @@ -0,0 +1,57 @@ +const fs = require("fs"); +const util = require("util"); + +// eslint-disable-next-line security/detect-non-literal-fs-filename +const readFile = util.promisify(fs.readFile); + +const { parse } = require("./parser"); + +test("should properly parse acstis empty finding log file", async () => { + const findings = await readFile( + __dirname + "/__testFiles__/acstis-test-empty-findings.txt", + { + encoding: "utf8" + } + ); + expect(await parse(findings)).toMatchInlineSnapshot( + 'Array []'); +}); + +test("should properly parse acstis finding log file", async () => { + const findings = await readFile( + __dirname + "/__testFiles__/acstis-test-findings.txt", + { + encoding: "utf8" + } + ); + expect(await parse(findings)).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object { + "injectedTemplate": "{{a=toString().constructor.prototype;a.charAt=a.trim;$eval('a,alert(1),a')}}", + "method": "POST", + "parameter": "string", + "url": "https://www.google.com/test/", + }, + "category": "Template Injection", + "description": "The given in this finding URL is vulnerable to AngularJS template injection which can lead to XSS", + "name": "AngularJS template injection", + "osi_layer": "APPLICATION", + "severity": "HIGH", + }, + Object { + "attributes": Object { + "injectedTemplate": "{{alert('test')}}", + "method": "GET", + "parameter": "category", + "url": "http://localhost:5000/home?category={{alert('test')}}", + }, + "category": "Template Injection", + "description": "The given in this finding URL is vulnerable to AngularJS template injection which can lead to XSS", + "name": "AngularJS template injection", + "osi_layer": "APPLICATION", + "severity": "HIGH", + }, + ] + `); +}); diff --git a/scanners/angularjs-csti-scanner/scanner/Dockerfile b/scanners/angularjs-csti-scanner/scanner/Dockerfile new file mode 100644 index 0000000000..ef2cf03b74 --- /dev/null +++ b/scanners/angularjs-csti-scanner/scanner/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.6-alpine +ARG scannerVersion +COPY acstis-script.py /acstis/acstis-script.py +COPY wrapper.sh /wrapper.sh +RUN apk add --update --no-cache g++ gcc libxslt-dev +RUN pip install https://github.com/tijme/angularjs-csti-scanner/archive/$scannerVersion.zip +ENTRYPOINT [ "sh", "/wrapper.sh" ] diff --git a/scanners/angularjs-csti-scanner/scanner/acstis-script.py b/scanners/angularjs-csti-scanner/scanner/acstis-script.py new file mode 100644 index 0000000000..4d0d5261bb --- /dev/null +++ b/scanners/angularjs-csti-scanner/scanner/acstis-script.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- + +# MIT License +# +# Copyright (c) 2017 Tijme Gommers +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import argparse +import colorlog +import logging + +from nyawc.Options import Options +from acstis.Driver import Driver +from acstis.helpers.PackageHelper import PackageHelper + +from requests.auth import HTTPBasicAuth +from nyawc.http.Request import Request + +def main(): + """Start the scanner.""" + + print_banner() + setup_logger() + + args = require_arguments() + + options = Options() + + options.scope.protocol_must_match = args.protocol_must_match + options.scope.subdomain_must_match = not args.scan_other_subdomains + options.scope.hostname_must_match = not args.scan_other_hostnames + options.scope.tld_must_match = not args.scan_other_tlds + options.scope.max_depth = args.max_depth if args.crawl else 0 + options.performance.max_threads = args.max_threads + options.misc.verify_ssl_certificates = not args.ignore_invalid_certificates + options.misc.trusted_certificates = args.trusted_certificates + + #INSERT CUSTOM OPTIONS HERE + + + driver = Driver(args, options) + driver.start() + +def require_arguments(): + """Get the arguments from CLI input. + Returns: + :class:`argparse.Namespace`: A namespace with all the parsed CLI arguments. + """ + + parser = argparse.ArgumentParser( + prog=PackageHelper.get_alias(), + formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=180, width=180) + ) + + optional = parser._action_groups.pop() + required = parser.add_argument_group("required arguments") + + required.add_argument("-d", "--domain", help="the domain to scan (e.g. finnwea.com)", required=True) + + optional.add_argument("-c", "--crawl", help="use the crawler to scan all the entire domain", action="store_true") + optional.add_argument("-vp", "--verify-payload", help="use a javascript engine to verify if the payload was executed (otherwise false positives may occur)", action="store_true") + optional.add_argument("-av", "--angular-version", help="manually pass the angular version (e.g. 1.4.2) if the automatic check doesn't work", type=str, default=None) + optional.add_argument("-vrl", "--vulnerable-requests-log", help="log all vulnerable requests to this file (e.g. /var/logs/acstis.log or urls.log)", type=str, default=None) + optional.add_argument("-siv", "--stop-if-vulnerable", help="(crawler option) stop scanning if a vulnerability was found", action="store_true") + optional.add_argument("-pmm", "--protocol-must-match", help="(crawler option) only scan pages with the same protocol as the startpoint (e.g. only https)", action="store_true") + optional.add_argument("-sos", "--scan-other-subdomains", help="(crawler option) also scan pages that have another subdomain than the startpoint", action="store_true") + optional.add_argument("-soh", "--scan-other-hostnames", help="(crawler option) also scan pages that have another hostname than the startpoint", action="store_true") + optional.add_argument("-sot", "--scan-other-tlds", help="(crawler option) also scan pages that have another tld than the startpoint", action="store_true") + optional.add_argument("-md", "--max-depth", help="(crawler option) the maximum search depth (default is unlimited)", type=int) + optional.add_argument("-mt", "--max-threads", help="(crawler option) the maximum amount of simultaneous threads to use (default is 20)", type=int, default=20) + optional.add_argument("-iic", "--ignore-invalid-certificates", help="(crawler option) ignore invalid ssl certificates", action="store_true") + optional.add_argument("-tc", "--trusted-certificates", help="(crawler option) trust this CA_BUNDLE file (.pem) or directory with certificates", type=str, default=None) + + parser._action_groups.append(optional) + return parser.parse_args() + +def setup_logger(): + """Setup ColorLog to enable colored logging output.""" + + # Colored logging + handler = colorlog.StreamHandler() + handler.setFormatter(colorlog.ColoredFormatter( + "%(log_color)s[%(levelname)s] %(message)s", + log_colors={ + "DEBUG": "cyan", + "INFO": "white", + "SUCCESS": "green", + "WARNING": "yellow", + "ERROR": "red", + "CRITICAL": "red,bg_white" + } + )) + + logger = colorlog.getLogger() + logger.addHandler(handler) + + # Also show INFO logs + logger.setLevel(logging.INFO) + + # Add SUCCESS logging + logging.SUCCESS = 25 + logging.addLevelName( + logging.SUCCESS, + "SUCCESS" + ) + + # Disable Selenium logging + selenium_logger = logging.getLogger("selenium.webdriver.remote.remote_connection") + selenium_logger.setLevel(logging.WARNING) + + setattr( + logger, + "success", + lambda message, *args: logger._log(logging.SUCCESS, message, args) + ) + +def print_banner(): + """Print a useless ASCII art banner to make things look a bit nicer.""" + + print(""" + /$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$$$ /$$$$$$ /$$$$$$ + /$$__ $$ /$$__ $$ /$$__ $$|__ $$__/|_ $$_/ /$$__ $$ +| $$ \ $$| $$ \__/| $$ \__/ | $$ | $$ | $$ \__/ +| $$$$$$$$| $$ | $$$$$$ | $$ | $$ | $$$$$$ +| $$__ $$| $$ \____ $$ | $$ | $$ \____ $$ +| $$ | $$| $$ $$ /$$ \ $$ | $$ | $$ /$$ \ $$ +| $$ | $$| $$$$$$/| $$$$$$/ | $$ /$$$$$$| $$$$$$/ +|__/ |__/ \______/ \______/ |__/ |______/ \______/ +Version """ + PackageHelper.get_version() + """ - Copyright 2017 Tijme Gommers + """) + +if __name__ == "__main__": + main() diff --git a/scanners/angularjs-csti-scanner/scanner/wrapper.sh b/scanners/angularjs-csti-scanner/scanner/wrapper.sh new file mode 100644 index 0000000000..9d1602a960 --- /dev/null +++ b/scanners/angularjs-csti-scanner/scanner/wrapper.sh @@ -0,0 +1,14 @@ +# If acstis config exists paste it into the acstis script +if [ -f /acstis/config/acstis-config.py ]; then + echo "Insert acstis-config file into acstis script" + awk '{$1=$1}1' /acstis/config/acstis-config.py | # Trim start end end spaces of each line of the config + awk -v x=4 '{printf "%" x "s%s\n", "", $0}' | # Add indentation of 4 to every line + sed -i '/#INSERT CUSTOM OPTIONS HERE/ r /dev/stdin' /acstis/acstis-script.py # Insert config into script +fi +python /acstis/acstis-script.py $@ + +# If no finding occured generate a empty file for the lurcher +if [ ! -f /home/securecodebox/findings.log ]; then + touch /home/securecodebox/findings.log +fi +exit 0 diff --git a/scanners/angularjs-csti-scanner/templates/angularjs-csti-scanner-parse-definition.yaml b/scanners/angularjs-csti-scanner/templates/angularjs-csti-scanner-parse-definition.yaml new file mode 100644 index 0000000000..a9b00640ba --- /dev/null +++ b/scanners/angularjs-csti-scanner/templates/angularjs-csti-scanner-parse-definition.yaml @@ -0,0 +1,8 @@ +apiVersion: "execution.securecodebox.io/v1" +kind: ParseDefinition +metadata: + name: "acstis-log" +spec: + handlesResultsType: acstis-log + image: "{{ .Values.parserImage.repository }}:{{ .Values.parserImage.tag | default .Chart.Version }}" + ttlSecondsAfterFinished: {{ .Values.parseJob.ttlSecondsAfterFinished }} diff --git a/scanners/angularjs-csti-scanner/templates/angularjs-csti-scanner-scan-type.yaml b/scanners/angularjs-csti-scanner/templates/angularjs-csti-scanner-scan-type.yaml new file mode 100644 index 0000000000..a71ab18406 --- /dev/null +++ b/scanners/angularjs-csti-scanner/templates/angularjs-csti-scanner-scan-type.yaml @@ -0,0 +1,38 @@ +apiVersion: "execution.securecodebox.io/v1" +kind: ScanType +metadata: + name: "angularjs-csti-scanner" +spec: + extractResults: + type: acstis-log + location: "/home/securecodebox/findings.log" + jobTemplate: + spec: + {{- if .Values.scannerJob.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ .Values.scannerJob.ttlSecondsAfterFinished }} + {{- end }} + backoffLimit: 3 + template: + spec: + restartPolicy: OnFailure + containers: + - name: acstis-scanner + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.appVersion }}" + command: + - "sh" + - "/wrapper.sh" + - "-vrl" + - "/home/securecodebox/findings.log" + resources: + {{- toYaml .Values.scannerJob.resources | nindent 16 }} + securityContext: + {{- toYaml .Values.scannerJob.securityContext | nindent 16 }} + env: + {{- toYaml .Values.scannerJob.env | nindent 16 }} + volumeMounts: + {{- toYaml .Values.scannerJob.extraVolumeMounts | nindent 16 }} + {{- if .Values.scannerJob.extraContainers }} + {{- toYaml .Values.scannerJob.extraContainers | nindent 12 }} + {{- end }} + volumes: + {{- toYaml .Values.scannerJob.extraVolumes | nindent 12 }} diff --git a/scanners/angularjs-csti-scanner/values.yaml b/scanners/angularjs-csti-scanner/values.yaml new file mode 100644 index 0000000000..4bb11145b4 --- /dev/null +++ b/scanners/angularjs-csti-scanner/values.yaml @@ -0,0 +1,46 @@ +image: + # image.repository -- Container Image to run the scan + repository: docker.io/securecodebox/scanner-acstis + # image.tag -- defaults to the charts version + tag: null + +parserImage: + # parserImage.tag - defaults to the charts version + # parserImage.repository -- Parser image repository + repository: docker.io/securecodebox/parser-acstis + # parserImage.tag -- Parser image tag + # @default -- defaults to the charts version + tag: null + +parseJob: + # parseJob.ttlSecondsAfterFinished -- seconds after which the kubernetes job for the parser will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ + ttlSecondsAfterFinished: null + +scannerJob: +# scannerJob.ttlSecondsAfterFinished -- seconds after which the kubernetes job for the scanner will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ + ttlSecondsAfterFinished: null + + # scannerJob.resources -- CPU/memory resource requests/limits (see: https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/, https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/) + resources: {} + # resources: + # requests: + # memory: "256Mi" + # cpu: "250m" + # limits: + # memory: "512Mi" + # cpu: "500m" + + # scannerJob.env -- Optional environment variables mapped into each scanJob (see: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) + env: [] + + # scannerJob.extraVolumes -- Optional Volumes mapped into each scanJob (see: https://kubernetes.io/docs/concepts/storage/volumes/) + extraVolumes: [] + + # scannerJob.extraVolumeMounts -- Optional VolumeMounts mapped into each scanJob (see: https://kubernetes.io/docs/concepts/storage/volumes/) + extraVolumeMounts: [] + + # scannerJob.extraContainers -- Optional additional Containers started with each scanJob (see: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) + extraContainers: [] + + # scannerJob.securityContext -- Optional securityContext set on scanner container (see: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) + securityContext: {}