How to Implement a Custom Response Filter Using the `-x` Option in Patator

To implement a custom response filter in Patator, extend the Response_Base class to expose your data, register a new condition keyword in available_conditions, and implement a match_<keyword> method that evaluates the filter logic against module responses.

Patator's flexible brute-forcing framework allows you to define custom response filters using the -x option, which attaches actions like ignore, retry, or skip to conditions evaluated against execution results. This guide walks through the lanjelot/patator source code to show you how to extend the built-in filtering system with your own conditions.

Understanding Patator's Action-Condition Framework

The -x option uses a simple syntax: action:condition=value. For example, -x ignore:code=404 tells Patator to ignore responses with HTTP status 404. This framework relies on three core components in src/patator/patator.py:

  • Command-line parsing: The Controller.usage_parser() method (lines 814-822) defines the -x option syntax as actions:conditions.
  • Action storage: Controller.update_actions() (lines 1011-1030) parses the actions portion and stores conditions in self.ns.actions.
  • Condition evaluation: Controller.lookup_actions() (lines 1034-1046) iterates through stored actions and evaluates conditions by calling resp.match(key, val) on the Response object.

The Response_Base class (lines 1530-1563) serves as the foundation for all response filtering. It maintains an available_conditions tuple that registers valid filter keywords and implements a generic match() dispatcher (around line 1580) that routes condition checks to specific match_<keyword> methods.

Step-by-Step Implementation Guide

Step 1: Expose Data in the Module Response Class

First, modify the module's Response subclass to capture the data you want to filter. Each module (e.g., HTTP, FTP, SSH) defines its own Response class inheriting from Response_Base.

For example, to filter based on the HTTP Server header, add a server attribute to the HTTP module's response class:


# Inside the HTTP module (e.g., src/patator/http.py)

class Response(Response_Base):
    def __init__(self, code, mesg, timing=0, trace=None, server=None):
        super().__init__(code, mesg, timing, trace)
        self.server = server  # New attribute for custom filtering

Ensure this attribute is populated when the module creates the response object during execution.

Step 2: Register the New Condition Keyword

Add your condition to available_conditions in the Response_Base class definition (around line 1556 in patator.py):

class Response_Base:
    available_conditions = (
        ('code',  'match status code'),
        ('size',  'match size (N or N-M or N- or -N)'),
        ('time',  'match time (N or N-M or N- or -N)'),
        ('mesg',  'match message'),
        ('fgrep', 'search for string in mesg'),
        ('egrep', 'search for regex in mesg'),
        ('server','match Server header'),   # <-- Your new condition

    )

Registration is mandatory—Patator only accepts conditions listed in this tuple when parsing the -x argument.

Step 3: Implement the Matching Logic

Implement a match_<keyword> method in Response_Base to handle the comparison logic. The method receives the value from the command line and returns a boolean:


# In Response_Base class, following existing match methods (around line 1596)

def match_server(self, val):
    """Match the Server header against a substring pattern."""
    return self.server and val in self.server

You can implement complex logic here—regex matching, numeric ranges, or case-insensitive comparisons—depending on your filtering requirements. The match() dispatcher automatically calls this method when it encounters the server keyword.

Step 4: Use the Custom Filter

Invoke your custom filter from the command line using the standard -x syntax:

patator http_fuzz url=http://target.com/FUZZ \
         -x ignore:server=nginx \
         0=wordlist.txt

This configuration ignores any response where the Server header contains "nginx". You can combine multiple conditions using commas: -x ignore:code=404,server=apache.

Code Reference and Architecture

Understanding these specific source locations helps when debugging or extending filters:

  • Option definition: Controller.usage_parser() at line 814 adds the -x flag and builds help text.
  • Action parsing: Controller.update_actions() at line 1011 separates actions from conditions.
  • Condition lookup: Controller.lookup_actions() at line 1034 triggers resp.match().
  • Built-in conditions: Defined in Response_Base.available_conditions at line 1556.
  • Dispatch mechanism: Response_Base.match() at line 1580 routes to match_<keyword> methods.

Module-specific response classes inherit from Response_Base and can override available_conditions or add module-specific match methods, though registering conditions in the base class makes them available globally.

Summary

  • Extend Response_Base: Add your data attribute to the module's Response class constructor.
  • Register the keyword: Append a tuple to available_conditions in Response_Base to enable parsing.
  • Implement match_<keyword>: Create the evaluation method that returns True when the condition matches.
  • Execute with -x: Use the syntax action:keyword=value (e.g., -x ignore:server=nginx) to activate your filter.

This architecture allows you to filter on any response attribute—from HTTP headers and LDAP error codes to custom protocol fields—without modifying Patator's core execution logic.

Frequently Asked Questions

What is the syntax for the -x option in Patator?

The -x option accepts a string in the format actions:conditions, where actions are comma-separated keywords like ignore, retry, or stop, and conditions use the syntax keyword=value. Multiple condition pairs can be chained with commas: -x ignore:code=200,size=0. The Controller.update_actions() method at line 1011 parses this string into actionable tuples.

Where are the built-in conditions defined in Patator?

Built-in conditions are defined in the available_conditions class attribute of Response_Base at line 1556 in src/patator/patator.py. The default conditions include code (status code), size (response size), time (execution time), mesg (message text), fgrep (substring search), and egrep (regex search). Each condition has a corresponding match_<keyword> method that implements the comparison logic.

Can I use regex patterns in custom response filters?

Yes. While the example above uses simple substring matching, you can implement regex matching by importing the re module and using re.search() inside your match_<keyword> method. The built-in egrep condition demonstrates this pattern in the source code. Ensure your method handles cases where the attribute might be None to avoid attribute errors during execution.

How do I debug a custom filter that isn't matching?

First, verify that your condition keyword appears in Response_Base.available_conditions and that your module's Response class actually populates the attribute you're filtering on. You can temporarily add debug prints to your match_<keyword> method to inspect the self object's attributes. Also confirm that the -x syntax uses the exact keyword you registered—Patator's lookup_actions() method silently skips unrecognized conditions rather than throwing errors.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →