Headless Web Application Scanning with OWASP ZAP

Headless Web Application Scanning with OWASP ZAP

OWASP Zed Attack Proxy (ZAP) is one of the most used suite to perform web application scanning assessment alongside with Burp Suite from PortSwigger.

If you don’t know about OWASP (Open Web Application Security Project), you should check their official web to learn more about their projects, initiatives and guidelines: https://owasp.org/

To briefly explain what is OWASP foundation, it is an organisation that helps cybersecurity professionals around the world to follow and enforce a security industry standard in their cybersecurity programs to protect their web applications. Their mission is to make a more secure internet for everybody with their material and also offers trainings.

Therefore, one of the tools provided by OWASP, is the OWASP ZAP which allows cybersecurity or penetration testing professionals, to perform web application security scanning, like web crawling, proxy intercept, web application vulnerability scanning, testing or, in other words, black box testing or DAST (Dynamic Application Security Testing). The good thing about this tool compared to the Burp Suite, is that is free and you don’t need to pay any license fee in order to use the complete product.

In this post, I’m going to explain one of the ways to execute OWASP ZAP in headless or command line way, so you don’t need to deal with any GUI which could be a hassle to integrate in any automation or CI/CD pipeline.

As a reminder, I recommend to execute these steps always in a separate testing environment from scratch, so you can ensure to not impact any working environment and also to avoid interfering in the results of the tests.

With that been said, let’s dive in to the topic in order to learn how to use OWASP ZAP in headless mode to scan your web applications.

Install your environment for OWASP ZAP in CentOS

First of all, you need to setup a machine (Virtual machine is recommended) with docker engine to run OWASP ZAP. To do so, follow these sequence of commands for CentOS 7. You’ll need a user with sudo privileges in order to complete installation step:

$  sudo yum install -y yum-utils
$  sudo yum-config-manager --add-repo   https://download.docker.com/linux/centos/docker-ce.repo
$  sudo yum install -y docker-ce docker-ce-cli containerd

If the import GPG key (060a 61c5 1b55 8a7f 742b 77aa c52f eb6b 621e 9f35) is prompted to ask confirmation then type “y” and enter:

Yum GPG Key installation prompt

You might want to check whether docker was installed or not running the following commands:

$ rpm -qa | grep docker
$ which docker

The output from the above commands should be similar to the picture:

Validating if docker engine was installed correctly in CentOS

If everything is okay, then jump to the Setup docker engine installation section of this post.

Install your environment for OWASP ZAP in Ubuntu

You need to setup a machine (Virtual machine is recommended) with docker engine to run OWASP ZAP. In this post, we are going to use Ubuntu 18, but newer versions can follow this same guide to install docker engine as well. Note that sudo privileges will be needed during installation:

$ sudo apt-get update -y
$ sudo apt-get install ca-certificates curl gnupg lsb-release -y
$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update -y
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y

Once the installation is completed, then run the following commands to ensure that was done successfuly:

$ dpkg-query -l | grep docker
$ which docker
validating the docker engine installation with Ubuntu

If you obtain an output that it looks like the above picture, then you are good to proceed to the next section.

Setup docker engine installation

After installing successfully docker engine on your machine with either CentOS or Ubuntu, execute the following commands in order to provide docker privileges to the current user that will use docker and o run the docker daemon.

$ sudo usermod -G docker -a $USER
$ sudo su $USER
$ sudo systemctl start docker
$ docker ps

If running docker ps command line doesn’t shows any error then the docker engine is up and running correctly. Note that the usermod command is to include the current user into docker’s group, so you don’t need to run docker commands with the sudo command all the time. In addition, the purpose of sudo su $USER command is to create a new session with the current user to refresh the groups assigned.

Run OWASP ZAP docker container to perform the headless web application scanning

Once you have installed and setup the docker engine, you can proceed to use the play ground to test the OWASP ZAP in headless mode. First, let’s run a container with a vulnerable web application named WebGoat that will serve as the scanning target:

$ docker run -t --name vulnapp -p 8080:8080 -d webgoat/webgoat-8.0:latest
$ VULNIP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' vulnapp)

The previous commands will pull the container webgoat/webgoat-8.0:latest to your docker environment, run it to serve on port 8080 of your virtual machine and the second command, will be stored in the variable VULNIP to be used later. The output should be similar to:

$ docker run -t --name vulnapp -p 8080:8080 -d webgoat/webgoat-8.0:latest
Unable to find image 'webgoat/webgoat-8.0:latest' locally
latest: Pulling from webgoat/webgoat-8.0
5e6ec7f28fb7: Pull complete 
1cf4e4a3f534: Pull complete 
5d9d21aca480: Pull complete 
0a126fb8ec28: Pull complete 
1904df324545: Pull complete 
e6d9d96381c8: Pull complete 
885c4a759329: Pull complete 
970a9918b240: Pull complete 
0320947fb529: Pull complete 
Digest: sha256:e24bcaf41034c28b6a08aba94507a169ae23f2b87899e225a3d18fe8c36d26f5
Status: Downloaded newer image for webgoat/webgoat-8.0:latest
ed5e8c6f59404c61d4d8b2bc88960dbab45d02f8e8d87a32b5e38f197fcfce15
$ VULNIP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' vulnapp)

Next, pull and run the OWASP ZAP container to scan the target vulnerable container:

$ docker run --rm -t owasp/zap2docker-stable zap-full-scan.py -t http://$VULNIP:8080/

The above command, will pull and run the OWASP ZAP container to scan the vulnerable container on port 8080. It will take some minutes to conclude and the outcome should look like:

$ docker run --rm -t owasp/zap2docker-stable zap-full-scan.py -t http://$VULNIP:8080/
2022-08-16 00:33:34,243 Could not find custom hooks file at /home/zap/.zap_hooks.py 
Total of 5 URLs
PASS: Directory Browsing [0]
PASS: Vulnerable JS Library (Powered by Retire.js) [10003]
PASS: Cookie No HttpOnly Flag [10010]
PASS: Cookie Without Secure Flag [10011]
PASS: Re-examine Cache-control Directives [10015]
PASS: Cross-Domain JavaScript Source File Inclusion [10017]
PASS: Content-Type Header Missing [10019]
PASS: Anti-clickjacking Header [10020]
PASS: X-Content-Type-Options Header Missing [10021]
PASS: Information Disclosure - Debug Error Messages [10023]
PASS: Information Disclosure - Sensitive Information in URL [10024]
PASS: Information Disclosure - Sensitive Information in HTTP Referrer Header [10025]
PASS: HTTP Parameter Override [10026]
PASS: Information Disclosure - Suspicious Comments [10027]
PASS: Open Redirect [10028]
PASS: Cookie Poisoning [10029]
PASS: User Controllable Charset [10030]
PASS: User Controllable HTML Element Attribute (Potential XSS) [10031]
PASS: Viewstate [10032]
PASS: Directory Browsing [10033]
PASS: Heartbleed OpenSSL Vulnerability (Indicative) [10034]
PASS: Strict-Transport-Security Header [10035]
PASS: HTTP Server Response Header [10036]
PASS: Server Leaks Information via "X-Powered-By" HTTP Response Header Field(s) [10037]
PASS: Content Security Policy (CSP) Header Not Set [10038]
PASS: X-Backend-Server Header Information Leak [10039]
PASS: Secure Pages Include Mixed Content [10040]
PASS: HTTP to HTTPS Insecure Transition in Form Post [10041]
PASS: HTTPS to HTTP Insecure Transition in Form Post [10042]
PASS: User Controllable JavaScript Event (XSS) [10043]
PASS: Big Redirect Detected (Potential Sensitive Information Leak) [10044]
PASS: Source Code Disclosure - /WEB-INF folder [10045]
PASS: HTTPS Content Available via HTTP [10047]
PASS: Remote Code Execution - Shell Shock [10048]
PASS: Retrieved from Cache [10050]
PASS: Relative Path Confusion [10051]
PASS: X-ChromeLogger-Data (XCOLD) Header Information Leak [10052]
PASS: Cookie without SameSite Attribute [10054]
PASS: CSP [10055]
PASS: X-Debug-Token Information Leak [10056]
PASS: Username Hash Found [10057]
PASS: GET for POST [10058]
PASS: X-AspNet-Version Response Header [10061]
PASS: PII Disclosure [10062]
PASS: Backup File Disclosure [10095]
PASS: Timestamp Disclosure [10096]
PASS: Hash Disclosure [10097]
PASS: Cross-Domain Misconfiguration [10098]
PASS: User Agent Fuzzer [10104]
PASS: Weak Authentication Method [10105]
PASS: HTTP Only Site [10106]
PASS: Httpoxy - Proxy Header Misuse [10107]
PASS: Reverse Tabnabbing [10108]
PASS: Modern Web Application [10109]
PASS: Absence of Anti-CSRF Tokens [10202]
PASS: Private IP Disclosure [2]
PASS: Anti-CSRF Tokens Check [20012]
PASS: HTTP Parameter Pollution [20014]
PASS: Heartbleed OpenSSL Vulnerability [20015]
PASS: Cross-Domain Misconfiguration [20016]
PASS: Source Code Disclosure - CVE-2012-1823 [20017]
PASS: Remote Code Execution - CVE-2012-1823 [20018]
PASS: External Redirect [20019]
PASS: Session ID in URL Rewrite [3]
PASS: Buffer Overflow [30001]
PASS: Format String Error [30002]
PASS: Integer Overflow Error [30003]
PASS: CRLF Injection [40003]
PASS: Parameter Tampering [40008]
PASS: Server Side Include [40009]
PASS: Cross Site Scripting (Reflected) [40012]
PASS: Session Fixation [40013]
PASS: Cross Site Scripting (Persistent) [40014]
PASS: Cross Site Scripting (Persistent) - Prime [40016]
PASS: Cross Site Scripting (Persistent) - Spider [40017]
PASS: SQL Injection [40018]
PASS: SQL Injection - MySQL [40019]
PASS: SQL Injection - Hypersonic SQL [40020]
PASS: SQL Injection - Oracle [40021]
PASS: SQL Injection - PostgreSQL [40022]
PASS: Possible Username Enumeration [40023]
PASS: SQL Injection - SQLite [40024]
PASS: Proxy Disclosure [40025]
PASS: Cross Site Scripting (DOM Based) [40026]
PASS: SQL Injection - MsSQL [40027]
PASS: ELMAH Information Leak [40028]
PASS: Trace.axd Information Leak [40029]
PASS: .htaccess Information Leak [40032]
PASS: .env Information Leak [40034]
PASS: Hidden File Finder [40035]
PASS: Source Code Disclosure - Git  [41]
PASS: Source Code Disclosure - SVN [42]
PASS: Source Code Disclosure - File Inclusion [43]
PASS: Script Active Scan Rules [50000]
PASS: Script Passive Scan Rules [50001]
PASS: Path Traversal [6]
PASS: Remote File Inclusion [7]
PASS: Insecure JSF ViewState [90001]
PASS: Charset Mismatch [90011]
PASS: XSLT Injection [90017]
PASS: Server Side Code Injection [90019]
PASS: Remote OS Command Injection [90020]
PASS: XPath Injection [90021]
PASS: Application Error Disclosure [90022]
PASS: XML External Entity Attack [90023]
PASS: Generic Padding Oracle [90024]
PASS: Expression Language Injection [90025]
PASS: SOAP Action Spoofing [90026]
PASS: Cookie Slack Detector [90027]
PASS: Insecure HTTP Method [90028]
PASS: SOAP XML Injection [90029]
PASS: WSDL File Detection [90030]
PASS: Loosely Scoped Cookie [90033]
PASS: Cloud Metadata Potentially Exposed [90034]
FAIL-NEW: 0     FAIL-INPROG: 0  WARN-NEW: 0     WARN-INPROG: 0  INFO: 0 IGNORE: 0       PASS: 114

The previous output only prints the status of the checks, but does not tell any findings that the OWASP ZAP found during the assessment.

In order to obtain a report from OWASP ZAP, you may run the following command to write in the current path, a report called test_report.html.

$ docker run --rm -v /tmp:/zap/wrk:rw -t owasp/zap2docker-stable zap-full-scan.py -g gen-conf -r test_report.html -t http://$VULNIP:8080/

The name of the report can be changed to anything more convenient for you. After completing the OWASP ZAP scan executed by the previous docker command, you can check the report generated with a browser like Firefox or Chrome:

OWASP ZAP Scan report open in browser

To wrap up

With the following post, I hope you can start using OWASP ZAP and get familiarised with this great and free tool. Once you’ve done additional tests and reviewed the ZAP Docker Documentation, you might want to implement on your CI/CD pipelines a testing step to run this tool and cover your web application dynamic scanning or DAST.

Finally, do not use this tool to target any other website on the internet since it is not legit. These kinds of actions should be done in your offline test environment or in a previously formally agreed corporate network for the penetration testing or assessment activities.