Skip to content

Latest commit

 

History

History

README.md

Validator - Burp Suite Extension

A Burp Suite extension for validating HTTP requests against various strategies with deduplication and persistent result tracking.

Originally scaffolded from the PortSwigger Extension Template Project; the code below is specific to this pipeline's validation/live-testing needs.

Contents

Quick Start

Build and Test

# Build the extension
./gradlew jar

# Run automated tests (headless, exits after completion)
./gradlew livetesting

# Run tests with GUI (for manual validation, stays open)
./gradlew livetestingGui

Both livetesting tasks load the freshly-built build/libs/validator.jar automatically, via a generated Burp user-config (build/livetesting-user-config.json, written by writeLiveTestingUserConfig). You do not need to register the extension in Burp by hand for tests, and the run is unaffected by whatever is registered in your personal ~/.BurpSuite config. (The Burp jar is auto-downloaded to libs/ on first run.)

Burp edition

livetesting runs on Burp Suite Community (free) or Professional. downloadBurp fetches Professional by default; pass -Dburp.product=community to fetch the free Community jar instead (delete libs/burp.jar first if switching editions). On Community, the handful of Pro-only tests (Collaborator, persistent project files, scanner issue reporting) report SKIPPED (requires Burp Suite Professional) and the suite still passes; on Professional they run in full.

Test data

livetesting validates an model_outputs_v5 corpus. It resolves which database to use in this order:

  1. -Dvalidator.db=<path> if set;
  2. ../flamer/production.db — a real corpus, if you have run flamer and it actually contains model_outputs_v5 rows;
  3. otherwise a small committed seed, built from ../flamer/seed/production-seed.sql.

So ./gradlew livetesting works from a fresh clone with no flamer run: the buildSeedDb task materializes the seed into build/seed.db via sqlite-jdbc (no sqlite3 CLI needed) and the suite runs against it. The seed is a diverse, target-agnostic subset (placeholder hosts only) plus the specific technique ids a few tests look up by id. To extend it, add rows to flamer/seed/production-seed.sql (statements are separated by lines reading exactly --STMT--).

Note: an empty flamer/production.db (e.g. from a no-op flamer run) is treated as absent — resolution skips it and falls back to the seed, so data-dependent tests still pass. The task logs which database it chose (livetesting DB: ...). (livetesting also needs a Burp jar — Community or Professional; see Burp edition.)

Testing with GUI

When running ./gradlew livetestingGui, Burp Suite will:

  1. Launch with the GUI visible
  2. Automatically run all tests when started
  3. Display results in the "Validator" tab
  4. Stay open after tests complete for manual inspection
  5. You can re-run tests by clicking the "Run Tests" button in the Validator tab

This is useful for:

  • Manual validation of test results
  • Inspecting the database state after tests
  • Debugging test failures
  • Exploring the Burp Suite interface with the extension loaded

Validation System

This extension validates HTTP requests from a SQLite database against configurable validation strategies:

  1. Read requests from model_outputs.db
  2. Normalize requests (remove body, set path to /, set host to example.com)
  3. Detect duplicates via byte-level comparison
  4. Validate using pluggable strategies
  5. Persist results with strategy name/version tracking

Available Validation Strategies

  • DummyValidationStrategy: Simple test strategy (POST=true, GET=false)
  • HackxorValidationStrategy: Sends to https://hackxor.net/, validates on HTTP 200

Test Coverage

The livetesting suite runs inside Burp (see Live testing) and, with the seed corpus above, passes from a fresh clone.

Key Development Commands

./gradlew clean          # Clean build artifacts
./gradlew build          # Build and test the extension
./gradlew jar            # Create the extension JAR file
./gradlew livetesting    # Run automated tests (headless, exits after completion)
./gradlew livetestingGui # Run tests with GUI for manual validation (stays open)

The built JAR file will be in build/libs/validator.jar and can be loaded directly into Burp Suite.

Note: compiling this extension requires bulkScan-all.jar in the project root — see Required external dependency: bulkScan below. Full livetesting also needs a Burp Suite jar (Community or Professional — see Burp edition) and is out of scope for CI; ./gradlew jar (i.e. compilation) is the runnable proof here.

Montoya API reference: https://portswigger.github.io/burp-extensions-montoya-api/javadoc/

Extension Loading in Burp

The extension's entry point is LiveTestingExtension.java, which implements Montoya's BurpExtension interface and wires up validation, live-testing, and the passive response watcher on load.

  1. Build the JAR using ./gradlew jar
  2. In Burp: Extensions > Installed > Add > Select the JAR file
  3. For quick reloading during development: Ctrl/⌘ + click the Loaded checkbox

Debug Mode

To enable the debug mode, start Burp Suite jar from libs folder with the Java VM option -Dlivetesting.debug and headless mode -Djava.awt.headless=true. Test results will be print out to the console.

To run only a specific test class, use the -Dlivetesting.class=ClassName option. This only works in headless mode with debug enabled. Example: java -Djava.awt.headless=true -Dlivetesting.debug -Dlivetesting.class=SimpleTest -jar your Burp Suite Pro jar

Live testing

Burp's Montoya API consist of only interfaces. Concrete implementation to those interfaces are only available during runtime. This makes unit testing hard. That is why this package livetesting exists. It enables the developer to write tests and execute them in the "Validator" tab when in debug mode. This is useful when hunting and reproducing bugs.

In order to write new tests, create a new class that ends with "Test", like "MyTest.java". For each test case write a public method with no parameters that returns a "TestResult". The LiveTestingTab will automatically search for such methods, invoke, check and present the results in console on headless mode.

Run tests with:

  1. Automated (headless, exits after tests): ./gradlew livetesting
  2. Manual validation (GUI, stays open): ./gradlew livetestingGui
  3. Specific test class: ./gradlew livetesting -Dlivetesting.class=MyTest

Inspecting Technique Normalization

To debug normalization issues, use the NormalizationInspectorTest:

./gradlew livetesting -Dlivetesting.class=NormalizationInspectorTest -Dinspect.id=123
./gradlew livetesting -Dlivetesting.class=NormalizationInspectorTest -Dinspect.ids=123,456,789

When you run livetesting, if the extension is loaded by Burp it will display "Extension loaded successfully". If you do not see this message within ten seconds, treat this as a test failure and ask for a human to fix it.

Required external dependency: bulkScan

This extension compiles against bulkScan-all.jar, a fat jar bundling bulkScan (a Burp bulk-scanning framework, itself dependent on the legacy Burp Extender API) together with its albinowaxUtils helper library. src/main/java/burp/BulkScanInitializer.java and src/main/java/burp/LiveTestingExtension.java reference its classes (BulkScan, BulkScanLauncher, Utilities, ConfigurableSettings, BulkUtilities, IBurpExtender, IBurpExtenderCallbacks, etc.) directly at compile time, and build.gradle.kts declares implementation(files("bulkScan-all.jar")).

The jar is not vendored in this repository (it isn't redistributable here). To build this extension:

  1. Build bulkScan-all.jar yourself (a shadow/fat jar containing bulkScan plus its dependencies), the same way you would supply your own Burp Suite Pro jar for livetesting.
  2. Place it at the project root (validator/bulkScan-all.jar) before running ./gradlew jar.

Without it, ./gradlew jar (and even ./gradlew compileJava) fails at compilation with "cannot find symbol" errors for the classes above — this is expected until the jar is supplied.

Building the JAR file

To build the JAR file, run the following command in the root directory of this project:

  • For UNIX-based systems: ./gradlew jar
  • For Windows systems: gradlew jar

If successful, the JAR file is saved to <project_root_directory>/build/libs/<project_name>.jar. If the build fails, errors are shown in the console. The project name is validator. You can change this in the settings.gradle.kts file.

Note: this requires bulkScan-all.jar to be present first — see Required external dependency: bulkScan above.

Loading the JAR file into Burp

To load the JAR file into Burp:

  1. In Burp, go to Extensions > Installed.
  2. Click Add.
  3. Under Extension details, click Select file.
  4. Select the JAR file you just built, then click Open.
  5. [Optional] Under Standard output and Standard error, choose where to save output and error messages.
  6. Click Next. The extension is loaded into Burp.
  7. Review any messages displayed in the Output and Errors tabs.
  8. Click Close.

Your extension is loaded and listed in the Burp extensions table. You can test its behavior and make changes to the code as necessary.

Reloading the JAR file in Burp

If you make changes to the code, you must rebuild the JAR file and reload your extension in Burp for the changes to take effect.

To rebuild the JAR file, follow the steps for building the JAR file.

To quickly reload your extension in Burp:

  1. In Burp, go to Extensions > Installed.
  2. Hold Ctrl or , and select the Loaded checkbox next to your extension.