Mastering FFUF: Advanced Techniques for Hidden API Endpoint and Parameter Discovery

Uncovering concealed API endpoints and parameters is a critical phase in any web application penetration test. While FFUF (Ffuf is a fast web fuzzer written in Go) excels at basic directory and file brute-forcing, its true power lies in leveraging its advanced features to dissect complex applications. This isn't about simply throwing a wordlist; it's about surgical reconnaissance to expose the undocumented attack surface.

Beyond Basic Path Traversal

Basic path fuzzing is the entry point, but real targets often demand more. When initial directory enumeration yields limited results, pivoting to HTTP method fuzzing and virtual host enumeration can reveal hidden paths only accessible via specific methods or hosts.

HTTP Method Fuzzing

Many APIs restrict certain actions to specific HTTP methods. Fuzzing the method itself can unveil sensitive endpoints or unexpected behaviors. This is particularly effective against RESTful APIs that might incorrectly handle methods like PUT, DELETE, or PATCH on endpoints expecting only GET or POST.

ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZ \
     -X FUZZ -w /usr/share/seclists/Discovery/Web-Content/http-methods.txt:FUZZ_METHOD \
     -u https://target.com/api/v1/FUZZ \
     -H "Content-Type: application/json" \
     -fc 404,405 \
     -of json -o method_fuzz_results.json

Here, -X FUZZ tells FFUF to replace FUZZ in the URL and header with values from the http-methods.txt wordlist. The -H "Content-Type: application/json" ensures requests are sent with an appropriate header, often crucial for API endpoints. Filtering out 404 (Not Found) and 405 (Method Not Allowed) responses helps narrow down interesting results, though 405s can sometimes indicate a valid path with an unsupported method, warranting further investigation.

Virtual Host Fuzzing

Modern applications frequently employ virtual hosting, sometimes exposing different applications or development versions on the same IP address through unique Host headers. FFUF can systematically probe these.

ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-100000.txt:FUZZ \
     -u https://target.com \
     -H "Host: FUZZ.target.com" \
     -fs 0 \
     -fc 400,403,404 \
     -t 50

This command injects subdomain candidates into the Host header. The -fs 0 option filters out responses with a size of zero bytes, which can often be irrelevant, while -fc 400,403,404 focuses on responses that aren't outright errors, potentially indicating a live virtual host. Large-scale reconnaissance tasks like this can benefit from routing traffic through a dedicated proxy service like GProxy to manage source IPs and maintain anonymity, especially when dealing with aggressive rate limits.

Advanced Parameter Discovery Nuances

Locating parameters, both reflected and hidden, is paramount. FFUF offers robust ways to achieve this beyond simple GET requests.

POST Body Parameter Fuzzing

Many APIs rely heavily on POST requests with JSON or URL-encoded bodies. FFUF can craft these requests effectively.

URL-encoded POST Parameters

ffuf -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt:PARAM \
     -w /usr/share/seclists/Fuzzing/special-chars.txt:VALUE \
     -u https://target.com/api/v1/login \
     -X POST \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "PARAM=VALUE&username=test" \
     -fs 1234,0 \
     -mc 200,302

Here, we're fuzzing both a parameter name (PARAM) and its value (VALUE) within a URL-encoded POST body. The -d flag specifies the request body. Using two wordlists (PARAM and VALUE) in conjunction allows for a comprehensive search. -fs filters by size, useful for ignoring common error pages or empty responses, while -mc focuses on successful responses or redirects.

JSON Body Parameter Fuzzing

For JSON APIs, injecting into the JSON structure is key. FFUF's -d flag can handle this with proper escaping.

ffuf -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt:PARAM \
     -u https://target.com/api/v2/users \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"PARAM": "FUZZVAL", "id": 123}' \
     -w /usr/share/seclists/Fuzzing/special-chars.txt:FUZZVAL \
     -fs 0 \
     -filter-size 1337,123 \
     -fr "error|invalid"

This snippet attempts to discover new JSON parameters. The -d flag defines the JSON payload where PARAM is fuzzed for parameter names and FUZZVAL for potential interesting values. -fr "error|invalid" uses a regular expression to filter out responses containing "error" or "invalid," indicating the fuzzed parameter might not be causing an outright error, which could be an interesting hit.

Header Parameter Fuzzing

Many applications, especially those using microservices or custom authentication schemes, rely on custom HTTP headers. Fuzzing these headers can expose unvalidated input points.

ffuf -w /usr/share/seclists/Discovery/Web-Content/burp-header-names.txt:HEADER \
     -w /usr/share/seclists/Fuzzing/special-chars.txt:VALUE \
     -u https://target.com/profile \
     -H "HEADER: VALUE" \
     -H "User-Agent: FFUF-Scanner" \
     -fc 400,401,403,404 \
     -ml 100 \
     -of html -o header_fuzz.html

This command targets custom headers. -H "HEADER: VALUE" injects both header names and values. -ml 100 filters responses by minimum line count, useful for identifying unusually short responses that might be errors. After an initial reconnaissance phase using broader tools like Zondex to map out the attack surface, FFUF's precision allows for deep dives into specific web application components.

Recursive Fuzzing and Chaining

Discovering a path often leads to more paths. FFUF's recursion capabilities allow it to follow discovered directories, and chaining with other tools provides analytical depth.

Recursive Directory Fuzzing

The -recursion flag is powerful. It instructs FFUF to continue fuzzing within directories it discovers, effectively mapping out a deeper tree structure.

ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-large-directories-lowercase.txt:FUZZ \
     -u https://target.com/FUZZ \
     -recursion -recursion-depth 2 \
     -e .php,.html,.js,.json \
     -fs 0,1337 \
     -of csv -o recursive_paths.csv

Here, -recursion enables recursive mode, and -recursion-depth 2 limits it to two levels deep. The -e flag appends common extensions, increasing the chance of hitting relevant files. Filtering by common error page sizes (-fs 0,1337) helps maintain focus on potentially valid content.

Chaining FFUF with External Tools

FFUF output can be piped or processed by other utilities for deeper analysis. For instance, parsing JSON output with jq or grepping through HTML output for specific keywords.

ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZ \
     -u https://target.com/api/v3/FUZZ \
     -H "Accept: application/json" \
     -of json -o /dev/stdout \
     | jq -r '.results[] | select(.status == 200) | .url' \
     | while read url; do echo "Found 200 OK: $url"; done

This example outputs FFUF results to standard output in JSON format, which is then piped to jq. jq -r '.results[] | select(.status == 200) | .url' filters for results with a 200 OK status and extracts the URL, which is then processed by a while loop. This allows for immediate action or further processing on relevant findings, moving beyond just raw discovery to intelligent analysis.

Payload Generation Strategies

The quality of your wordlists directly impacts discovery success. Beyond common SecLists, custom, target-specific wordlists are crucial.

Parameter Wordlist Generation

Analyzing JavaScript files, previous API documentation, or even client-side code can yield unique parameter names. A simple script can extract these.

# param_extractor.py
import re
import sys

def extract_params(content):
    # Regex for common JS variable/property names that look like parameters
    # This is a basic example; more sophisticated regex might be needed
    patterns = [
        r'\.([a-zA-Z_][a-zA-Z0-9_]*)\s*[:=]',  # object.param: or object.param =
        r'[\'"]([a-zA-Z_][a-zA-Z0-9_]*)[\'"]\s*:', # "param": or 'param': in JSON/JS objects
        r'\?([a-zA-Z_][a-zA-Z0-9_]*)=', # ?param= in URLs
    ]
    
    found_params = set()
    for pattern in patterns:
        matches = re.findall(pattern, content)
        for match in matches:
            if len(match) > 1 and match.lower() not in ["function", "const", "var", "let", "this", "return", "data", "id", "name"]: # basic filter
                found_params.add(match)
    return sorted(list(found_params))

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("Usage: python param_extractor.py <file_path> [ <file_path2> ... ]")
        sys.exit(1)

    all_extracted = set()
    for file_path in sys.argv[1:]:
        try:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()
                all_extracted.update(extract_params(content))
        except FileNotFoundError:
            print(f"Error: File not found - {file_path}")
        except Exception as e:
            print(f"Error processing {file_path}: {e}")
            
    for param in sorted(list(all_extracted)):
        print(param)

This Python script, param_extractor.py, can be used to parse JavaScript files or other text-based application assets to generate a highly relevant parameter wordlist. Running it on all JavaScript files found on a target can yield excellent results:

find . -name "*.js" -exec python3 param_extractor.py {} + > custom_params.txt
ffuf -w custom_params.txt:PARAM -u https://target.com/api/v1/search?PARAM=value -fs 0

The generated custom_params.txt then becomes a potent, targeted wordlist for subsequent FFUF runs. This granular approach, combined with the comprehensive scanning capabilities of platforms like Secably, provides a strong security posture. While Secably handles broad vulnerability scanning, FFUF excels at this kind of deep, custom-tailored API exploration.

Custom Filters and Matchers

FFUF's filtering and matching capabilities are essential for handling noisy responses and pinpointing true positives. Beyond basic status codes and sizes, regex-based filtering allows for sophisticated anomaly detection.

Response Line/Word/Character Count Filtering

Sometimes, legitimate responses have a very consistent size or structure. Any deviation, even a small one, can indicate an interesting finding. Filtering by line count (-fl), word count (-fw), or character count (-fc) helps identify these anomalies.

ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZ \
     -u https://target.com/admin/FUZZ \
     -recursion \
     -fl 23,24,25 \
     -fw 120,121,122 \
     -fr "Access Denied" \
     -o output.json -of json

In this example, -fl 23,24,25 and -fw 120,121,122 filter out responses matching specific line and word counts, assuming these are characteristic of default error pages. -fr "Access Denied" filters results that contain the exact phrase "Access Denied," allowing you to ignore common security messages and focus on truly different responses.

Content-based Matching (Regex)

Matching specific strings or patterns in the response body can highlight vulnerable reflections or interesting data leakage.

ffuf -w /usr/share/seclists/Fuzzing/XSS/xss-payloads.txt:INJECT \
     -u https://target.com/search?q=INJECT \
     -mc all \
     -mr "FUZZ_VALUE_REGEX" \
     -o reflected_xss_test.txt

The -mr "FUZZ_VALUE_REGEX" flag tells FFUF to match responses where the injected payload (or a specific pattern related to its reflection) appears. For instance, if injecting , a regex like could be used to confirm its reflection, even if the status code is still 200 OK. Setting -mc all ensures all status codes are considered before the regex match is applied.

Mastering FFUF involves more than just running simple commands. It's about understanding the target application's nuances, crafting intelligent wordlists, leveraging advanced filtering and matching, and knowing when to chain it with other tools. This disciplined approach transforms FFUF from a basic fuzzer into an indispensable tool for deep API and parameter discovery.