From ad38b56473aff4c8791ea565a4007491638e9fc3 Mon Sep 17 00:00:00 2001 From: epi Date: Sun, 26 Feb 2023 06:39:03 -0600 Subject: [PATCH] finalized new detections; removed wildcard filter and supporting code --- src/filters/container.rs | 14 +- src/filters/mod.rs | 1 - src/filters/tests.rs | 75 ------ src/filters/wildcard.rs | 118 --------- src/heuristics.rs | 384 ++++++++--------------------- src/scan_manager/scan_container.rs | 6 +- src/scanner/ferox_scanner.rs | 21 +- src/traits.rs | 8 +- 8 files changed, 111 insertions(+), 516 deletions(-) delete mode 100644 src/filters/wildcard.rs diff --git a/src/filters/container.rs b/src/filters/container.rs index c44fc11..4404d10 100644 --- a/src/filters/container.rs +++ b/src/filters/container.rs @@ -10,7 +10,7 @@ use crate::{ use super::{ FeroxFilter, LinesFilter, RegexFilter, SimilarityFilter, SizeFilter, StatusCodeFilter, - WildcardFilter, WordsFilter, + WordsFilter, }; /// Container around a collection of `FeroxFilters`s @@ -76,13 +76,7 @@ impl FeroxFilters { for filter in filters.iter() { // wildcard.should_filter goes here if filter.should_filter_response(response) { - log::warn!("filtering response due to: {:?}", filter); - log::warn!("filtering response due to: {:?}", filters); - if filter.as_any().downcast_ref::().is_some() { - tx_stats - .send(AddToUsizeField(WildcardsFiltered, 1)) - .unwrap_or_default(); - } + log::debug!("filtering response due to: {:?}", filter); return true; } } @@ -116,10 +110,6 @@ impl Serialize for FeroxFilters { filter.as_any().downcast_ref::() { seq.serialize_element(similarity_filter).unwrap_or_default(); - } else if let Some(wildcard_filter) = - filter.as_any().downcast_ref::() - { - seq.serialize_element(wildcard_filter).unwrap_or_default(); } } seq.end() diff --git a/src/filters/mod.rs b/src/filters/mod.rs index 443230d..03bbfb0 100644 --- a/src/filters/mod.rs +++ b/src/filters/mod.rs @@ -15,7 +15,6 @@ pub use self::similarity::{SimilarityFilter, SIM_HASHER}; pub use self::size::SizeFilter; pub use self::status_code::StatusCodeFilter; pub(crate) use self::utils::{create_similarity_filter, filter_lookup}; -pub use self::wildcard::WildcardFilter; pub use self::words::WordsFilter; mod wildcard; diff --git a/src/filters/tests.rs b/src/filters/tests.rs index b48c71b..1a37131 100644 --- a/src/filters/tests.rs +++ b/src/filters/tests.rs @@ -1,29 +1,7 @@ use super::*; use ::fuzzyhash::FuzzyHash; use ::regex::Regex; -use super::similarity::HashValueType; -#[test] -/// simply test the default values for wildcardfilter, expect 0, 0 -fn wildcard_filter_default() { - let wcf = WildcardFilter::default(); - assert_eq!(wcf.size, u64::MAX); - assert_eq!(wcf.dynamic, u64::MAX); -} - -#[test] -/// just a simple test to increase code coverage by hitting as_any and the inner value -fn wildcard_filter_as_any() { - let filter = WildcardFilter::default(); - let filter2 = WildcardFilter::default(); - - assert!(filter.box_eq(filter2.as_any())); - - assert_eq!( - *filter.as_any().downcast_ref::().unwrap(), - filter - ); -} #[test] /// just a simple test to increase code coverage by hitting as_any and the inner value @@ -109,59 +87,6 @@ fn regex_filter_as_any() { ); } -#[test] -/// test should_filter on WilcardFilter where static logic matches -fn wildcard_should_filter_when_static_wildcard_found() { - let mut resp = FeroxResponse::default(); - resp.set_wildcard(true); - resp.set_url("http://localhost"); - resp.set_text( - "pellentesque diam volutpat commodo sed egestas egestas fringilla phasellus faucibus", - ); - - let filter = WildcardFilter { - size: 83, - dynamic: 0, - dont_filter: false, - method: "GET".to_owned(), - }; - - assert!(filter.should_filter_response(&resp)); -} - -#[test] -/// test should_filter on WilcardFilter where static logic matches but response length is 0 -fn wildcard_should_filter_when_static_wildcard_len_is_zero() { - let mut resp = FeroxResponse::default(); - resp.set_wildcard(true); - resp.set_url("http://localhost"); - - // default WildcardFilter is used in the code that executes when response.content_length() == 0 - let filter = WildcardFilter::new(false); - - assert!(filter.should_filter_response(&resp)); -} - -#[test] -/// test should_filter on WilcardFilter where dynamic logic matches -fn wildcard_should_filter_when_dynamic_wildcard_found() { - let mut resp = FeroxResponse::default(); - resp.set_wildcard(true); - resp.set_url("http://localhost/stuff"); - resp.set_text("pellentesque diam volutpat commodo sed egestas egestas fringilla"); - - let filter = WildcardFilter { - size: 0, - dynamic: 59, // content-length - 5 (len('stuff')) - dont_filter: false, - method: "GET".to_owned(), - }; - - println!("resp: {resp:?}: filter: {filter:?}"); - - assert!(filter.should_filter_response(&resp)); -} - #[test] /// test should_filter on RegexFilter where regex matches body fn regexfilter_should_filter_when_regex_matches_on_response_body() { diff --git a/src/filters/wildcard.rs b/src/filters/wildcard.rs deleted file mode 100644 index 8c08d9b..0000000 --- a/src/filters/wildcard.rs +++ /dev/null @@ -1,118 +0,0 @@ -use super::*; -use crate::{url::FeroxUrl, DEFAULT_METHOD}; - -/// Data holder for two pieces of data needed when auto-filtering out wildcard responses -/// -/// `dynamic` is the size of the response that will later be combined with the length -/// of the path of the url requested and used to determine interesting pages from custom -/// 404s where the requested url is reflected back in the response -/// -/// `size` is size of the response that should be included with filters passed via runtime -/// configuration and any static wildcard lengths. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct WildcardFilter { - /// size of the response that will later be combined with the length of the path of the url - /// requested - pub dynamic: u64, - - /// size of the response that should be included with filters passed via runtime configuration - pub size: u64, - - /// method used in request that should be included with filters passed via runtime configuration - pub method: String, - - /// whether or not the user passed -D on the command line - pub(super) dont_filter: bool, -} - -/// implementation of WildcardFilter -impl WildcardFilter { - /// given a boolean representing whether -D was used or not, create a new WildcardFilter - pub fn new(dont_filter: bool) -> Self { - Self { - dont_filter, - ..Default::default() - } - } -} - -/// implement default that populates both values with u64::MAX -impl Default for WildcardFilter { - /// populate both values with u64::MAX - fn default() -> Self { - Self { - dont_filter: false, - size: u64::MAX, - method: DEFAULT_METHOD.to_owned(), - dynamic: u64::MAX, - } - } -} - -/// implementation of FeroxFilter for WildcardFilter -impl FeroxFilter for WildcardFilter { - /// Examine size, dynamic, and content_len to determine whether or not the response received - /// is a wildcard response and therefore should be filtered out - fn should_filter_response(&self, response: &FeroxResponse) -> bool { - log::trace!("enter: should_filter_response({:?} {})", self, response); - - // quick return if dont_filter is set - if self.dont_filter { - // --dont-filter applies specifically to wildcard filters, it is not a 100% catch all - // for not filtering anything. As such, it should live in the implementation of - // a wildcard filter - return false; - } - - if self.size != u64::MAX - && self.size == response.content_length() - && self.method == response.method().as_str() - { - // static wildcard size found during testing - // size isn't default, size equals response length, and auto-filter is on - log::debug!("static wildcard: filtered out {}", response.url()); - log::trace!("exit: should_filter_response -> true"); - return true; - } - - if self.size == u64::MAX - && response.content_length() == 0 - && self.method == response.method().as_str() - { - // static wildcard size found during testing - // but response length was zero; pointed out by @Tib3rius - log::debug!("static wildcard: filtered out {}", response.url()); - log::trace!("exit: should_filter_response -> true"); - return true; - } - - if self.dynamic != u64::MAX { - // dynamic wildcard offset found during testing - - // I'm about to manually split this url path instead of using reqwest::Url's - // builtin parsing. The reason is that they call .split() on the url path - // except that I don't want an empty string taking up the last index in the - // event that the url ends with a forward slash. It's ugly enough to be split - // into its own function for readability. - let url_len = FeroxUrl::path_length_of_url(response.url()); - - if url_len + self.dynamic == response.content_length() { - log::debug!("dynamic wildcard: filtered out {}", response.url()); - log::trace!("exit: should_filter_response -> true"); - return true; - } - } - log::trace!("exit: should_filter_response -> false"); - false - } - - /// Compare one WildcardFilter to another - fn box_eq(&self, other: &dyn Any) -> bool { - other.downcast_ref::().map_or(false, |a| self == a) - } - - /// Return self as Any for dynamic dispatch purposes - fn as_any(&self) -> &dyn Any { - self - } -} diff --git a/src/heuristics.rs b/src/heuristics.rs index 95c4b51..685189b 100644 --- a/src/heuristics.rs +++ b/src/heuristics.rs @@ -11,7 +11,7 @@ use crate::nlp::preprocess; use crate::{ config::OutputLevel, event_handlers::{Command, Handles}, - filters::{LinesFilter, SizeFilter, WildcardFilter, WordsFilter}, + filters::{LinesFilter, SizeFilter, WordsFilter}, progress::PROGRESS_PRINTER, response::FeroxResponse, skip_fail, @@ -23,23 +23,6 @@ use crate::{ /// length of a standard UUID, used when determining wildcard responses const UUID_LENGTH: u64 = 32; -/// wrapper around ugly string formatting -macro_rules! format_template { - ($template:expr, $method:expr, $length:expr) => { - format!( - $template, - status_colorizer("WLD"), - $method, - "-", - "-", - "-", - style("auto-filtering").yellow(), - style($length).cyan(), - style("--dont-filter").yellow() - ) - }; -} - /// enum representing the different servers that `parse_html` can detect when directory listing is /// enabled #[derive(Copy, Debug, Clone)] @@ -76,26 +59,6 @@ pub struct HeuristicTests { handles: Arc, } -/// simple way to pass around a wildcard filter to the internal helper below -/// in a way that quickly tells us if it's static or dynamic -enum WildcardType<'a> { - Static(&'a WildcardFilter), - Dynamic(&'a WildcardFilter), -} - -/// internal helper to stop repeating the same pattern -fn print_dont_filter_message(wildcard_type: WildcardType, output_level: OutputLevel) { - if matches!(output_level, OutputLevel::Default | OutputLevel::Quiet) { - let msg = match wildcard_type { - WildcardType::Static(wc) => { - format_template!("{} {:>8} {:>9} {:>9} {:>9} Wildcard response is static; {} {} responses; toggle this behavior by using {}\n", wc.method.as_str(), wc.size) - } - WildcardType::Dynamic(wc) => format_template!("{} {:>8} {:>9} {:>9} {:>9} Wildcard response is dynamic; {} ({} + url length) responses; toggle this behavior by using {}\n", wc.method.as_str(), wc.dynamic), - }; - ferox_print(&msg, &PROGRESS_PRINTER); - } -} - /// HeuristicTests implementation impl HeuristicTests { /// create a new HeuristicTests struct @@ -122,167 +85,6 @@ impl HeuristicTests { unique_id } - /// wrapper for sending a filter to the filters event handler - fn send_filter(&self, filter: WildcardFilter) -> Result<()> { - self.handles - .filters - .send(Command::AddFilter(Box::new(filter))) - } - - /// Tests the given url to see if it issues a wildcard response - /// - /// In the event that url returns a wildcard response, a - /// [WildcardFilter](struct.WildcardFilter.html) is created and sent to the filters event - /// handler. - /// - /// Returns the number of times to increment the caller's progress bar - pub async fn wildcard(&self, target_url: &str) -> Result { - log::trace!("enter: wildcard_test({:?})", target_url); - - if self.handles.config.dont_filter { - // early return, dont_filter scans don't need tested - log::trace!("exit: wildcard_test -> 0"); - return Ok(0); - } - - let data = match self.handles.config.data.is_empty() { - true => None, - false => Some(self.handles.config.data.as_slice()), - }; - - let ferox_url = FeroxUrl::from_string(target_url, self.handles.clone()); - - for method in self.handles.config.methods.iter() { - let ferox_response = self - .make_wildcard_request(&ferox_url, method.as_str(), data, 1) - .await?; - - // found a wildcard response - let mut wildcard = WildcardFilter::new(self.handles.config.dont_filter); - - let wc_length = ferox_response.content_length(); - - if wc_length == 0 { - log::trace!("exit: wildcard_test -> 1"); - print_dont_filter_message( - WildcardType::Static(&wildcard), - self.handles.config.output_level, - ); - self.send_filter(wildcard)?; - return Ok(1); - } - - // content length of wildcard is non-zero, perform additional tests: - // make a second request, with a known-sized (64) longer request - let resp_two = self - .make_wildcard_request(&ferox_url, method.as_str(), data, 3) - .await?; - - let wc2_length = resp_two.content_length(); - - wildcard.method = resp_two.method().as_str().to_owned(); - - if wc2_length == wc_length + (UUID_LENGTH * 2) { - // second length is what we'd expect to see if the requested url is - // reflected in the response along with some static content; aka custom 404 - wildcard.dynamic = wc_length - UUID_LENGTH; - - print_dont_filter_message( - WildcardType::Dynamic(&wildcard), - self.handles.config.output_level, - ); - } else if wc_length == wc2_length { - wildcard.size = wc_length; - - print_dont_filter_message( - WildcardType::Static(&wildcard), - self.handles.config.output_level, - ); - } - - self.send_filter(wildcard)?; - } - - log::trace!("exit: wildcard_test"); - Ok(2) - } - - /// Generates a uuid and appends it to the given target url. The reasoning is that the randomly - /// generated unique string should not exist on and be served by the target web server. - /// - /// Once the unique url is created, the request is sent to the server. If the server responds - /// back with a valid status code, the response is considered to be a wildcard response. If that - /// wildcard response has a 3xx status code, that redirection location is displayed to the user. - async fn make_wildcard_request( - &self, - target: &FeroxUrl, - method: &str, - data: Option<&[u8]>, - length: usize, - ) -> Result { - log::trace!("enter: make_wildcard_request({}, {})", target, length); - - let unique_str = self.unique_string(length); - - // To take care of slash when needed - let slash = if self.handles.config.add_slash { - Some("/") - } else { - None - }; - - let nonexistent_url = target.format(&unique_str, slash)?; - - let response = logged_request( - &nonexistent_url.to_owned(), - method, - data, - self.handles.clone(), - ) - .await?; - - if self - .handles - .config - .status_codes - .contains(&response.status().as_u16()) - { - // found a wildcard response - - let mut ferox_response = FeroxResponse::from( - response, - &target.target, - method, - self.handles.config.output_level, - ) - .await; - ferox_response.set_wildcard(true); - - if self - .handles - .filters - .data - .should_filter_response(&ferox_response, self.handles.stats.tx.clone()) - { - bail!("filtered response") - } - - if matches!( - self.handles.config.output_level, - OutputLevel::Default | OutputLevel::Quiet - ) { - let boxed = Box::new(ferox_response.clone()); - self.handles.output.send(Command::Report(boxed))?; - } - - log::trace!("exit: make_wildcard_request -> {}", ferox_response); - return Ok(ferox_response); - } - - log::trace!("exit: make_wildcard_request -> Err"); - bail!("uninteresting status code") - } - /// Simply tries to connect to all given sites before starting to scan /// /// In the event that no sites can be reached, the program will exit. @@ -439,19 +241,17 @@ impl HeuristicTests { } /// given a target's base url, attempt to automatically detect its 404 response - /// pattern, and then set a filter that will exclude all but the first result - pub async fn detect_404_response(&self, target_url: &str) -> Result { - log::trace!("enter: detect_404_response({:?})", target_url); + /// pattern(s), and then set filters that will exclude those patterns from future + /// responses + pub async fn detect_404_like_responses(&self, target_url: &str) -> Result { + log::trace!("enter: detect_404_like_responses({:?})", target_url); if self.handles.config.dont_filter { // early return, dont_filter scans don't need tested - log::trace!("exit: detect_404_response -> dont_filter is true"); + log::trace!("exit: detect_404_like_responses -> dont_filter is true"); return Ok(0); } - let mut size_sentry = true; - let mut word_sentry = true; - let mut line_sentry = true; let mut req_counter = 0; let data = if self.handles.config.data.is_empty() { @@ -460,24 +260,33 @@ impl HeuristicTests { Some(self.handles.config.data.as_slice()) }; + // To take care of slash when needed + let slash = if self.handles.config.add_slash { + Some("/") + } else { + None + }; + // 4 is due to the array in the nested for loop below let mut responses = Vec::with_capacity(4); + // for every method, attempt to id its 404 response + // + // a good example of one where the GET/POST differ is on hackthebox: + // - http://prd.m.rendering-api.interface.htb/api for method in self.handles.config.methods.iter() { for (prefix, length) in [("", 1), ("", 3), (".htaccess", 1), ("admin", 1)] { let path = format!("{prefix}{}", self.unique_string(length)); - // To take care of slash when needed - let slash = if self.handles.config.add_slash { - Some("/") - } else { - None - }; - let ferox_url = FeroxUrl::from_string(target_url, self.handles.clone()); let nonexistent_url = ferox_url.format(&path, slash)?; + // example requests: + // - http://localhost/2fc1077836ad43ab98b7a31c2ca28fea + // - http://localhost/92969beae6bf4beb855d1622406d87e395c87387a9ad432e8a11245002b709b03cf609d471004154b83bcc1c6ec49f6f + // - http://localhost/.htaccessa005a2131e68449aa26e99029c914c09 + // - http://localhost/adminf1d2541e73c44dcb9d1fb7d93334b280 let response = logged_request(&nonexistent_url, &method, data, self.handles.clone()).await; @@ -512,74 +321,18 @@ impl HeuristicTests { if responses.len() < 2 { // don't have enough responses to make a determination, continue to next method + responses.clear(); continue; } - // examine chars/words/lines for each response - // if all responses respetive length match each other, we can assume - // that will remain true for subsequent non-existent urls, and create - // a filter for it. - // - // values are examined from most to least specific (content length, word count, line count) - let content_length = responses[0].content_length(); - let word_count = responses[0].word_count(); - let line_count = responses[0].line_count(); - - for response in &responses[1..] { - // if any of the responses differ in length, that particular - // response length type is no longer a canidate for filtering - if response.content_length() != content_length { - size_sentry = false; - } - - if response.word_count() != word_count { - word_sentry = false; - } - - if response.line_count() != line_count { - line_sentry = false; - } - } - - // the if/else-if/else nature of the block means that we'll get the most - // specific match, if one is to be had - // - // each block returns the information needed to send the filter away and - // display a message to the user - let (command, filter_type, filter_length) = if size_sentry { - log::info!( - "[404-like] {target_url} => filtering future responses with {content_length} bytes" - ); - ( - Command::AddFilter(Box::new(SizeFilter { content_length })), - "bytes", - content_length as usize, - ) - } else if word_sentry { - log::info!( - "[404-like] {target_url} => filtering future responses with {word_count} words" - ); - ( - Command::AddFilter(Box::new(WordsFilter { word_count })), - "words", - word_count, - ) - } else if line_sentry { - log::info!( - "[404-like] {target_url} => filtering future responses with {line_count} lines" - ); - ( - Command::AddFilter(Box::new(LinesFilter { line_count })), - "lines", - line_count, - ) - } else { - log::trace!("exit: detect_404_response -> no filter added"); - // no match was found; clear the vec and continue to the next + // Command::AddFilter, &str (bytes/words/lines), usize (i.e. length associated with the type) + let Some((command, filter_type, filter_length)) = self.examine_404_like_responses(&responses) else { + // no match was found during analysis of responses responses.clear(); continue; }; + // check whether we already know about this filter match command { Command::AddFilter(ref filter) => { if let Ok(guard) = self.handles.filters.data.filters.read() { @@ -590,10 +343,14 @@ impl HeuristicTests { } } } - _ => {} + _ => unreachable!(), } - // if we're here, we've detected a 404-like response pattern, so we're already filtering for size/word/line + // create the new filter + self.handles.filters.send(command)?; + + // if we're here, we've detected a 404-like response pattern, and we're already filtering for size/word/line + // // in addition, we'll create a similarity filter as a fallback let hash = SIM_HASHER.create_signature(preprocess(responses[0].text()).iter()); @@ -602,14 +359,14 @@ impl HeuristicTests { original_url: responses[0].url().to_string(), }; - self.handles.filters.send(command)?; + self.handles + .filters + .send(Command::AddFilter(Box::new(sim_filter)))?; // reset the responses for the next method, if it exists responses.clear(); - self.handles - .filters - .send(Command::AddFilter(Box::new(sim_filter)))?; + // report to the user, if appropriate if matches!( self.handles.config.output_level, OutputLevel::Default | OutputLevel::Quiet @@ -619,10 +376,75 @@ impl HeuristicTests { } } - log::trace!("exit: detect_404_response"); + log::trace!("exit: detect_404_like_responses"); return Ok(req_counter); } + + /// for all responses, examine chars/words/lines + /// if all responses respective lengths match each other, we can assume + /// that will remain true for subsequent non-existent urls + /// + /// values are examined from most to least specific (content length, word count, line count) + fn examine_404_like_responses( + &self, + responses: &[FeroxResponse], + ) -> Option<(Command, &'static str, usize)> { + let mut size_sentry = true; + let mut word_sentry = true; + let mut line_sentry = true; + + let content_length = responses[0].content_length(); + let word_count = responses[0].word_count(); + let line_count = responses[0].line_count(); + + for response in &responses[1..] { + // if any of the responses differ in length, that particular + // response length type is no longer a candidate for filtering + if response.content_length() != content_length { + size_sentry = false; + } + + if response.word_count() != word_count { + word_sentry = false; + } + + if response.line_count() != line_count { + line_sentry = false; + } + } + + // the if/else-if/else nature of the block means that we'll get the most + // specific match, if one is to be had + // + // each block returns the information needed to send the filter away and + // display a message to the user + if size_sentry { + // - command to send to the filters handler + // - the unit-type we're filtering on (bytes/words/lines) + // - the value associated with the unit-type on which we're filtering + Some(( + Command::AddFilter(Box::new(SizeFilter { content_length })), + "bytes", + content_length as usize, + )) + } else if word_sentry { + Some(( + Command::AddFilter(Box::new(WordsFilter { word_count })), + "words", + word_count, + )) + } else if line_sentry { + Some(( + Command::AddFilter(Box::new(LinesFilter { line_count })), + "lines", + line_count, + )) + } else { + // no match was found; clear the vec and continue to the next + None + } + } } #[cfg(test)] diff --git a/src/scan_manager/scan_container.rs b/src/scan_manager/scan_container.rs index d3118bb..290e22c 100644 --- a/src/scan_manager/scan_container.rs +++ b/src/scan_manager/scan_container.rs @@ -3,7 +3,7 @@ use super::*; use crate::event_handlers::Handles; use crate::filters::{ EmptyFilter, LinesFilter, RegexFilter, SimilarityFilter, SizeFilter, StatusCodeFilter, - WildcardFilter, WordsFilter, + WordsFilter, }; use crate::traits::FeroxFilter; use crate::Command::AddFilter; @@ -182,10 +182,6 @@ impl FeroxScans { serde_json::from_value::(filter.clone()) { Box::new(deserialized) - } else if let Ok(deserialized) = - serde_json::from_value::(filter.clone()) - { - Box::new(deserialized) } else if let Ok(deserialized) = serde_json::from_value::(filter.clone()) { diff --git a/src/scanner/ferox_scanner.rs b/src/scanner/ferox_scanner.rs index 43bf14c..97693e8 100644 --- a/src/scanner/ferox_scanner.rs +++ b/src/scanner/ferox_scanner.rs @@ -298,25 +298,12 @@ impl FeroxScanner { // the server is using to respond to resources that don't exist (could be a // traditional 404, or a custom response) // - // `detect_404_response` will make the requests that the wildcard test used to - // perform pre-2.8, and then hand those off to `wildcard`, so we're not - // duplicating effort. - // - // the wildcard test will only add a filter in the event that the filter it - // would create isn't already being filtered by the user or by the - // auto-detected 404-like response - let num_reqs_made = test.detect_404_response(&self.target_url).await?; + // `detect_404_like_responses` will make the requests that the wildcard test used to + // perform pre-2.8 in addition to new detection techniques, superseding the old + // wildcard test + let num_reqs_made = test.detect_404_like_responses(&self.target_url).await?; - - // let num_reqs_made = test.wildcard(detection_responses).await.unwrap_or_default(); progress_bar.inc(num_reqs_made); - - // if !detected { - // // on error, we'll have 0, same for --dont-filter - // // anything higher than 0 indicates a wildcard was found - // let num_reqs_made = test.wildcard(&self.target_url).await.unwrap_or_default(); - // progress_bar.inc(num_reqs_made); - // } } // Arc clones to be passed around to the various scans diff --git a/src/traits.rs b/src/traits.rs index 3800951..ecbacdd 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,6 +1,6 @@ //! collection of all traits used use crate::filters::{ - LinesFilter, RegexFilter, SimilarityFilter, SizeFilter, StatusCodeFilter, WildcardFilter, + LinesFilter, RegexFilter, SimilarityFilter, SizeFilter, StatusCodeFilter, WordsFilter, }; use crate::response::FeroxResponse; @@ -37,12 +37,6 @@ impl Display for dyn FeroxFilter { write!(f, "Response size: {}", style(filter.content_length).cyan()) } else if let Some(filter) = self.as_any().downcast_ref::() { write!(f, "Regex: {}", style(&filter.raw_string).cyan()) - } else if let Some(filter) = self.as_any().downcast_ref::() { - if filter.dynamic != u64::MAX { - write!(f, "Dynamic wildcard: {}", style(filter.dynamic).cyan()) - } else { - write!(f, "Static wildcard: {}", style(filter.size).cyan()) - } } else if let Some(filter) = self.as_any().downcast_ref::() { write!(f, "Status code: {}", style(filter.filter_code).cyan()) } else if let Some(filter) = self.as_any().downcast_ref::() {