### FeroxFuzz Fuzzer Output Example Source: https://github.com/epi052/feroxfuzz/blob/main/README.md This example displays the typical output generated by the FeroxFuzz fuzzer after a fuzzing loop, including status codes, request details, timing, and a detailed breakdown of the shared state and statistics. ```text [200] 815 - http://localhost:8000/?admin=Ajax - 840.985µs [200] 206 - http://localhost:8000/?admin=Al - 4.092037ms ---- SharedState::{ Seed=24301 Rng=RomuDuoJrRand { x_state: 97704, y_state: 403063 } Corpus[words]=Wordlist::{len=102774, top-3=[Static("A"), Static("A's"), Static("AMD")]}, Statistics={"timeouts":0,"requests":102774.0,"errors":44208,"informatives":3626,"successes":29231,"redirects":25709,"client_errors":18195,"server_errors":26013,"redirection_errors":0,"connection_errors":0,"request_errors":0,"start_time":{"secs":1662124648,"nanos":810398280},"avg_reqs_per_sec":5946.646301595066,"statuses":{"500":14890,"201":3641,"307":3656,"203":3562,"101":3626,"401":3625,"207":3711,"308":3578,"300":3724,"404":3705,"301":3707,"302":3651,"304":3706,"502":3682,"402":3636,"200":3718,"503":3762,"400":3585,"501":3679,"202":3659,"205":3680,"206":3676,"204":3584,"403":3644,"303":3687}} } ``` -------------------------------- ### Async Fuzzer Setup with FeroxFuzz Source: https://github.com/epi052/feroxfuzz/blob/main/README.md This snippet shows the essential components for an asynchronous fuzzer. It includes creating a corpus, initializing an async client, defining a mutator, setting up the request with fuzzable directives, configuring a status code decider, and a response observer and processor. ```rust #[tokio::main] async fn main() -> Result<(), Box> { // create a new corpus from the given list of words let words = Wordlist::from_file("./examples/words")? .name("words") .build(); // pass the corpus to the state object, which will be shared between all of the fuzzers and processors let mut state = SharedState::with_corpus(words); // bring-your-own client, this example uses the reqwest library let req_client = reqwest::Client::builder().build()?; // with some client that can handle the actual http request/response stuff // we can build a feroxfuzz client, specifically an asynchronous client in this // instance. // // feroxfuzz provides both a blocking and an asynchronous client implementation // using reqwest. let client = AsyncClient::with_client(req_client); // ReplaceKeyword mutators operate similar to how ffuf/wfuzz work, in that they'll // put the current corpus item wherever the keyword is found, as long as its found // in data marked fuzzable (see ShouldFuzz directives below) let mutator = ReplaceKeyword::new(&"FUZZ", "words"); // fuzz directives control which parts of the request should be fuzzed // anything not marked fuzzable is considered to be static and won't be mutated // // ShouldFuzz directives map to the various components of an HTTP request let request = Request::from_url( "http://localhost:8000/?admin=FUZZ", Some(&[ShouldFuzz::URLParameterValues]), )?; // a `StatusCodeDecider` provides a way to inspect each response's status code and decide upon some Action // based on the result of whatever comparison function (closure) is passed to the StatusCodeDecider's // constructor // // in plain english, the `StatusCodeDecider` below will check to see if the request's http response code // received is equal to 200/OK. If the response code is 200, then the decider will recommend the `Keep` // action be performed. If the response code is anything other than 200, then the recommendation will // be to `Discard` the response. // // `Keep`ing the response means that the response will be allowed to continue on for further processing // later in the fuzz loop. let decider = StatusCodeDecider::new(200, |status, observed, _state| { if status == observed { Action::Keep } else { Action::Discard } }); // a `ResponseObserver` is responsible for gathering information from each response and providing // that information to later fuzzing components, like Processors. It knows things like the response's // status code, content length, the time it took to receive the response, and a bunch of other stuff. let response_observer: ResponseObserver = ResponseObserver::new(); // a `ResponseProcessor` provides access to the fuzzer's instance of `ResponseObserver` // as well as the `Action` returned from calling `Deciders` (like the `StatusCodeDecider` above). // Those two objects may be used to produce side-effects, such as printing, logging, calling out to // some other service, or whatever else you can think of. let response_printer = ResponseProcessor::new( |response_observer: &ResponseObserver, action, _state| { if let Some(Action::Keep) = action { println!( "[{}] {} - {} - {:?}", response_observer.status_code(), response_observer.content_length(), response_observer.url(), response_observer.elapsed() ); } }, ); // `Scheduler`s manage how the fuzzer gets entries from the corpus. The `OrderedScheduler` provides // in-order access of the associated `Corpus` (`Wordlist` in this example's case) let scheduler = OrderedScheduler::new(state.clone())?; // the macro calls below are essentially boilerplate. Whatever observers, deciders, mutators, // and processors you want to use, you simply pass them to the appropriate macro call and // eventually to the Fuzzer constructor. let deciders = build_deciders!(decider); let mutators = build_mutators!(mutator); let observers = build_observers!(response_observer); let processors = build_processors!(response_printer); ``` -------------------------------- ### Build an Asynchronous HTTP Fuzzer Source: https://context7.com/epi052/feroxfuzz/llms.txt Demonstrates an asynchronous fuzzer setup using tokio, featuring concurrent request execution and status code filtering. ```rust use feroxfuzz::client::{AsyncClient, HttpClient}; use feroxfuzz::corpora::Wordlist; use feroxfuzz::deciders::StatusCodeDecider; use feroxfuzz::fuzzers::{AsyncFuzzer, AsyncFuzzing}; use feroxfuzz::mutators::ReplaceKeyword; use feroxfuzz::observers::ResponseObserver; use feroxfuzz::prelude::*; use feroxfuzz::processors::ResponseProcessor; use feroxfuzz::responses::AsyncResponse; use feroxfuzz::schedulers::OrderedScheduler; use feroxfuzz::state::SharedState; #[tokio::main] async fn main() -> Result<(), Box> { // Setup corpus and state let words = Wordlist::from_file("./wordlist.txt")?.name("words").build(); let mut state = SharedState::with_corpus(words); // Setup HTTP client let req_client = reqwest::Client::builder().build()?; let client = AsyncClient::with_client(req_client); // Setup mutator let mutator = ReplaceKeyword::new(&"FUZZ", "words"); // Setup request with fuzzable path let request = Request::from_url( "http://localhost:8000/FUZZ", Some(&[ShouldFuzz::URLPath]), )?; // Setup decider - keep 200 responses let decider = StatusCodeDecider::new(200, |status, observed, _state| { if status == observed { Action::Keep } else { Action::Discard } }); // Setup observer and processor let response_observer: ResponseObserver = ResponseObserver::new(); let response_printer = ResponseProcessor::new( |observer: &ResponseObserver, action, _state| { if let Some(Action::Keep) = action { println!("[{}] {}", observer.status_code(), observer.url()); } }, ); // Setup scheduler let scheduler = OrderedScheduler::new(state.clone())?; // Build component tuples let deciders = build_deciders!(decider); let mutators = build_mutators!(mutator); let observers = build_observers!(response_observer); let processors = build_processors!(response_printer); // Build and run fuzzer with 40 concurrent threads let mut fuzzer = AsyncFuzzer::new(40) .client(client) .request(request) .scheduler(scheduler) .mutators(mutators) .observers(observers) .processors(processors) .deciders(deciders) .build(); // Run single iteration over corpus fuzzer.fuzz_once(&mut state).await?; // Or run forever // fuzzer.fuzz(&mut state).await?; // Or run N iterations // fuzzer.fuzz_n_iterations(5, &mut state).await?; println!("{state:#}"); Ok(()) } ``` -------------------------------- ### Build a Blocking HTTP Fuzzer Source: https://context7.com/epi052/feroxfuzz/llms.txt Demonstrates a synchronous, sequential fuzzer setup using a numeric range corpus and request-based processing. ```rust use feroxfuzz::client::{BlockingClient, HttpClient}; use feroxfuzz::corpora::RangeCorpus; use feroxfuzz::fuzzers::{BlockingFuzzer, BlockingFuzzing}; use feroxfuzz::mutators::ReplaceKeyword; use feroxfuzz::observers::ResponseObserver; use feroxfuzz::prelude::*; use feroxfuzz::processors::RequestProcessor; use feroxfuzz::requests::ShouldFuzz; use feroxfuzz::responses::BlockingResponse; use feroxfuzz::schedulers::OrderedScheduler; use feroxfuzz::state::SharedState; use std::time::Duration; fn main() -> Result<(), Box> { // Setup corpus with numeric range let range = RangeCorpus::with_stop(100).name("ids").build()?; let mut state = SharedState::with_corpus(range); // Setup blocking client with timeout let req_client = reqwest::blocking::Client::builder() .timeout(Duration::from_secs(5)) .build()?; let client = BlockingClient::with_client(req_client); // Setup mutator let mutator = ReplaceKeyword::new(&"ID", "ids"); // Setup request let request = Request::from_url( "http://localhost:8000/api/user/ID", Some(&[ShouldFuzz::URLPath]), )?; // Setup observer and processor let response_observer: ResponseObserver = ResponseObserver::new(); let request_printer = RequestProcessor::new(|request, _action, _state| { println!("Testing: {}", request.path()); }); // Setup scheduler let scheduler = OrderedScheduler::new(state.clone())?; // Build component tuples let mutators = build_mutators!(mutator); let observers = build_observers!(response_observer); let processors = build_processors!(request_printer); // Build and run fuzzer let mut fuzzer = BlockingFuzzer::new() .client(client) .request(request) .scheduler(scheduler) .mutators(mutators) .observers(observers) .processors(processors) .build(); fuzzer.fuzz_once(&mut state)?; println!("{state:#}"); Ok(()) } ``` -------------------------------- ### Create Range Corpora Source: https://context7.com/epi052/feroxfuzz/llms.txt Generate numeric sequences with configurable start, stop, and step values for fuzzing numeric parameters. ```rust use feroxfuzz::corpora::RangeCorpus; use feroxfuzz::Len; // Generate 0, 1, 2, 3, 4 let range = RangeCorpus::with_stop(5) .name("ids") .build()?; assert_eq!(range.len(), 5); // Generate 0, 2, 4, 6, 8 (start=0, stop=10, step=2) let even_range = RangeCorpus::new() .start(0) .stop(10) .step(2) .name("even_ids") .build()?; assert_eq!(even_range.len(), 5); // Generate 100, 95, 90, 85, 80 (descending with negative step) let descending = RangeCorpus::new() .start(100) .stop(79) .step(-5) .name("countdown") .build()?; ``` -------------------------------- ### Configure and Run FeroxFuzz Fuzzer Source: https://github.com/epi052/feroxfuzz/blob/main/README.md This snippet shows how to initialize and configure the `AsyncFuzzer` with various components like client, request, scheduler, mutators, observers, processors, and deciders. It also includes a post-loop hook for printing statistics and running the fuzzer once. ```rust let threads = 40; // number of threads to use for the fuzzing process // the `Fuzzer` is the main component of the feroxfuzz library. It wraps most of the other components // and takes care of the actual fuzzing process. let mut fuzzer = AsyncFuzzer::new(threads) .client(client) .request(request) .scheduler(scheduler) .mutators(mutators) .observers(observers) .processors(processors) .deciders(deciders) .post_loop_hook(|state| { // this closure is called after each fuzzing loop iteration completes. // it's a good place to do things like print out stats // or do other things that you want to happen after each // full iteration over the corpus println!("\n•*´¨`*•.¸¸.•* Finished fuzzing loop •*´¨`*•.¸¸.•*\n"); println!("{state:#}"); }) .build(); // the fuzzer will run until it iterates over the entire corpus once fuzzer.fuzz_once(&mut state).await?; println!("{state:#}"); Ok(()) } ``` -------------------------------- ### Create Wordlist Corpora Source: https://context7.com/epi052/feroxfuzz/llms.txt Initialize wordlists from arrays, files, or unique sets for use as fuzzing inputs. ```rust use feroxfuzz::corpora::Wordlist; use feroxfuzz::Len; // Create from an array of words let wordlist = Wordlist::with_words(["admin", "user", "test", "guest"]) .name("usernames") .build(); assert_eq!(wordlist.len(), 4); // Create from a file (skips empty lines and comments starting with #) let wordlist = Wordlist::from_file("/path/to/wordlist.txt")? .name("paths") .build(); // Create a unique wordlist (removes duplicates) let wordlist = Wordlist::new() .words(["one", "two", "one", "three", "two"]) .name("unique_words") .unique() .build(); assert_eq!(wordlist.len(), 3); // duplicates removed ``` -------------------------------- ### Configure ProductScheduler for Cartesian Product Fuzzing Source: https://context7.com/epi052/feroxfuzz/llms.txt Creates nested loops over multiple corpora to generate all combinations. The order array determines the nesting hierarchy. ```rust use feroxfuzz::schedulers::ProductScheduler; use feroxfuzz::corpora::{Wordlist, RangeCorpus}; use feroxfuzz::state::SharedState; let users = Wordlist::with_words(["admin", "user"]).name("users").build(); let ids = RangeCorpus::with_stop(3).name("ids").build()?; let state = SharedState::with_corpora([users, ids]); // Order determines nesting: outer loop = users, inner loop = ids // Produces: (admin,0), (admin,1), (admin,2), (user,0), (user,1), (user,2) let order = ["users", "ids"]; let scheduler = ProductScheduler::new(order, state.clone())?; ``` -------------------------------- ### Implement ResponseProcessor for Custom Actions Source: https://context7.com/epi052/feroxfuzz/llms.txt Executes custom logic after receiving responses, such as logging or alerting. Requires importing ResponseProcessor, ResponseObserver, and BlockingResponse. ```rust use feroxfuzz::processors::ResponseProcessor; use feroxfuzz::observers::ResponseObserver; use feroxfuzz::responses::BlockingResponse; use feroxfuzz::prelude::*; // Print interesting responses let printer = ResponseProcessor::new( |observer: &ResponseObserver, action, _state| { if let Some(Action::Keep) = action { println!( "[{}] {} - {} - {:?}", observer.status_code(), observer.content_length(), observer.url(), observer.elapsed() ); } }, ); // Log all responses to a file let logger = ResponseProcessor::new( |observer: &ResponseObserver, action, _state| { let status = observer.status_code(); let url = observer.url(); let length = observer.content_length(); // Write to log file, database, etc. eprintln!("[LOG] {} {} {}", status, length, url); }, ); // Send alerts for specific findings let alerter = ResponseProcessor::new( |observer: &ResponseObserver, action, state| { if observer.status_code() == 200 { // Could send webhook, email, etc. println!("FOUND: {}", observer.url()); } }, ); ``` -------------------------------- ### Configure FeroxFuzz Dependencies Source: https://context7.com/epi052/feroxfuzz/llms.txt Add the library to Cargo.toml with specific feature flags for async, blocking, or extended functionality. ```toml [dependencies] # Async fuzzing (default) feroxfuzz = { version = "1.0.0-rc.13" } # Blocking fuzzing feroxfuzz = { version = "1.0.0-rc.13", default-features = false, features = ["blocking"] } # All features feroxfuzz = { version = "1.0.0-rc.13", features = ["async", "blocking", "json", "encoders"] } ``` -------------------------------- ### ResponseObserver Usage Source: https://context7.com/epi052/feroxfuzz/llms.txt Initializes observers for async or blocking fuzzing to access response metadata. ```rust use feroxfuzz::observers::ResponseObserver; use feroxfuzz::responses::{AsyncResponse, BlockingResponse}; // For async fuzzing let response_observer: ResponseObserver = ResponseObserver::new(); // For blocking fuzzing let response_observer: ResponseObserver = ResponseObserver::new(); // The observer provides access to response data: // - response_observer.status_code() -> u16 // - response_observer.content_length() -> u64 // - response_observer.url() -> &Url // - response_observer.elapsed() -> Duration // - response_observer.headers() -> &HeaderMap // - response_observer.body() -> &[u8] ``` -------------------------------- ### Add FeroxFuzz Dependency Source: https://github.com/epi052/feroxfuzz/blob/main/README.md Include the library in your project by adding the specified version to your Cargo.toml file. ```toml [dependencies] feroxfuzz = { version = "1.0.0-rc.13" } ``` -------------------------------- ### Implement Sniper Attack Pattern Source: https://context7.com/epi052/feroxfuzz/llms.txt Uses OrderedScheduler to fuzz one parameter position at a time while keeping others static. Requires manual toggling of fuzzable status for each parameter position. ```rust use feroxfuzz::client::{BlockingClient, HttpClient}; use feroxfuzz::corpora::RangeCorpus; use feroxfuzz::fuzzers::{BlockingFuzzer, BlockingFuzzing}; use feroxfuzz::mutators::ReplaceKeyword; use feroxfuzz::observers::ResponseObserver; use feroxfuzz::prelude::*; use feroxfuzz::responses::BlockingResponse; use feroxfuzz::schedulers::OrderedScheduler; use std::time::Duration; fn main() -> Result<(), Box> { let range = RangeCorpus::with_stop(5).name("range").build()?; let mut state = SharedState::with_corpus(range); let req_client = reqwest::blocking::Client::builder() .timeout(Duration::from_secs(1)) .build()?; let client = BlockingClient::with_client(req_client); // One mutator per position let mutator1 = ReplaceKeyword::new(&"VAL1", "range"); let mutator2 = ReplaceKeyword::new(&"VAL2", "range"); let mutator3 = ReplaceKeyword::new(&"VAL3", "range"); // Start with all positions STATIC (not fuzzable) let mut request = Request::from_url("http://localhost:8000/", None)?; request.add_static_param("first", "VAL1"); request.add_static_param("second", "VAL2"); request.add_static_param("third", "VAL3"); let num_positions = 3; let scheduler = OrderedScheduler::new(state.clone())?; let response_observer: ResponseObserver = ResponseObserver::new(); let observers = build_observers!(response_observer); let mutators = build_mutators!(mutator1, mutator2, mutator3); let mut fuzzer = BlockingFuzzer::new() .client(client) .request(request) .scheduler(scheduler) .mutators(mutators) .observers(observers) .build(); // Fuzz each position independently for position_idx in 0..num_positions { let params = fuzzer.request_mut().params_mut().unwrap(); for (param_idx, (_key, value)) in params.iter_mut().enumerate() { if value.is_fuzzable() { value.toggle_type(); // Make previous position static } if position_idx == param_idx { value.toggle_type(); // Make current position fuzzable break; } } fuzzer.fuzz_once(&mut state)?; println!("--- Completed position {} ---", position_idx); } Ok(()) } ``` -------------------------------- ### Define HTTP Requests with Fuzz Directives Source: https://context7.com/epi052/feroxfuzz/llms.txt Configure specific parts of an HTTP request to be targeted by the fuzzer using ShouldFuzz directives. ```rust use feroxfuzz::prelude::*; use feroxfuzz::requests::ShouldFuzz; // Create a request with fuzzable URL parameter values let request = Request::from_url( "http://localhost:8000/api?user=FUZZ&id=123", Some(&[ShouldFuzz::URLParameterValues]), )?; // Create a request with fuzzable path let request = Request::from_url( "http://localhost:8000/FUZZ", Some(&[ShouldFuzz::URLPath]), )?; // Create a request with multiple fuzzable components let mut request = Request::from_url( "http://localhost:8000/api", Some(&[ ShouldFuzz::URLPath, ShouldFuzz::HTTPMethod(b"GET"), ShouldFuzz::RequestBody(b"{\"key\": \"value\"}"), ]), )?; // Add fuzzable headers request.add_fuzzable_header("Authorization", "Bearer TOKEN", ShouldFuzz::Value)?; // Add fuzzable parameters after creation request.add_fuzzable_param("search", "KEYWORD", ShouldFuzz::Value)?; // Add static (non-fuzzable) parameters request.add_static_param("page", "1"); request.add_static_header("Content-Type", "application/json"); ``` -------------------------------- ### ResponseRegexDecider Implementation Source: https://context7.com/epi052/feroxfuzz/llms.txt Filters responses by matching content against regular expressions. ```rust use feroxfuzz::deciders::ResponseRegexDecider; use feroxfuzz::prelude::*; // Keep responses containing "success" or "authenticated" let decider = ResponseRegexDecider::new("(success|authenticated)", |regex, response, _state| { if regex.is_match(response.body()) { Action::Keep } else { Action::Discard } }); // Discard responses with error messages let decider = ResponseRegexDecider::new("(error|failed|denied)", |regex, response, _state| { if regex.is_match(response.body()) { Action::Discard } else { Action::Keep } }); ``` -------------------------------- ### ContentLengthDecider Implementation Source: https://context7.com/epi052/feroxfuzz/llms.txt Filters responses based on content length thresholds or baseline comparisons. ```rust use feroxfuzz::deciders::ContentLengthDecider; use feroxfuzz::prelude::*; // Keep responses larger than 1000 bytes let decider = ContentLengthDecider::new(1000, |threshold, observed, _state| { if observed > threshold { Action::Keep } else { Action::Discard } }); // Keep responses with different length than baseline let baseline_length = 4523; let decider = ContentLengthDecider::new(baseline_length, |baseline, observed, _state| { if observed != baseline { Action::Keep // Different length might indicate interesting response } else { Action::Discard } }); ``` -------------------------------- ### Configure OrderedScheduler for Sequential Fuzzing Source: https://context7.com/epi052/feroxfuzz/llms.txt Iterates through corpus entries in the order they are defined. Requires a shared state initialized with a corpus. ```rust use feroxfuzz::schedulers::OrderedScheduler; use feroxfuzz::corpora::Wordlist; use feroxfuzz::state::SharedState; let words = Wordlist::with_words(["a", "b", "c"]).name("words").build(); let state = SharedState::with_corpus(words); // Creates scheduler that iterates: a -> b -> c let scheduler = OrderedScheduler::new(state.clone())?; ``` -------------------------------- ### Chain Deciders with AND/OR Logic Source: https://context7.com/epi052/feroxfuzz/llms.txt Combine multiple deciders using LogicOperation::And for a denylist effect or LogicOperation::Or for an allowlist effect. Ensure necessary imports are present. ```rust use feroxfuzz::deciders::{StatusCodeDecider, ContentLengthDecider, LogicOperation}; use feroxfuzz::prelude::*; use feroxfuzz::fuzzers::BlockingFuzzer; // Decider 1: Discard 404 responses let status_decider = StatusCodeDecider::new(404, |expected, observed, _state| { if expected == observed { Action::Discard } else { Action::Keep } }); // Decider 2: Discard 403 responses let status_decider2 = StatusCodeDecider::new(403, |expected, observed, _state| { if expected == observed { Action::Discard } else { Action::Keep } }); let deciders = build_deciders!(status_decider, status_decider2); // Using AND logic: Both deciders must return Keep for the response to be kept // This creates a denylist effect - discard if ANY decider returns Discard let mut fuzzer = BlockingFuzzer::new() .client(client) .request(request) .scheduler(scheduler) .mutators(mutators) .observers(observers) .deciders(deciders) .post_send_logic(LogicOperation::And) // Denylist pattern .build(); // Using OR logic: Only one decider needs to return Keep // This creates an allowlist effect let mut fuzzer = BlockingFuzzer::new() .client(client) .request(request) .scheduler(scheduler) .mutators(mutators) .observers(observers) .deciders(deciders) .post_send_logic(LogicOperation::Or) // Allowlist pattern .build(); ``` -------------------------------- ### Manage SharedState for Fuzzer Coordination Source: https://context7.com/epi052/feroxfuzz/llms.txt Coordinate corpora, statistics, and PRNG state across multiple fuzzer components. ```rust use feroxfuzz::state::SharedState; use feroxfuzz::corpora::{Wordlist, RangeCorpus}; use feroxfuzz::Len; // Create state with a single corpus let words = Wordlist::with_words(["admin", "user"]).name("users").build(); let mut state = SharedState::with_corpus(words); // Create state with multiple corpora let users = Wordlist::with_words(["admin", "user"]).name("users").build(); let ids = RangeCorpus::with_stop(100).name("ids").build()?; let mut state = SharedState::with_corpora([users, ids]); // Add corpus after creation let passwords = Wordlist::with_words(["password", "123456"]).name("passwords").build(); state.add_corpus(passwords); // Set a specific seed for reproducible fuzzing state.set_seed(0xDEADBEEF); // Access corpus by name let corpus = state.corpus_by_name("users")?; assert_eq!(corpus.read().unwrap().len(), 2); // Get total items across all corpora let total = state.total_corpora_len(); ``` -------------------------------- ### Add Custom Metadata to SharedState Source: https://context7.com/epi052/feroxfuzz/llms.txt Define and add custom metadata structs implementing the Metadata trait to SharedState. Ensure `serde` and `typetag` are used for serialization and trait downcasting. ```rust use feroxfuzz::state::SharedState; use feroxfuzz::corpora::RangeCorpus; use feroxfuzz::metadata::{Metadata, AsAny, AsAnyMut}; use serde::{Serialize, Deserialize}; use std::any::Any; // Define custom metadata #[derive(Debug, Serialize, Deserialize)] struct FuzzingStats { interesting_count: u64, start_time: u64, } impl AsAny for FuzzingStats { fn as_any(&self) -> &dyn Any { self } } impl AsAnyMut for FuzzingStats { fn as_any_mut(&mut self) -> &mut dyn Any { self } } #[typetag::serde] impl Metadata for FuzzingStats { fn is_equal(&self, other: &dyn Any) -> bool { other.downcast_ref::() .is_some_and(|o| o.interesting_count == self.interesting_count) } } // Usage let corpus = RangeCorpus::with_stop(10).name("test").build()?; let state = SharedState::with_corpus(corpus); // Add metadata state.add_metadata("stats", FuzzingStats { interesting_count: 0, start_time: 1234567890, }); // Check if metadata exists if state.has_metadata("stats") { println!("Stats metadata exists"); } // Thread-safe conditional insertion state.add_metadata_if_absent("stats", FuzzingStats { interesting_count: 0, start_time: 0, }); // Returns false if already exists ``` -------------------------------- ### Implement RequestProcessor for Pre-Send Processing Source: https://context7.com/epi052/feroxfuzz/llms.txt Modifies or inspects requests before they are sent to the target. Useful for logging request details or debugging mutation results. ```rust use feroxfuzz::processors::RequestProcessor; use feroxfuzz::prelude::*; // Log all requests being sent let request_logger = RequestProcessor::new(|request, _action, _state| { println!("Sending: {} {}", request.method(), request.original_url()); if let Some(params) = request.params() { for (key, value) in params { print!(" {}={}", key, value); } println!(); } }); // Debug printer showing mutation results let debug_printer = RequestProcessor::new(|request, _action, _state| { print!("{}?", request.original_url()); if let Some(params) = request.params() { for (i, (key, value)) in params.iter().enumerate() { if i > 0 { print!("&"); } print!("{key}={value}"); } } println!(); }); ``` -------------------------------- ### Implement Cluster Bomb Attack Pattern Source: https://context7.com/epi052/feroxfuzz/llms.txt Uses ProductScheduler to fuzz all combinations of multiple parameters simultaneously. Requires multiple corpora and corresponding ReplaceKeyword mutators. ```rust use feroxfuzz::client::{BlockingClient, HttpClient}; use feroxfuzz::corpora::{Wordlist, RangeCorpus}; use feroxfuzz::fuzzers::BlockingFuzzer; use feroxfuzz::mutators::ReplaceKeyword; use feroxfuzz::observers::ResponseObserver; use feroxfuzz::prelude::*; use feroxfuzz::requests::ShouldFuzz; use feroxfuzz::responses::BlockingResponse; use feroxfuzz::schedulers::ProductScheduler; use std::time::Duration; fn main() -> Result<(), Box> { // Multiple corpora for different parameters let users = Wordlist::with_words(["admin", "user", "guest"]) .name("users") .build(); let ids = RangeCorpus::with_stop(5).name("ids").build()?; let mut state = SharedState::with_corpora([users, ids]); let req_client = reqwest::blocking::Client::builder() .timeout(Duration::from_secs(1)) .build()?; let client = BlockingClient::with_client(req_client); // Separate mutator for each keyword let user_mutator = ReplaceKeyword::new(&"USER", "users"); let id_mutator = ReplaceKeyword::new(&"ID", "ids"); let request = Request::from_url( "http://localhost:8000/?user=USER&id=ID", Some(&[ShouldFuzz::URLParameterValues]), )?; // ProductScheduler creates all combinations: // admin+0, admin+1, admin+2, admin+3, admin+4, // user+0, user+1, user+2, user+3, user+4, // guest+0, guest+1, guest+2, guest+3, guest+4 let order = ["users", "ids"]; let scheduler = ProductScheduler::new(order, state.clone())?; let response_observer: ResponseObserver = ResponseObserver::new(); let observers = build_observers!(response_observer); let mutators = build_mutators!(user_mutator, id_mutator); let mut fuzzer = BlockingFuzzer::new() .client(client) .request(request) .scheduler(scheduler) .mutators(mutators) .observers(observers) .build(); fuzzer.fuzz_once(&mut state)?; Ok(()) } ``` -------------------------------- ### ReplaceKeyword Mutator Usage Source: https://context7.com/epi052/feroxfuzz/llms.txt Configures keyword replacement in fuzzable data using corpus entries. Supports multiple mutators for different keywords within a single request. ```rust use feroxfuzz::mutators::ReplaceKeyword; use feroxfuzz::prelude::*; use feroxfuzz::requests::ShouldFuzz; use feroxfuzz::corpora::Wordlist; use feroxfuzz::state::SharedState; // Create corpus and state let words = Wordlist::with_words(["admin", "root", "user"]).name("users").build(); let mut state = SharedState::with_corpus(words); // Create mutator that replaces "FUZZ" with items from "users" corpus let mutator = ReplaceKeyword::new(&"FUZZ", "users"); // Request with FUZZ keyword in parameter value let request = Request::from_url( "http://localhost:8000/?username=FUZZ", Some(&[ShouldFuzz::URLParameterValues]), )?; // Multiple mutators for different keywords let user_mutator = ReplaceKeyword::new(&"USER", "users"); let pass_mutator = ReplaceKeyword::new(&"PASS", "passwords"); let request = Request::from_url( "http://localhost:8000/login?user=USER&pass=PASS", Some(&[ShouldFuzz::URLParameterValues]), )?; // Build mutators tuple for the fuzzer let mutators = build_mutators!(user_mutator, pass_mutator); ``` -------------------------------- ### StatusCodeDecider Implementation Source: https://context7.com/epi052/feroxfuzz/llms.txt Filters responses based on HTTP status codes using custom logic to keep, discard, or add to corpus. ```rust use feroxfuzz::deciders::StatusCodeDecider; use feroxfuzz::prelude::*; // Keep only 200 OK responses let decider = StatusCodeDecider::new(200, |expected, observed, _state| { if expected == observed { Action::Keep } else { Action::Discard } }); // Discard 404 Not Found responses (allowlist pattern) let decider = StatusCodeDecider::new(404, |expected, observed, _state| { if expected == observed { Action::Discard } else { Action::Keep } }); // Keep responses in 2xx range let decider = StatusCodeDecider::new(200, |_, observed, _state| { if (200..300).contains(&observed) { Action::Keep } else { Action::Discard } }); // Add to corpus when finding interesting responses let decider = StatusCodeDecider::new(200, |expected, observed, _state| { if expected == observed { Action::AddToCorpus("interesting".to_string(), CorpusItemType::Request) } else { Action::Discard } }); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.