Deployment guide

Wapiti

This image ships Wapiti on Ubuntu 24.04 LTS, ready to scan a running web application you own for vulnerabilities from the first boot of every deployed virtual machine. Wapiti is installed from PyPI, pinned to a known release inside an isolated virtualenv, with a simple wapiti command on the path.

Wapiti is an open source dynamic application security testing (DAST) tool: a black box web vulnerability scanner. Point it at the URL of an application you own or are authorised to test and it crawls the pages and forms, then injects crafted payloads to surface real vulnerabilities: SQL injection, cross site scripting, command and code injection, path traversal, XML external entity, server side request forgery, open redirects, exposed backup files and more, reporting each finding with the exact request that triggered it.

Only scan systems you are authorised to test

Read this first. Wapiti is an offensive security tool: it actively attacks the target you point it at. Running it against a host you do not own or have written permission to test is illegal in most jurisdictions. It also breaches the acceptable use policy of every cloud provider, including Azure.

This image ships safe by default. It scans nothing on its own. There is no default target, and the scheduled scan is empty until you add one. The only scan this guide runs is against a throwaway target that the commands stand up on the machine's own loopback address (127.0.0.1). Add only your own applications, or applications you have explicit authorisation to test, to the scheduled scan.

What this appliance does and does not do

What Wapiti is good at. Wapiti answers one question with authority: does my deployed, running web application expose a vulnerability that an attacker could reach over HTTP? It drives the live application from the outside. That lets it catch issues that appear only in the deployed system, such as a reflected cross-site scripting flaw or an injectable parameter. It complements static code scanning rather than replacing it.

What Wapiti is not. Wapiti is an on-demand, black-box scanner. This image does not include, and Wapiti itself is not:

  • A static code scanner. It tests a running application over HTTP and does not read your source code.
  • A web application firewall or a runtime protection agent. It finds flaws and does not block attacks.
  • A central console, a SIEM or an agent that reports to a server.
  • A remediation engine. It reports findings, and the fix to the target application is yours to make.
  • A web interface of any kind.

Wapiti tells you that a running application exposes a flaw, and shows you the request that proves it. Fixing the application is your work, and this guide shows you the workflow.

What makes this image different

It is ready to run and has no credential. Wapiti has no user database, no network service and no credential of any kind. There is nothing to rotate and nothing to leak. You administer the machine over SSH with your own key.

The release is pinned in an isolated virtualenv. Wapiti and its Python dependencies are installed into a dedicated virtualenv. They are pinned to a known release and scanned clean of fixable vulnerabilities before the image is sealed. What you run is reproducible rather than whatever floated to the top of an index on build day.

A scheduled scan is already wired, and ships with no target. A systemd timer is ready to scan the targets you authorise and to log its reports. You get continuous coverage of applications you own with almost no configuration. It scans nothing until you add a target.

The image fails closed. The scheduled scan will not run unless first boot has completed and the scanner actually executes. Two independent safeguards enforce that on every run, not only the first.

1. Deploy the virtual machine

Deploy the image from the Azure Marketplace. This guide assumes the following defaults:

  • Size: Standard_B2s (2 vCPU, 4 GB) is sufficient and is what this image is validated on. Wapiti is a command-line tool, so size up only to scan very large applications.
  • Inbound ports: SSH (22) only. Wapiti opens no network port of its own, so nothing else needs to be open.
  • Authentication: your own SSH public key.

2. Connect to the virtual machine

ssh azureuser@<vm-ip>

On first boot, the machine verifies the scanner itself and records an instance note. That takes a moment. If you connect before first boot finishes, it is still working. Section 8 shows how to watch it.

3. Confirm Wapiti is installed

wapiti --version sudo test -f /var/lib/sac/data/wapiti-firstboot.done && echo "firstboot sentinel present" systemctl is-active wapiti-firstboot.service

You should see the pinned Wapiti version, the first-boot sentinel present, and a first-boot service that is active. Wapiti lives in an isolated virtualenv at /opt/wapiti/venv. The wapiti command on your path is a thin wrapper around it.

4. See the attack modules it loads

Wapiti runs a set of attack modules, each targeting a class of vulnerability. List them to confirm the module set loads:

wapiti --list-modules

You should see the modules Wapiti can run, including sql (SQL injection), xss (reflected cross-site scripting), exec (command and code execution), xxe (XML external entity), ssrf (server-side request forgery), redirect (open redirect), file (path traversal and file disclosure) and more. A plain scan runs the modules marked as used by default. Select a specific set with -m.

5. Prove it actually detects a vulnerability

Do not take "the scanner ran" as proof that detection works. Prove it. This step stands up a tiny, deliberately vulnerable web page on the machine's own loopback address. The page reflects a URL parameter back without escaping it, which is a textbook reflected cross-site scripting flaw. You then scan it and confirm that Wapiti reports the finding.

cat > /tmp/demo-target.py <<'PY' import sys, html from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.parse import urlparse, parse_qs class H(BaseHTTPRequestHandler): def log_message(self, *a): pass def do_GET(self): q = parse_qs(urlparse(self.path).query); name = q.get("name", [""])[0] body = (f"<html><body><p>Hello {name}</p>" "<form action='/' method='get'><input name='name'></form></body></html>").encode() self.send_response(200); self.send_header("Content-Type", "text/html") self.send_header("Content-Length", str(len(body))); self.end_headers() try: self.wfile.write(body) except Exception: pass HTTPServer(("127.0.0.1", 8231), H).serve_forever() PY python3 /tmp/demo-target.py & SRV=$!; echo "demo target running on 127.0.0.1:8231 (loopback only)" sleep 1 wapiti -u "http://127.0.0.1:8231/?name=demo" -m xss --scope url --flush-session -f json -o /tmp/demo-report.json python3 -c "import json; d=json.load(open('/tmp/demo-report.json')); v={k:x for k,x in d['vulnerabilities'].items() if x}; print('findings:', {k: len(x) for k,x in v.items()}); [print(' ', x[0]['info'], '(parameter:', x[0]['parameter'], ')') for x in v.values()]" kill "$SRV" 2>/dev/null; rm -f /tmp/demo-target.py /tmp/demo-report.json

You should see Wapiti report a Reflected Cross Site Scripting finding on the name parameter. That is Wapiti's core job: it found a real flaw in the running application from the outside, over HTTP, and named the parameter that carries it.

6. Scan your own application

To scan an application you own or are authorised to test, point Wapiti at its URL and write a report. A full scan runs the default module set and produces an HTML report that you can open in a browser:

# Replace the URL with YOUR OWN application, or one you are authorised to test. wapiti -u https://your-app.example/ -f html -o ~/wapiti-report.html

Useful flags:

  • -m xss,sql,exec restricts the scan to a chosen set of modules.
  • --scope domain lets the crawler follow links across the whole domain rather than a single page.
  • -d 3 sets how deep the crawler follows links.
  • --flush-session starts a fresh scan rather than resuming.

Run wapiti --help for the full set. Wapiti keeps its scan session under ~/.wapiti, so you can resume a long scan if it is interrupted.

7. The scheduled scan

A systemd timer can scan a set of target URLs that you configure, and it writes each report to /var/log/wapiti/. This gives you continuous coverage of applications you own. It ships with no target configured, so it scans nothing until you add one.

systemctl is-active wapiti-scan.timer
systemctl list-timers wapiti-scan.timer --no-pager | sed -n '1,3p'
sudo sed -n '1,12p' /etc/wapiti/targets.conf

To enable the scheduled scan, add one target URL per line to /etc/wapiti/targets.conf. Use only hosts you own or are authorised to test. The next commands add a target, run the scheduled scan immediately instead of waiting for the timer, and show the tail of its log:

# Add ONLY hosts you are authorised to test, one URL per line.
echo "https://your-app.example/" | sudo tee -a /etc/wapiti/targets.conf
sudo systemctl start wapiti-scan.service
sudo tail -n 20 /var/log/wapiti/scan.log

8. First boot and troubleshooting

The wapiti-firstboot.service unit handles first boot. It verifies the scanner on this machine and writes the instance note at /root/wapiti-instance.txt. To check its status and read the note:

systemctl status wapiti-firstboot.service --no-pager | sed -n '1,8p'
sudo sed -n '1,14p' /root/wapiti-instance.txt

If first boot did not complete, for example because the machine lost power part-way through, re-run it:

# Re-run first boot if it did not complete.
sudo systemctl restart wapiti-firstboot.service

The scheduled scan refuses to run until first boot has completed and the scanner executes. A machine that has not finished first boot therefore never presents a scan that silently ran nothing.

9. Licensing

Wapiti is licensed under the GNU General Public License, version 2, and is installed unmodified from PyPI (the wapiti3 distribution). The licence text is shipped on the image at /usr/share/doc/sac/WAPITI-LICENSE.txt.

The GPL is a copyleft licence, so the image also ships a written offer for the corresponding source, along with the exact command to fetch it, at /usr/share/doc/sac/WAPITI-GPL-2-WRITTEN-OFFER.txt. The exact resolved dependency set is recorded at /usr/share/doc/sac/wapiti-pip-freeze.txt.

The underlying Ubuntu operating system and its system Python are installed from Ubuntu's public apt archive. They stay patchable through the normal unattended-upgrades path for the life of the release.

Support

Every SecureAnyCloud deployment is backed by 24/7 support. If you have any questions about this image, contact us at sales@secureanycloud.com.

Deploy on Azure

Launch Wapiti on Ubuntu 24.04 LTS by SecureAnyCloud with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure