Skip to main content

Angularjs CSTI Scanner

acstis logo

License Apache-2.0GitHub release (latest SemVer)OWASP Incubator ProjectArtifact HUBGitHub Repo starsTwitter Follower

What is AngularJS Client-Side Template Injection Scanner (acstis)?#

The AngularJS Client-Side Template Injection Scanner (acstis) is an open source scanner for finding possible template injection vulnerabilities on websites using AngularJS.

For more information visit the projects GitHub site.

Deployment#

The angularjs-csti-scanner chart can be deployed via helm:

# Install HelmChart (use -n to configure another namespace)helm upgrade --install angularjs-csti-scanner secureCodeBox/angularjs-csti-scanner

Scanner Configuration#

The only mandatory parameter is:

Optional arguments:

-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 starting point (e.g. only https)-sos, --scan-other-subdomains                                                    (crawler option) also scan pages that have another subdomain than the starting point-soh, --scan-other-hostnames                                                     (crawler option) also scan pages that have another hostname than the starting point-sot, --scan-other-tlds                                                          (crawler option) also scan pages that have another tld than the starting point-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.

Requirements#

Kubernetes: >=v1.11.0-0

Additional Chart Configurations#

Request configuration#

Because acstis does not 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:

kubectl create configmap --from-file /path/to/my/acstis-config.py acstis-config

Then, mount it into the container:

 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

options.identity.auth = HTTPBasicAuth("username", "password")

Cookies

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

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

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

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]

Values#

KeyTypeDefaultDescription
cascadingRules.enabledboolfalseEnables or disables the installation of the default cascading rules for this scanner
parser.envlist[]Optional environment variables mapped into each parseJob (see: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/)
parser.image.pullPolicystring"IfNotPresent"Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
parser.image.repositorystring"docker.io/securecodebox/parser-angularjs-csti-scanner"Parser image repository
parser.image.tagstringdefaults to the charts versionParser image tag
parser.ttlSecondsAfterFinishedstringnilseconds after which the kubernetes job for the parser will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/
scanner.activeDeadlineSecondsstringnilThere are situations where you want to fail a scan Job after some amount of time. To do so, set activeDeadlineSeconds to define an active deadline (in seconds) when considering a scan Job as failed. (see: https://kubernetes.io/docs/concepts/workloads/controllers/job/#job-termination-and-cleanup)
scanner.backoffLimitint3There are situations where you want to fail a scan Job after some amount of retries due to a logical error in configuration etc. To do so, set backoffLimit to specify the number of retries before considering a scan Job as failed. (see: https://kubernetes.io/docs/concepts/workloads/controllers/job/#pod-backoff-failure-policy)
scanner.envlist[]Optional environment variables mapped into each scanJob (see: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/)
scanner.extraContainerslist[]Optional additional Containers started with each scanJob (see: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)
scanner.extraVolumeMountslist[]Optional VolumeMounts mapped into each scanJob (see: https://kubernetes.io/docs/concepts/storage/volumes/)
scanner.extraVolumeslist[]Optional Volumes mapped into each scanJob (see: https://kubernetes.io/docs/concepts/storage/volumes/)
scanner.image.pullPolicystring"IfNotPresent"Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
scanner.image.repositorystring"docker.io/securecodebox/scanner-angularjs-csti-scanner"Container Image to run the scan
scanner.image.tagstringnildefaults to the charts appVersion
scanner.nameAppendstringnilappend a string to the default scantype name.
scanner.resourcesobject{}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/)
scanner.securityContextobject{"allowPrivilegeEscalation":false,"capabilities":{"drop":["all"]},"privileged":false,"readOnlyRootFilesystem":true,"runAsNonRoot":true}Optional securityContext set on scanner container (see: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
scanner.securityContext.allowPrivilegeEscalationboolfalseEnsure that users privileges cannot be escalated
scanner.securityContext.capabilities.drop[0]string"all"This drops all linux privileges from the container.
scanner.securityContext.privilegedboolfalseEnsures that the scanner container is not run in privileged mode
scanner.securityContext.readOnlyRootFilesystembooltruePrevents write access to the containers file system
scanner.securityContext.runAsNonRootbooltrueEnforces that the scanner image is run as a non root user
scanner.ttlSecondsAfterFinishedstringnilseconds after which the kubernetes job for the scanner will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/

License#

License

Code of secureCodeBox is licensed under the Apache License 2.0.

Examples#

scan-single-url#

This example scans a single URL.

# SPDX-FileCopyrightText: 2021 iteratec GmbH## SPDX-License-Identifier: Apache-2.0
apiVersion: "execution.securecodebox.io/v1"kind: Scanmetadata:  name: "scan-single-url"spec:  scanType: "angularjs-csti-scanner"  parameters:    - "-d"    - "https://example.com"

scan-website-with-options#

To add some headers to the scanners requests create a file called acstis-config.py with the following content:

options.identity.headers.update({    "Authorization": "Bearer <JWT>"})

Then create a config map from this file:

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.

# SPDX-FileCopyrightText: 2021 iteratec GmbH## SPDX-License-Identifier: Apache-2.0
apiVersion: "execution.securecodebox.io/v1"kind: Scanmetadata:  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/"