Skip to content

Runner

runner.sh is the suite orchestrator that executes all numbered scripts in a suite directory in order, captures output, and records results metadata. It is installed at /opt/traffic-generator/suites/runner.sh on the VM.

Terminal window
runner.sh <suite-name> [--dry-run]

Arguments:

ArgumentRequiredDescription
suite-nameYesName of the suite directory (e.g., web-app-attacks, api-attacks)
--dry-runNoPrint what would execute without running any scripts

Examples:

Terminal window
# Run the web-app-attacks suite
/opt/traffic-generator/suites/runner.sh web-app-attacks
# Dry-run to preview api-attacks scripts
/opt/traffic-generator/suites/runner.sh api-attacks --dry-run
# Run bot simulation
/opt/traffic-generator/suites/runner.sh bot-simulation

The runner reads configuration from /opt/traffic-generator/config.env:

Terminal window
# Required: target FQDN (F5 XC load balancer domain)
TARGET_FQDN=demo.example.com
# Optional: direct origin IP for baseline testing (bypasses F5 XC)
TARGET_ORIGIN_IP=

This file is written automatically during Terraform provisioning from the target_fqdn and target_origin_ip variables. To change the target after deployment, edit this file directly on the VM.

Any variable in config.env can be overridden by exporting it before running the suite:

Terminal window
# Override target FQDN for a single run
TARGET_FQDN=staging.example.com /opt/traffic-generator/suites/runner.sh web-app-attacks
# Override via export
export TARGET_FQDN=staging.example.com
/opt/traffic-generator/suites/runner.sh web-app-attacks

The config file path itself can also be overridden:

Terminal window
CONFIG_FILE=/tmp/my-config.env /opt/traffic-generator/suites/runner.sh web-app-attacks

The --dry-run flag prints each script that would be executed without running it:

Terminal window
/opt/traffic-generator/suites/runner.sh web-app-attacks --dry-run

Output:

=== 01-sqli.sh ===
[DRY-RUN] Would execute: /opt/traffic-generator/suites/web-app-attacks/01-sqli.sh demo.example.com
=== 02-xss.sh ===
[DRY-RUN] Would execute: /opt/traffic-generator/suites/web-app-attacks/02-xss.sh demo.example.com
=== 03-command-injection.sh ===
[DRY-RUN] Would execute: /opt/traffic-generator/suites/web-app-attacks/03-command-injection.sh demo.example.com
=== 04-path-traversal.sh ===
[DRY-RUN] Would execute: /opt/traffic-generator/suites/web-app-attacks/04-path-traversal.sh demo.example.com
=== 05-nikto-scan.sh ===
[DRY-RUN] Would execute: /opt/traffic-generator/suites/web-app-attacks/05-nikto-scan.sh demo.example.com
=== 06-nuclei-scan.sh ===
[DRY-RUN] Would execute: /opt/traffic-generator/suites/web-app-attacks/06-nuclei-scan.sh demo.example.com
=== Suite Complete ===
Passed: 0 | Failed: 0 | Skipped: 6
Results: /opt/traffic-generator/results/20260425-143000-web-app-attacks

Use dry-run to verify suite structure after deployment or before running a suite against a new target.

Each suite run creates a timestamped results directory:

/opt/traffic-generator/results/<YYYYMMDD-HHMMSS>-<suite-name>/

Structure:

/opt/traffic-generator/results/20260425-143000-web-app-attacks/
meta.json
01-sqli.sh.log
02-xss.sh.log
03-command-injection.sh.log
04-path-traversal.sh.log
05-nikto-scan.sh.log
06-nuclei-scan.sh.log

Each script’s stdout and stderr are captured to a .log file named after the script.

The meta.json file records suite execution metadata:

{
"suite": "web-app-attacks",
"target": "demo.example.com",
"started": "2026-04-25T14:30:00Z",
"completed": "2026-04-25T14:45:23Z",
"status": "completed",
"passed": 5,
"failed": 1,
"skipped": 0
}
FieldDescription
suiteSuite name
targetTarget FQDN used for the run
startedUTC timestamp when the suite started
completedUTC timestamp when the suite finished
statusrunning during execution, completed when done
passedNumber of scripts that exited with code 0
failedNumber of scripts that exited with non-zero code
skippedNumber of scripts skipped (not executable or dry-run)

Each script can be executed standalone without the runner:

Terminal window
# Run a single script directly
/opt/traffic-generator/suites/web-app-attacks/01-sqli.sh demo.example.com
# Run a specific API attack
/opt/traffic-generator/suites/api-attacks/01-vampi-owasp-top10.sh demo.example.com

Scripts accept the target FQDN as the first positional argument. They do not read config.env directly — only the runner does that. When running standalone, you must pass the FQDN explicitly.

To run every suite back-to-back:

Terminal window
for suite in web-app-attacks api-attacks bot-simulation reconnaissance ssl-scanning javascript-exploits traffic-generation; do
echo "========================================="
echo "Starting suite: ${suite}"
echo "========================================="
/opt/traffic-generator/suites/runner.sh "$suite"
echo ""
done

This generates comprehensive traffic across all F5 XC security features. Expect the full run to take 45-80 minutes depending on the target’s response times.

Run suites from your local machine without maintaining an SSH session:

Terminal window
TGEN_IP=$(terraform output -raw public_ip)
# Run a single suite
ssh azureuser@${TGEN_IP} '/opt/traffic-generator/suites/runner.sh web-app-attacks'
# Run a suite with target override
ssh azureuser@${TGEN_IP} 'TARGET_FQDN=staging.example.com /opt/traffic-generator/suites/runner.sh api-attacks'
# Run in background (disconnection-safe)
ssh azureuser@${TGEN_IP} 'nohup /opt/traffic-generator/suites/runner.sh web-app-attacks > /tmp/web-app-attacks.log 2>&1 &'
# Check results later
ssh azureuser@${TGEN_IP} 'ls -la /opt/traffic-generator/results/ | tail -5'
ssh azureuser@${TGEN_IP} 'cat /opt/traffic-generator/results/$(ls -t /opt/traffic-generator/results/ | head -1)/meta.json'

For long-running suites, use nohup or tmux to prevent SSH disconnection from killing the process:

Terminal window
ssh azureuser@${TGEN_IP} 'tmux new-session -d -s traffic "/opt/traffic-generator/suites/runner.sh reconnaissance"'
# Reattach later to watch progress
ssh -t azureuser@${TGEN_IP} 'tmux attach-session -t traffic'
  1. Load configuration — Runner reads config.env (or CONFIG_FILE override), then checks for TARGET_FQDN in environment.

  2. Validate suite — Confirms the named suite directory exists under the suites directory. Lists available suites if not found.

  3. Create results directory — Creates /opt/traffic-generator/results/<timestamp>-<suite>/ and writes initial meta.json with status: running.

  4. Execute scripts — Iterates through files matching [0-9]* in the suite directory, sorted by name. Skips non-executable files. Passes TARGET_FQDN as the first argument. Captures output to <script-name>.log.

  5. Record results — Updates meta.json with completion timestamp and pass/fail/skip counts.