paazmaya.fi

The Website of Juga Paazmaya | Stories about web development, hardware prototyping, and education

Finding Security holes with Zed Attack Proxy DAST Testing

Dynamic application security testing with Zed Attack Proxy running inside a Docker container and scanning locally running Astro based site called paazmaya.fi

The Zed Attack Proxy (ZAP) is an open-source tool for penetration testing and security assessment of web applications. Since it can find security vulnerabilities, such as Cross-Site Scripting (XSS), SQL Injection, and Broken Authentication, by using the dynamic application security testing (DAST) approach, I wanted to try running it locally against this site.

According to NIST, a Web application security scanner is:

An automated program that searches for software security vulnerabilities within web applications.

Looks like ZAP is currently backed up by Checkmarx, while earlier it was part of the OWASP tools.

While at it, I sent accessibility feedback to Checkmarx about their front page having plenty of movement but no controls for them. No reply yet, after two weeks…

Scanning local site via Docker

First I should have the site up and running, which in my paazmaya.fi project happens with using the command:

npm start

Then took a command from the ZAP documentation to run the full scan with Docker:

docker run --network="host" -v ${pwd}:/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable zap-full-scan.py -t http://localhost:8888/ -g gen.conf -r testreport.html

Note the --network="host" part which is needed to allow the Docker container to use the same network as the host operating system.

However I did face an issue:

ERROR [Errno 5] ZAP failed to access: http://localhost:8888/

For some reason the localhost could not be accessed, and even if I tried to use an IP, like in the following command:

docker run --network="host" -v ${pwd}:/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable zap-full-scan.py -t http://127.0.0.1:8888/ -g gen.conf -r testreport.html

…the issue remained:

ERROR [Errno 5] ZAP failed to access: http://127.0.0.1:8888/

Turns out that the Docker Desktop setting in “Network” had the host sharing their network off, and once I turned it on, the scanner was able to access the host network.

Here is some of the output from the scanner, from which the passing parts and URLs are ommitted:

WARN-NEW: Missing Anti-clickjacking Header [10020] x 12
WARN-NEW: X-Content-Type-Options Header Missing [10021] x 11
WARN-NEW: Content Security Policy (CSP) Header Not Set [10038] x 11
WARN-NEW: PII Disclosure [10062] x 1
WARN-NEW: Permissions Policy Header Not Set [10063] x 11
WARN-NEW: Timestamp Disclosure - Unix [10096] x 1
WARN-NEW: Source Code Disclosure - SQL [10099] x 2
WARN-NEW: Private IP Disclosure [2] x 1
WARN-NEW: CORS Misconfiguration [40040] x 525
WARN-NEW: Sub Resource Integrity Attribute Missing [90003] x 11
WARN-NEW: Insufficient Site Isolation Against Spectre Vulnerability [90004] x 12
FAIL-NEW: 0     FAIL-INPROG: 0  WARN-NEW: 11    WARN-INPROG: 0  INFO: 0 IGNORE: 0       PASS: 126

Results

The final part of the Docker command ealier had -g gen.conf -r testreport.html, which were used to create a HTML version of the report. The HTML report contained more details, and this report summary:

Risk LevelNumber of Alerts
High1
Medium5
Low5
Informational4
False Positives0

Let’s look at the alerts having high or medium risk level:

NameRisk LevelNumber of Instances
PII DisclosureHigh1
CORS MisconfigurationMedium526
Content Security Policy (CSP) Header Not SetMedium11
Missing Anti-clickjacking HeaderMedium12
Source Code Disclosure - SQLMedium2
Sub Resource Integrity Attribute MissingMedium11

The first one is interesting, the only one with high risk level and luckily only one instance. While looking at its origin, problematic-dvds-are-a-challenge, I can already guess that this might be a false positive.

Since the blog post in question is a draft (which is has been over 10 years), it is not publivclly available and found by the scanner only because the site was running locally, where it also shows the draft posts for my own ease of use.

PropertyDetails
Risk LevelHigh
NamePII Disclosure
DescriptionThe response contains Personally Identifiable Information, such as CC number, SSN and similar sensitive data.
URLhttp://localhost:8888/problematic-dvds-are-a-challenge/
MethodGET
Parameter
Attack
Evidence560 270847 270288
Other InfoCredit Card Type detected: Maestro
Instances1
SolutionCheck the response for the potential presence of personally identifiable information (PII), ensure nothing sensitive is leaked by the application.
Reference
CWE Id359
WASC Id13
Plugin Id10062

Nice finding! The issue is however a false positive as the evidence points to an output from a DVD reader, which is not related to credit card numbers.

How about the medium risk level issues?

CORS Misconfiguration

Huh, with 526 findings it is most likely attached to any success (HTTP 200 Code) request made against the site.

Cross-Origin Resource Sharing (CORS) is a security mechanism that, uses HTTP headers to manage cross-origin requests and prevents unauthorized cross-domain access while enabling legitimate cross-origin data sharing.

This CORS misconfiguration could allow an attacker to perform AJAX queries to the vulnerable website from a malicious page loaded by the victim’s user agent.

In order to perform authenticated AJAX queries, the server must specify the header “Access-Control-Allow-Credentials: true” and the “Access-Control-Allow-Origin” header must be set to null or the malicious page’s domain. Even if this misconfiguration doesn’t allow authenticated AJAX requests, unauthenticated sensitive content can still be accessed (e.g intranet websites).

A malicious page can belong to a malicious website but also a trusted website with flaws (e.g XSS, support of HTTP without TLS allowing code injection through MITM, etc).

Adding the following header could be used to fix this issue, while allowing any access:

Access-Control-Allow-Origin: *

Or limiting access to resource only when requested via this site:

Access-Control-Allow-Origin: paazmaya.fi

Content Security Policy (CSP) Header Not Set

Another header related issue is about Content Security Policy (CSP) with 11 findings.

Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware. CSP provides a set of standard HTTP headers that allow website owners to declare approved sources of content that browsers should be allowed to load on that page — covered types are JavaScript, CSS, HTML frames, fonts, images and embeddable objects such as Java applets, ActiveX, audio and video files.

This issue is not valid when the site is served in production, as the header has been configured to be:

Content-Security-Policy: frame-ancestors 'none'

Missing Anti-clickjacking Header

Still on the headers, this ClickJacking issue with 12 findings, is also handled inproduction by using the configuration:

Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY

The response does not protect against ‘ClickJacking’ attacks. It should include either Content-Security-Policy with ‘frame-ancestors’ directive or X-Frame-Options.

Source Code Disclosure - SQL

Two (2) instances of SQL source code were found, both are in this case false positives, since the posts are there for a purpose:

Application Source Code was disclosed by the web server. - SQL

Sub Resource Integrity Attribute Missing

Last medium risk level issue, with 11 findings, is about Subresource integrity (SRI).

The integrity attribute is missing on a script or link tag served by an external server. The integrity tag prevents an attacker who have gained access to this server from injecting a malicious content.

All the findings refer to <link rel="profile" href="https://microformats.org/profile/hcard"> which might be a bit challenging to have a validation hash that would also be kept up to date when the target page changes.

Usually SRI is used for JavaScript that will be executed in the same context as the rest of the web site. Even for CSS is might be useful, as bad behaving CSS could prevent seeing something that the user should see.

Perhaps there could be an Astro plugin (such as Astro-Shield) that generates the SRI sha256 hash for any CSS of JavaScript files in the resulting HTML?