RedAmon - Resource Enumeration Module

August 10, 2026 · View on GitHub

Complete Technical Documentation

Module: recon/resource_enum.py Purpose: Endpoint discovery, classification, and parameter extraction Author: RedAmon Security Suite


Table of Contents

  1. Overview
  2. Features
  3. Installation
  4. Configuration Parameters
  5. GAU Configuration
  6. Kiterunner Configuration
  7. Hakrawler Configuration
  8. jsluice Configuration
  9. Architecture & Flow
  10. Output Data Structure
  11. Endpoint Classification
  12. Parameter Classification
  13. Form Parsing
  14. Usage Examples
  15. Troubleshooting

Overview

The resource_enum.py module provides comprehensive endpoint discovery and classification for web applications. It combines active crawling (Katana + Hakrawler), passive historical URL discovery (GAU), passive parameter mining (ParamSpider), API bruteforcing (Kiterunner), JavaScript analysis (jsluice), directory fuzzing (FFuf), and hidden parameter discovery (Arjun) to maximize endpoint coverage, extracts parameters, parses HTML forms, discovers embedded secrets, and organizes everything into a structured format ready for vulnerability scanning.

Pipeline Position: GROUP 5 in the parallelized pipeline (GROUP 4: http_probe -> GROUP 5: resource_enum -> GROUP 6: vuln_scan). Katana, Hakrawler, GAU, ParamSpider, and Kiterunner run concurrently via internal ThreadPoolExecutor. jsluice runs sequentially after crawling to analyze discovered JavaScript files. FFuf runs after jsluice to brute-force directory paths using wordlists. Arjun runs after FFuf to discover hidden parameters on discovered endpoints, with multiple methods (GET/POST/JSON/XML) executing in parallel.

Why Resource Enumeration?

FeatureWithout resource_enumWith resource_enum
Endpoint DiscoveryManual or basicAutomated crawling + passive + API bruteforce
Historical URLsMissedGAU finds old/deleted endpoints
Hidden APIsMissedKiterunner finds undocumented APIs
POST EndpointsMissedForm parsing
Parameter ExtractionNoneFull extraction
Endpoint ClassificationNoneCategorized
Parameter TypesUnknownInferred
Vulnerability CoverageLimitedComprehensive

How It Works

┌─────────────────┐     ┌────────────────────────────────────────────────┐     ┌─────────────────┐
│  http_probe     │────▶│              resource_enum                      │────▶│  js_recon (5b)  │────▶│  vuln_scan      │
│  (live URLs,    │     │                                                │     │  (targeted      │
│   responses)    │     │  ┌────────────┐ ┌────────────┐ ┌─────────────┐ │     │   scanning)     │
└─────────────────┘     │  │  Katana    │ │    GAU     │ │ Kiterunner  │ │     └─────────────────┘
                        │  │  (active)  │ │  (passive) │ │ (API brute) │ │
                        │  │            │ │            │ │             │ │
                        │  │ Crawl site │ │ Query:     │ │ Bruteforce: │ │
                        │  │ Parse JS   │ │ - Wayback  │ │ - 40k+ APIs │ │
                        │  │ Find forms │ │ - CommonCrl│ │ - Swagger   │ │
                        │  └─────┬──────┘ │ - OTX      │ │ - OpenAPI   │ │
                        │        │        │ - URLScan  │ └──────┬──────┘ │
                        │        │        └─────┬──────┘        │        │
                        │        └───────────┬──┴───────────────┘        │
                        │                    ▼                           │
                        │  ┌──────────────────────────────────────────┐  │
                        │  │  Merge & Deduplicate                     │  │
                        │  │  + Source tracking (sources array)       │  │
                        │  │  + Endpoint Classification               │  │
                        │  └──────────────────────────────────────────┘  │
                        └────────────────────────────────────────────────┘

Features

FeatureDescription
Katana CrawlingDeep endpoint discovery using ProjectDiscovery's Katana (active)
GAU DiscoveryHistorical URL discovery from Wayback, CommonCrawl, OTX, URLScan (passive)
Kiterunner API BruteforceHidden API discovery using 40k+ Swagger/OpenAPI specifications
Hakrawler CrawlingDOM-aware web crawling via Docker (active)
jsluice JS AnalysisJavaScript analysis to extract URLs, endpoints, and secrets (downloads JS files from target)
FFuf Directory FuzzingBrute-force directory/endpoint discovery using wordlists (built-in SecLists + custom uploads)
ParamSpider Parameter MiningPassive Wayback Machine CDX query for parameterized URLs — returns only URLs with query parameters, values replaced by placeholder (FUZZ)
Arjun Parameter DiscoveryDiscovers hidden HTTP query/body parameters on discovered endpoints using ~25,000 parameter names. Multi-method parallel execution (GET/POST/JSON/XML)
Parallel ExecutionKatana, Hakrawler, GAU, ParamSpider, and Kiterunner run simultaneously, then jsluice → FFuf → Arjun sequential (Arjun methods run in parallel internally)
URL VerificationVerifies GAU URLs are live before adding to results
Method DetectionOPTIONS probe detects allowed HTTP methods (GET, POST, PUT, DELETE)
Dead Endpoint FilteringFilters out endpoints that don't respond (404, 500, timeout)
JavaScript ParsingDiscovers endpoints in JavaScript files
Form ExtractionParses HTML forms for POST endpoints
Parameter ExtractionExtracts query and body parameters
Type InferenceInfers parameter data types (integer, email, URL, etc.)
Endpoint ClassificationCategorizes endpoints (auth, api, admin, file_access, etc.)
Parameter ClassificationIdentifies sensitive params (id, file, auth, redirect, command)
Source TrackingEach endpoint tracked with sources array: ["katana", "hakrawler", "gau", "paramspider", "kiterunner", "jsluice", "arjun"]
Docker ExecutionRuns via Docker for consistency
Incremental OutputSaves results as crawling progresses

Installation

Requirements

  • Docker installed and running
  • Previous pipeline steps completed (http_probe)

Setup

# Make sure Docker is running
sudo systemctl start docker

# Run the scan - image will be pulled automatically
python3 recon/main.py

Verify Docker is Ready

# Check Docker is running
docker info

# Optionally pre-pull the images
docker pull projectdiscovery/katana:latest
docker pull sxcurity/gau:latest
# Kiterunner binary is auto-downloaded from GitHub releases (no Docker needed)
docker pull projectdiscovery/httpx:latest  # For URL verification

Configuration Parameters

All parameters are configured via the webapp project settings (stored in PostgreSQL) or as defaults in project_settings.py.


1. Core Katana Configuration

ParameterTypeDefaultDescription
KATANA_DOCKER_IMAGEstr"projectdiscovery/katana:latest"Docker image to use
KATANA_DEPTHint3Maximum crawl depth (how many links deep to follow)
KATANA_MAX_URLSint1000Maximum URLs to discover per target
KATANA_RATE_LIMITint150Requests per second
KATANA_TIMEOUTint300Maximum crawl time in seconds (5 minutes)

Depth Tuning Guide:

DepthUse CaseCoverageTime
1Quick scan, homepage onlyLowFast
2Standard reconnaissanceMediumModerate
3Default - balanced coverageGood~5 min
5+Deep analysis, large sitesComprehensiveLong

2. Crawl Behavior

ParameterTypeDefaultDescription
KATANA_JS_CRAWLboolTrueParse JavaScript files for endpoints
KATANA_PARAMS_ONLYboolFalseOnly keep URLs with query parameters
KATANA_SCOPEstr"rdn"Scope: rdn (root domain), dn (domain), fqdn (full)

Scope Options:

ScopeDescriptionExample
rdnRoot domain and all subdomains*.example.com
dnExact domain onlywww.example.com
fqdnExact FQDN onlywww.example.com (no subdomains)

3. Filtering

ParameterTypeDefaultDescription
KATANA_EXCLUDE_PATTERNSlistSee belowURL patterns to exclude
KATANA_CUSTOM_HEADERSlist[]Custom HTTP headers

Default Exclude Patterns:

KATANA_EXCLUDE_PATTERNS = [
    # Next.js / React
    "/_next/image",          # Image optimization
    "/_next/static",         # Static assets

    # WordPress
    "/wp-content/uploads",   # Media uploads
    "/wp-includes",          # Core files

    # Common static
    "/static/",              # Static directories
    "/assets/",              # Asset directories
    ".css", ".js",           # Stylesheets, scripts
    ".jpg", ".png", ".gif",  # Images
    ".woff", ".ttf",         # Fonts
]

4. Performance Profiles

Fast Mode (Quick Recon)

KATANA_DEPTH = 2
KATANA_MAX_URLS = 500
KATANA_RATE_LIMIT = 200
KATANA_TIMEOUT = 120
KATANA_JS_CRAWL = False
KATANA_PARAMS_ONLY = True

Expected: ~1-2 minutes per target

Balanced Mode (Default)

KATANA_DEPTH = 3
KATANA_MAX_URLS = 1000
KATANA_RATE_LIMIT = 150
KATANA_TIMEOUT = 300
KATANA_JS_CRAWL = True
KATANA_PARAMS_ONLY = False

Expected: ~3-5 minutes per target

Deep Analysis Mode

KATANA_DEPTH = 5
KATANA_MAX_URLS = 5000
KATANA_RATE_LIMIT = 100
KATANA_TIMEOUT = 600
KATANA_JS_CRAWL = True
KATANA_PARAMS_ONLY = False

Expected: ~10-15 minutes per target


GAU Configuration

GAU (GetAllUrls) provides passive URL discovery from historical archives. It runs in parallel with Katana.

1. Core GAU Settings

ParameterTypeDefaultDescription
GAU_ENABLEDboolTrueEnable/disable GAU discovery
GAU_DOCKER_IMAGEstr"sxcurity/gau:latest"Docker image to use
GAU_PROVIDERSlist["wayback", "commoncrawl", "otx", "urlscan"]Data sources to query
GAU_MAX_URLSint1000Maximum URLs per domain (0 = unlimited)
GAU_TIMEOUTint60Timeout per provider in seconds
GAU_THREADSint5Parallel threads for fetching

2. GAU Data Sources

ProviderDescriptionURL Type
waybackWayback Machine (web.archive.org)Historical snapshots
commoncrawlCommon Crawl (index.commoncrawl.org)Web crawl data
otxAlienVault OTXThreat intelligence
urlscanURLScan.ioSecurity scan results

3. Filtering Options

ParameterTypeDefaultDescription
GAU_BLACKLIST_EXTENSIONSlistSee belowFile extensions to exclude
GAU_YEAR_RANGElist[]Filter by year range, e.g., ["2020", "2024"]

Default Blacklisted Extensions:

GAU_BLACKLIST_EXTENSIONS = [
    "png", "jpg", "jpeg", "gif", "svg", "ico", "webp", "avif",
    "css", "woff", "woff2", "ttf", "eot", "otf",
    "mp3", "mp4", "avi", "mov", "wmv", "flv", "webm",
    "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx",
    "zip", "rar", "7z", "tar", "gz"
]

4. URL Verification

GAU URLs are verified to check if they're still live before adding to results.

ParameterTypeDefaultDescription
GAU_VERIFY_URLSboolTrueEnable HTTP verification
GAU_VERIFY_DOCKER_IMAGEstr"projectdiscovery/httpx:latest"httpx image for verification
GAU_VERIFY_TIMEOUTint5Timeout per URL in seconds
GAU_VERIFY_RATE_LIMITint100Requests per second
GAU_VERIFY_THREADSint50Concurrent verification threads
GAU_VERIFY_ACCEPT_STATUSlist[200, 201, 301, 302, 307, 308, 401, 403]HTTP status codes to accept

5. HTTP Method Detection (OPTIONS Probe)

GAU doesn't know which HTTP methods an endpoint supports. This feature uses the OPTIONS HTTP method to detect allowed methods from the server's Allow header.

ParameterTypeDefaultDescription
GAU_DETECT_METHODSboolTrueEnable OPTIONS probe for method detection
GAU_METHOD_DETECT_TIMEOUTint5Timeout per URL in seconds
GAU_METHOD_DETECT_RATE_LIMITint50Requests per second
GAU_METHOD_DETECT_THREADSint25Concurrent threads
GAU_FILTER_DEAD_ENDPOINTSboolTrueFilter out endpoints that don't respond

How It Works:

  1. Send OPTIONS request to each verified GAU URL
  2. Parse Allow header from response (e.g., Allow: GET, POST, PUT, DELETE)
  3. If no Allow header, fall back to GET check
  4. Filter out dead endpoints (404, 500, timeout)
  5. Store detected methods in endpoint data

Example Output:

{
  "/api/users": {
    "methods": ["GET", "POST", "PUT", "DELETE"],
    "source": "gau"
  },
  "/login": {
    "methods": ["GET", "POST"],
    "source": "gau"
  }
}

Why This Matters:

  • Katana can detect methods from form parsing (e.g., <form method="POST">)
  • GAU only returns URLs - no method info
  • OPTIONS probe discovers POST/PUT/DELETE endpoints that would otherwise be missed
  • Dead endpoints (404/500) are filtered out to reduce noise

6. GAU Configuration Profiles

Minimal (Fast)

GAU_ENABLED = True
GAU_PROVIDERS = ["wayback"]  # Single source
GAU_MAX_URLS = 500
GAU_VERIFY_URLS = False  # Skip verification
GAU_DETECT_METHODS = False  # Skip method detection

Expected: ~10-20 seconds per domain

Balanced (Default)

GAU_ENABLED = True
GAU_PROVIDERS = ["wayback", "commoncrawl", "otx", "urlscan"]
GAU_MAX_URLS = 1000
GAU_VERIFY_URLS = True
GAU_DETECT_METHODS = True
GAU_FILTER_DEAD_ENDPOINTS = True

Expected: ~30-60 seconds per domain

Comprehensive

GAU_ENABLED = True
GAU_PROVIDERS = ["wayback", "commoncrawl", "otx", "urlscan"]
GAU_MAX_URLS = 5000
GAU_YEAR_RANGE = []  # All years
GAU_VERIFY_URLS = True
GAU_DETECT_METHODS = True
GAU_FILTER_DEAD_ENDPOINTS = True

Expected: ~2-5 minutes per domain

7. What GAU Finds

CategoryExamplesWhy It Matters
Old Admin Panels/admin/, /wp-admin/, /administrator/May still be accessible
Debug Endpoints/phpinfo.php, /debug/, /test/Information disclosure
Backup Files/backup.sql, /db_dump.sql, /config.bakSensitive data
Old API Versions/api/v1/, /api/beta/May have unpatched vulns
Hidden Parameters?debug=1, ?admin=trueBypass security
Forgotten Uploads/uploads/temp/, /files/old/Sensitive files

Kiterunner Configuration

Kiterunner provides API endpoint bruteforcing using real Swagger/OpenAPI specifications. It runs in parallel with Katana and GAU.

1. Core Kiterunner Settings

ParameterTypeDefaultDescription
KITERUNNER_ENABLEDboolTrueEnable/disable Kiterunner discovery
(Binary auto-download)-~/.redamon/tools/kiterunner/krAuto-downloaded from GitHub releases
KITERUNNER_WORDLISTstr"apiroutes-251227"Wordlist (354k+ API routes)
KITERUNNER_RATE_LIMITint100Requests per second
KITERUNNER_CONNECTIONSint100Concurrent connections
KITERUNNER_TIMEOUTint10Request timeout per endpoint (seconds)
KITERUNNER_SCAN_TIMEOUTint300Overall scan timeout (seconds)
KITERUNNER_THREADSint50Scanning threads

2. Kiterunner Wordlists

Run kr wordlist list to see all available wordlists.

WordlistDescriptionRoutes
apiroutes-251227Comprehensive API routes (default)354,000+
aspx-251227ASP.NET specific routes~82,000
jsp-251227JSP/Java specific routes~21,000
php-251227PHP specific routes~178,000
directories-251227Directory discovery~703,000
Custom pathYour own wordlistVariable

3. Filtering Options

ParameterTypeDefaultDescription
KITERUNNER_IGNORE_STATUSlist[404, 400, 502, 503]Status codes to ignore
KITERUNNER_MATCH_STATUSlist[]Only match these status codes (empty = all)
KITERUNNER_MIN_CONTENT_LENGTHint0Ignore responses smaller than this
KITERUNNER_HEADERSlist[]Custom headers for authenticated scanning

4. Kiterunner Configuration Profiles

Minimal (Fast)

KITERUNNER_ENABLED = True
KITERUNNER_WORDLIST = "apiroutes-251227"
KITERUNNER_RATE_LIMIT = 200
KITERUNNER_SCAN_TIMEOUT = 120

Expected: ~1-2 minutes per target

Balanced (Default)

KITERUNNER_ENABLED = True
KITERUNNER_WORDLIST = "apiroutes-251227"
KITERUNNER_RATE_LIMIT = 100
KITERUNNER_CONNECTIONS = 100
KITERUNNER_SCAN_TIMEOUT = 300

Expected: ~3-5 minutes per target

Comprehensive (Stealth)

KITERUNNER_ENABLED = True
KITERUNNER_WORDLIST = "apiroutes-251227"
KITERUNNER_RATE_LIMIT = 50
KITERUNNER_CONNECTIONS = 50
KITERUNNER_SCAN_TIMEOUT = 600

Expected: ~5-10 minutes per target

5. What Kiterunner Finds

CategoryExamplesWhy It Matters
Hidden REST APIs/api/v1/users, /api/admin/configUndocumented functionality
GraphQL Endpoints/graphql, /gql, /api/graphqlComplex query surface
Internal APIs/internal/, /private/, /debug/Bypass access controls
Version Endpoints/version, /health, /statusInformation disclosure
CRUD Operations/users/create, /posts/deleteData manipulation
Swagger/OpenAPI/swagger.json, /api-docsAPI documentation exposure

6. Why Kiterunner Over Traditional Wordlists?

FeatureTraditional WordlistsKiterunner
Route coverageLimited to common paths40k+ real API routes
HTTP MethodsUsually GET onlyCorrect method per route
ParametersNoneSwagger-defined params
HeadersNoneAPI-specific headers
False positivesMany 404sValidated responses

Hakrawler Configuration

Hakrawler is a DOM-aware web crawler that runs as a Docker container (jauderho/hakrawler). It runs in parallel with Katana, GAU, and Kiterunner, providing an additional crawling perspective with scope-aware link following.

1. Core Hakrawler Settings

ParameterTypeDefaultDescription
HAKRAWLER_ENABLEDboolTrueEnable/disable Hakrawler crawling
HAKRAWLER_DOCKER_IMAGEstr"jauderho/hakrawler:latest"Docker image to use
HAKRAWLER_DEPTHint2Crawl depth (how many links deep to follow)
HAKRAWLER_THREADSint5Concurrent threads
HAKRAWLER_TIMEOUTint30Per-URL timeout in seconds
HAKRAWLER_MAX_URLSint500Maximum URLs to discover
HAKRAWLER_INCLUDE_SUBSboolTrueInclude subdomains in crawl scope
HAKRAWLER_INSECUREboolTrueSkip TLS certificate verification
HAKRAWLER_CUSTOM_HEADERSlist[]Custom HTTP headers

2. Scope Filtering

Hakrawler scope filtering works at two levels:

LevelMechanismDescription
Crawl scope-subs flagIf INCLUDE_SUBS=True, Hakrawler follows links to subdomains of the target
Output scopeHostname exact matchAfter crawling, results are filtered against target_domains set (from http_probe). URLs with hostnames not in scope are captured as ExternalDomain nodes instead of Endpoint nodes

3. What Hakrawler Finds

CategoryExamplesWhy It Matters
DOM links<a href="...">, <link>, <script src>Links that JS-rendered crawlers may miss
Form actions<form action="/submit">POST endpoints for parameter fuzzing
Asset referencesCSS imports, image URLs, font filesReveals directory structure
Subdomain linksLinks pointing to api.example.comDiscovers related subdomains
External domainsLinks to third-party servicesMaps external dependencies

4. Stealth Mode

When STEALTH_MODE is enabled, Hakrawler is automatically disabled to reduce the active crawling footprint. jsluice max files is reduced to 20.


jsluice Configuration

jsluice is a JavaScript analysis tool compiled into the recon container (no Docker image needed). It downloads JavaScript files already discovered by Katana/Hakrawler from the target and analyzes their contents locally to extract URLs, API endpoints, and embedded secrets.

1. Core jsluice Settings

ParameterTypeDefaultDescription
JSLUICE_ENABLEDboolTrueEnable/disable jsluice analysis
JSLUICE_MAX_FILESint50Maximum number of JS files to analyze
JSLUICE_TIMEOUTint120Overall timeout in seconds
JSLUICE_CONCURRENCYint5Files to process concurrently
JSLUICE_EXTRACT_URLSboolTrueRun URL extraction mode
JSLUICE_EXTRACT_SECRETSboolTrueRun secret detection mode

2. How jsluice Works

jsluice sends HTTP requests to download each JS file from the target, then analyzes them locally:

  1. Filter: Selects .js and .mjs URLs from all URLs discovered by Katana/Hakrawler/GAU
  2. Download: Fetches JS files to a temporary directory (/tmp/redamon/jsluice_<pid>/)
  3. Analyze URLs: Runs jsluice urls to extract embedded URLs and API endpoints
  4. Analyze Secrets: Runs jsluice secrets to detect API keys, tokens, credentials
  5. Scope filter: Extracted URLs are filtered against allowed_hosts; out-of-scope URLs become ExternalDomain nodes
  6. Cleanup: Temporary files are deleted in a finally block

3. What jsluice Finds

URL Extraction:

CategoryExamplesWhy It Matters
API endpoints/api/v2/users, /graphqlHidden backend routes
Internal URLs/admin/config, /debug/varsUndocumented functionality
External serviceshttps://api.stripe.com/v1/chargesThird-party integrations
CDN/asset paths/static/js/, /assets/Directory structure

Secret Detection:

Secret TypeExamplesSeverity
AWS Access KeysAKIA...High
GitHub Tokensghp_..., gho_...High
GCP CredentialsAIza...High
API KeysGeneric API key patternsMedium
Private Keys-----BEGIN RSA PRIVATE KEY-----High
JWT TokenseyJ...Medium

Discovered secrets are stored as Secret nodes in Neo4j, linked to their parent BaseURL via [:HAS_SECRET].

4. jsluice in the Pipeline

jsluice runs sequentially after the parallel crawling phase (Katana + Hakrawler + GAU + Kiterunner), because it needs their discovered URLs as input. It adds minimal time since JS file analysis is CPU-bound (no network scanning).


Architecture & Flow

Pipeline context: Resource enumeration runs in GROUP 5 of the parallelized recon pipeline, after HTTP probing (GROUP 4). The four discovery tools (Katana, Hakrawler, GAU, Kiterunner) run concurrently via an internal ThreadPoolExecutor. jsluice then runs sequentially on discovered JS files. Graph DB updates happen in a background thread.

Execution Flow

1. INITIALIZATION
   └── Check Docker availability
   └── Pull Katana + GAU + Kiterunner images in parallel

2. TARGET EXTRACTION
   └── Get live URLs from http_probe
   └── Extract domains for GAU
   └── Filter by status code (< 500)
   └── Fallback to DNS data if no http_probe

3. PARALLEL DISCOVERY (Katana + Hakrawler + GAU + Kiterunner)
   ┌───────────────────────────────────────────────────────────────────────────┐
   │  ThreadPoolExecutor (max_workers=4)                                       │
   │                                                                           │
   │  ┌───────────┐  ┌────────────┐  ┌───────────┐  ┌────────────────────┐    │
   │  │  KATANA   │  │ HAKRAWLER  │  │    GAU    │  │    KITERUNNER      │    │
   │  │  (active) │  │  (active)  │  │ (passive) │  │    (API brute)     │    │
   │  │           │  │            │  │           │  │                    │    │
   │  │ - Crawl   │  │ - DOM-walk │  │ - Wayback │  │ - Swagger specs    │    │
   │  │ - Parse JS│  │ - Docker   │  │ - CmnCrl  │  │ - 40k+ API routes  │    │
   │  │ - Find URL│  │ - Scope    │  │ - OTX     │  │ - Method detection │    │
   │  │           │  │            │  │ - URLScan │  │                    │    │
   │  └─────┬─────┘  └─────┬──────┘  └─────┬─────┘  └─────────┬──────────┘    │
   │        │               │               │                  │               │
   └────────┴───────────────┴───────────────┴──────────────────┴───────────────┘


3b. JSLUICE ANALYSIS (sequential, after parallel discovery)
   └── Filter discovered URLs to .js/.mjs files
   └── Download JS files to /tmp/redamon/jsluice_<pid>/
   └── Run jsluice urls (extract endpoints)
   └── Run jsluice secrets (detect API keys, tokens, credentials)
   └── Scope-filter extracted URLs
   └── Cleanup temp files

4. GAU URL VERIFICATION (if enabled)
   └── Write GAU URLs to temp file
   └── Run httpx Docker for verification
   └── Filter to live URLs only

5. METHOD DETECTION (if enabled)
   └── Send OPTIONS request to each verified URL
   └── Parse 'Allow' header for supported methods
   └── Fall back to GET check if OPTIONS fails
   └── Filter out dead endpoints (404/500/timeout)

6. MERGE & DEDUPLICATE
   └── Mark Katana endpoints with sources=['katana']
   └── Merge Hakrawler URLs, add 'hakrawler' to sources array
   └── Merge GAU URLs, add 'gau' to sources array
   └── Merge Kiterunner APIs, add 'kiterunner' to sources array
   └── Merge jsluice URLs, add 'jsluice' to sources array
   └── Apply detected methods to endpoints
   └── Track overlap statistics for each tool

7. FORM PARSING
   └── Extract HTML from http_probe responses
   └── Parse <form> elements
   └── Extract action URLs and methods
   └── Extract input fields

8. ENDPOINT ORGANIZATION
   └── Group by base URL
   └── Parse query parameters
   └── Merge form data
   └── Classify endpoints
   └── Classify parameters

9. OUTPUT GENERATION
   └── Build structured JSON
   └── Include GAU + Hakrawler + Kiterunner + jsluice stats
   └── Generate summary statistics
   └── Save to recon file

Data Flow Diagram

┌──────────────────────────────────────────────────────────────────┐
│                        http_probe data                           │
│  ┌────────────────┐  ┌────────────────┐  ┌────────────────┐     │
│  │ live URLs      │  │ response bodies │  │ status codes   │     │
│  │ (for crawling) │  │ (for forms)     │  │ (filtering)    │     │
│  └───────┬────────┘  └───────┬────────┘  └───────┬────────┘     │
└──────────┼───────────────────┼───────────────────┼──────────────┘
           │                   │                   │
           ▼                   ▼                   │
    ┌──────────────┐    ┌──────────────┐          │
    │ Katana       │    │ Form Parser  │          │
    │ Crawler      │    │              │          │
    └──────┬───────┘    └──────┬───────┘          │
           │                   │                   │
           ▼                   ▼                   │
    ┌──────────────────────────────────────┐      │
    │          organize_endpoints()         │◄─────┘
    │  - Parse URLs                         │
    │  - Extract parameters                 │
    │  - Merge form data                    │
    │  - Classify endpoints                 │
    │  - Classify parameters                │
    └──────────────────┬───────────────────┘


    ┌──────────────────────────────────────┐
    │          resource_enum result         │
    │  - by_base_url (organized endpoints)  │
    │  - forms (POST endpoints)             │
    │  - discovered_urls (raw list)         │
    │  - summary (statistics)               │
    └──────────────────────────────────────┘

Output Data Structure

Complete JSON Schema

{
  "resource_enum": {
    "scan_metadata": {
      "scan_timestamp": "2024-01-15T12:00:00.000000",
      "scan_duration_seconds": 145.5,

      "katana_docker_image": "projectdiscovery/katana:latest",
      "katana_crawl_depth": 3,
      "katana_max_urls": 1000,
      "katana_rate_limit": 150,
      "katana_js_crawl": true,
      "katana_params_only": false,
      "katana_urls_found": 234,

      "gau_enabled": true,
      "gau_docker_image": "sxcurity/gau:latest",
      "gau_providers": ["wayback", "commoncrawl", "otx", "urlscan"],
      "gau_urls_found": 156,
      "gau_verify_enabled": true,
      "gau_method_detection_enabled": true,
      "gau_filter_dead_endpoints": true,
      "gau_stats": {
        "gau_total": 156,
        "gau_parsed": 142,
        "gau_new": 87,
        "gau_overlap": 55,
        "gau_skipped_unverified": 14,
        "gau_skipped_dead": 8,
        "gau_with_post": 23,
        "gau_with_multiple_methods": 15
      },

      "kiterunner_enabled": true,
      "kiterunner_binary_path": "~/.redamon/tools/kiterunner/kr",
      "kiterunner_wordlist": "apiroutes-251227",
      "kiterunner_endpoints_found": 45,
      "kiterunner_stats": {
        "kr_total": 45,
        "kr_parsed": 45,
        "kr_new": 38,
        "kr_overlap": 7,
        "kr_methods": {"GET": 30, "POST": 12, "PUT": 3}
      },

      "hakrawler_enabled": true,
      "hakrawler_docker_image": "jauderho/hakrawler:latest",
      "hakrawler_depth": 2,
      "hakrawler_threads": 5,
      "hakrawler_urls_found": 78,

      "jsluice_enabled": true,
      "jsluice_max_files": 50,
      "jsluice_urls_found": 42,
      "jsluice_secrets_found": 3,

      "proxy_used": false,
      "target_urls_count": 5,
      "target_domains_count": 3,
      "total_discovered_urls": 321
    },

    "discovered_urls": [
      "https://example.com/",
      "https://example.com/login?redirect=/dashboard",
      "https://example.com/api/v1/users?id=1",
      "https://example.com/old-admin/config.php",
      "https://example.com/search?q=test"
    ],

    "by_base_url": {
      "https://example.com": {
        "base_url": "https://example.com",
        "endpoints": {
          "/login": {
            "path": "/login",
            "methods": ["GET", "POST"],
            "parameters": {
              "query": [
                {
                  "name": "redirect",
                  "type": "url",
                  "sample_values": ["/dashboard", "/home"],
                  "category": "redirect_params"
                }
              ],
              "body": [
                {
                  "name": "username",
                  "type": "string",
                  "input_type": "text",
                  "required": true,
                  "category": "auth_params"
                },
                {
                  "name": "password",
                  "type": "string",
                  "input_type": "password",
                  "required": true,
                  "category": "auth_params"
                }
              ],
              "path": []
            },
            "sample_urls": ["https://example.com/login?redirect=/dashboard"],
            "urls_found": 3,
            "category": "authentication",
            "sources": ["katana", "gau"],
            "parameter_count": {
              "query": 1,
              "body": 2,
              "path": 0,
              "total": 3
            }
          },
          "/api/v1/users": {
            "path": "/api/v1/users",
            "methods": ["GET"],
            "parameters": {
              "query": [
                {
                  "name": "id",
                  "type": "integer",
                  "sample_values": ["1", "2", "100"],
                  "category": "id_params"
                }
              ],
              "body": [],
              "path": []
            },
            "sample_urls": ["https://example.com/api/v1/users?id=1"],
            "urls_found": 5,
            "category": "api",
            "sources": ["katana"],
            "parameter_count": {
              "query": 1,
              "body": 0,
              "path": 0,
              "total": 1
            }
          },
          "/old-admin/config.php": {
            "path": "/old-admin/config.php",
            "methods": ["GET"],
            "parameters": {
              "query": [
                {
                  "name": "debug",
                  "category": "other"
                }
              ],
              "body": [],
              "path": []
            },
            "sample_urls": ["https://example.com/old-admin/config.php?debug=1"],
            "category": "admin",
            "sources": ["gau"],
            "parameter_count": {
              "query": 1,
              "body": 0,
              "path": 0,
              "total": 1
            }
          }
        },
        "summary": {
          "total_endpoints": 15,
          "total_parameters": 23,
          "methods": {
            "GET": 12,
            "POST": 3
          },
          "categories": {
            "api": 5,
            "authentication": 2,
            "dynamic": 4,
            "static": 3,
            "search": 1
          }
        }
      }
    },

    "forms": [
      {
        "action": "https://example.com/login",
        "method": "POST",
        "enctype": "application/x-www-form-urlencoded",
        "found_at": "https://example.com/login",
        "inputs": [
          {"name": "username", "type": "text", "value": "", "required": true},
          {"name": "password", "type": "password", "value": "", "required": true},
          {"name": "remember", "type": "checkbox", "value": "1", "required": false}
        ]
      },
      {
        "action": "https://example.com/upload",
        "method": "POST",
        "enctype": "multipart/form-data",
        "found_at": "https://example.com/dashboard",
        "inputs": [
          {"name": "file", "type": "file", "value": "", "required": true},
          {"name": "description", "type": "text", "value": "", "required": false}
        ]
      }
    ],

    "summary": {
      "total_base_urls": 3,
      "total_endpoints": 45,
      "total_parameters": 78,
      "total_forms": 5,
      "from_katana": 234,
      "from_gau": 156,
      "gau_new_endpoints": 87,
      "gau_overlap": 55,
      "methods": {
        "GET": 38,
        "POST": 7
      },
      "categories": {
        "api": 15,
        "dynamic": 12,
        "static": 8,
        "authentication": 4,
        "search": 3,
        "admin": 2,
        "file_access": 1
      }
    }
  }
}

Endpoint Sources Field

Each endpoint includes a sources array indicating where it was discovered:

ExampleMeaning
["katana"]Found only by Katana active crawling
["hakrawler"]Found only by Hakrawler DOM crawling
["gau"]Found only by GAU passive discovery
["kiterunner"]Found only by Kiterunner API bruteforce
["jsluice"]Found only by jsluice JavaScript analysis
["katana", "hakrawler"]Found by both active crawlers
["katana", "gau"]Found by both Katana and GAU
["katana", "hakrawler", "gau", "kiterunner", "jsluice"]Found by all five tools

Why Array Format?

  • With 5 discovery tools, a simple string can't capture all combinations
  • Arrays allow precise tracking of which tools found each endpoint
  • Helps prioritize endpoints found by multiple tools (higher confidence)

Endpoint Classification

The module automatically classifies endpoints into categories based on URL patterns, HTTP methods, and parameters.

Categories

CategoryDetection PatternsSecurity Relevance
authentication/login, /signup, /auth, /token, body params with username/passwordCredential stuffing, brute force
admin/admin, /dashboard, /panel, /wp-adminPrivilege escalation
api/api/, /v1/, /v2/, /rest/, /graphqlAPI abuse, IDOR
file_access/download, /file, /image, /attachmentLFI, path traversal
upload/upload, /importMalicious file upload
search/search, /find, /querySQL injection, XSS
dynamic.php, .asp, .jsp, or URLs with paramsVarious injection attacks
static.html, .css, .js, imagesLow priority
otherEverything elseManual review

Classification Logic

def classify_endpoint(path, methods, params):
    # Priority order:
    # 1. Check path patterns (auth, admin, api, file, search)
    # 2. Check body parameters for auth indicators
    # 3. Check file extension (static vs dynamic)
    # 4. Check for query parameters (dynamic)
    # 5. Default to "other"

Parameter Classification

Parameters are classified to identify potentially vulnerable inputs.

Parameter Categories

CategoryExamplesVulnerability Risk
id_paramsid, user_id, product_id, catIDOR, SQL injection
file_paramsfile, path, template, includeLFI, RFI, path traversal
search_paramsq, query, search, keywordSQL injection, XSS
auth_paramsusername, password, token, apikeyCredential exposure
redirect_paramsurl, redirect, next, callbackOpen redirect, SSRF
command_paramscmd, exec, host, ipCommand injection
otherEverything elseContext-dependent

Type Inference

The module infers parameter data types from names and sample values:

TypeDetection MethodExample
integerNumeric values, names like id, pageid=123
emailContains @ and .email=user@example.com
urlStarts with http:// or https://redirect=https://...
pathContains /, \, or file extensionsfile=../etc/passwd
datetimeNames like date, time, timestampcreated_at=...
booleanNames like enabled, active, is_*active=true
stringDefaultEverything else

Form Parsing

The module parses HTML to extract form elements and their inputs.

Extracted Form Information

{
  "action": "https://example.com/login",
  "method": "POST",
  "enctype": "application/x-www-form-urlencoded",
  "found_at": "https://example.com/",
  "inputs": [
    {
      "name": "username",
      "type": "text",
      "value": "",
      "required": true,
      "placeholder": "Enter username"
    },
    {
      "name": "password",
      "type": "password",
      "value": "",
      "required": true
    }
  ]
}

Supported Input Types

HTML ElementExtracted Info
<form>action, method, enctype
<input>name, type, value, required, placeholder
<textarea>name, required
<select>name, required
<button type="submit">name, value

Form Data in Endpoints

Forms are merged into the endpoint structure:

  • Form action URL becomes the endpoint path
  • Form method is added to endpoint methods
  • Form inputs become body parameters with input_type field

Usage Examples

Basic Usage (via main.py)

# Include "resource_enum" in SCAN_MODULES in project settings
SCAN_MODULES = ["domain_discovery", "port_scan", "http_probe", "resource_enum", "vuln_scan"]

# Run the full pipeline
python3 recon/main.py

Standalone Enrichment

from resource_enum import run_resource_enum
from pathlib import Path
import json

# Load existing recon data
with open("output/recon_example.com.json", "r") as f:
    recon_data = json.load(f)

# Run resource enumeration
enriched = run_resource_enum(recon_data, output_file=Path("output/recon_example.com.json"))

Command Line

# Enrich an existing recon file
python3 recon/resource_enum.py output/recon_example.com.json

Using Results in vuln_scan

The vuln_scan module automatically uses resource_enum data:

# vuln_scan.py - build_target_urls()

# Priority 1: Use resource_enum endpoints (most comprehensive)
resource_enum_data = recon_data.get("resource_enum")
if resource_enum_data:
    base_urls, endpoint_urls = build_target_urls_from_resource_enum(resource_enum_data)
    # Returns both base URLs and URLs with parameters for comprehensive scanning

Integration with Graph Database

Resource enumeration data is stored in Neo4j:

Node Types

NodeProperties
Endpointpath, method, category, has_parameters, query_param_count, body_param_count
Parametername, position (query/body), type, category, sample_values
Secretsecret_type, severity, source, source_url, base_url, sample
ExternalDomaindomain, source (katana, hakrawler, jsluice, gau), url

Relationships

(BaseURL) -[:HAS_ENDPOINT]-> (Endpoint) -[:HAS_PARAMETER]-> (Parameter)
(BaseURL) -[:HAS_SECRET]-> (Secret)
(Domain) -[:HAS_EXTERNAL_DOMAIN]-> (ExternalDomain)

Example Cypher Queries

// Find all authentication endpoints
MATCH (e:Endpoint {category: 'authentication'})
RETURN e.path, e.method

// Find endpoints with file parameters (LFI risk)
MATCH (e:Endpoint)-[:HAS_PARAMETER]->(p:Parameter {category: 'file_params'})
RETURN e.path, p.name

// Find all POST forms
MATCH (e:Endpoint {method: 'POST', is_form: true})
RETURN e.path, e.form_found_at

// Find secrets discovered in JavaScript files
MATCH (b:BaseURL)-[:HAS_SECRET]->(s:Secret)
WHERE s.severity IN ['high', 'critical']
RETURN b.url, s.secret_type, s.source_url, s.sample

// Find endpoints discovered by Hakrawler but not Katana
MATCH (e:Endpoint)
WHERE 'hakrawler' IN e.sources AND NOT 'katana' IN e.sources
RETURN e.path, e.method

Troubleshooting

Common Issues

"Docker not found"

# Install Docker
sudo apt install docker.io

# Start Docker daemon
sudo systemctl start docker

"No URLs discovered"

Possible causes:

  1. JavaScript-heavy site (SPAs)
  2. WAF blocking crawler
  3. Rate limiting

Solutions:

# Increase depth
KATANA_DEPTH = 5

# Enable JS crawling
KATANA_JS_CRAWL = True

# Reduce rate limit
KATANA_RATE_LIMIT = 50

"Too many URLs (noise)"

# Enable params-only mode
KATANA_PARAMS_ONLY = True

# Add exclude patterns
KATANA_EXCLUDE_PATTERNS = [
    "/static/",
    "/assets/",
    "/wp-content/",
    ".css", ".js", ".jpg", ".png"
]

# Reduce max URLs
KATANA_MAX_URLS = 500

"Crawl taking too long"

# Reduce depth
KATANA_DEPTH = 2

# Reduce timeout
KATANA_TIMEOUT = 120

# Increase rate limit
KATANA_RATE_LIMIT = 200

# Disable JS crawling
KATANA_JS_CRAWL = False

"GAU returning too many URLs"

# Limit URLs per domain
GAU_MAX_URLS = 500

# Use fewer providers
GAU_PROVIDERS = ["wayback"]  # Only Wayback Machine

# Filter by date range
GAU_YEAR_RANGE = ["2022", "2024"]

# Add more extensions to blacklist
GAU_BLACKLIST_EXTENSIONS.extend(["aspx", "jsp"])

"GAU URLs not being added to results"

Possible causes:

  1. URL verification filtering them out
  2. URLs from different domains (subdomains disabled)
  3. Extension blacklist filtering

Solutions:

# Disable verification to see all URLs
GAU_VERIFY_URLS = False

# Check blacklist isn't too aggressive
GAU_BLACKLIST_EXTENSIONS = ["png", "jpg", "gif", "css"]  # Minimal

"GAU timeout errors"

# Increase timeout
GAU_TIMEOUT = 120

# Reduce providers
GAU_PROVIDERS = ["wayback", "commoncrawl"]  # Skip slower ones

# Reduce threads
GAU_THREADS = 2

"Kiterunner not finding endpoints"

Possible causes:

  1. Target doesn't have REST APIs
  2. WAF blocking bruteforce attempts
  3. APIs use non-standard routes

Solutions:

# Try different wordlist
KITERUNNER_WORDLIST = "aspx-251227"  # For ASP.NET

# Reduce rate to avoid WAF
KITERUNNER_RATE_LIMIT = 50

# Add authentication headers
KITERUNNER_HEADERS = ["Authorization: Bearer <token>"]

"Kiterunner timeout errors"

# Increase scan timeout
KITERUNNER_SCAN_TIMEOUT = 600

# Reduce concurrent connections
KITERUNNER_CONNECTIONS = 50

# Increase per-request timeout
KITERUNNER_TIMEOUT = 15

"Kiterunner too aggressive (WAF blocks)"

# Stealth mode
KITERUNNER_RATE_LIMIT = 30
KITERUNNER_CONNECTIONS = 20
KITERUNNER_THREADS = 10

Debug Mode

Run Katana manually via Docker:

docker run --rm \
  projectdiscovery/katana:latest \
  -u https://example.com \
  -d 2 \
  -jc \
  -silent

Run GAU manually via Docker:

docker run --rm \
  sxcurity/gau:latest \
  --threads 5 \
  --timeout 60 \
  --providers wayback,commoncrawl \
  example.com

Run Kiterunner manually (binary auto-downloads to ~/.redamon/tools/kiterunner/):

# Binary location after first run
# Use -A flag for auto-downloaded wordlists
~/.redamon/tools/kiterunner/kr scan https://example.com \
  -A apiroutes-251227:20000 \
  -x 50 \
  -j 25 \
  -t 10s

Security Considerations

RiskMitigation
Rate limiting/bansReduce KATANA_RATE_LIMIT and KITERUNNER_RATE_LIMIT
WAF blockingUse custom User-Agent, reduce rate
API bruteforce detectionLower KITERUNNER_CONNECTIONS and KITERUNNER_THREADS
Legal issuesOnly scan authorized targets

Safe Defaults

# Katana (Active Crawling)
KATANA_RATE_LIMIT = 50
KATANA_DEPTH = 2
KATANA_TIMEOUT = 120
KATANA_CUSTOM_HEADERS = [
    "User-Agent: Mozilla/5.0 (compatible; SecurityScanner/1.0)"
]

# Kiterunner (API Bruteforce)
KITERUNNER_RATE_LIMIT = 50
KITERUNNER_CONNECTIONS = 30
KITERUNNER_THREADS = 20

Dependencies

PackagePurpose
DockerContainer runtime for Katana, GAU, and httpx
projectdiscovery/katana:latestKatana Docker image (auto-pulled)
sxcurity/gau:latestGAU Docker image (auto-pulled)
Kiterunner binaryAuto-downloaded from GitHub releases to ~/.redamon/tools/kiterunner/
projectdiscovery/httpx:latesthttpx Docker image for URL verification (auto-pulled)
Python 3.8+Script runtime
html.parserBuilt-in HTML form parsing
urllib.parseBuilt-in URL parsing for GAU endpoint extraction

  • Downstream — AI Surface Recon (Phase 4.5): consumes the endpoints classified here (ai_interface_type = llm-chat/mcp/…) and actively confirms the AI/LLM/MCP/vector-DB surfaces with benign protocol probes.

References


Documentation generated for RedAmon v1.0 - Resource Enumeration Module