mirror of
https://github.com/epi052/feroxbuster.git
synced 2026-06-02 05:41:13 -03:00
fixed collect backups filtering (#1016)
* fixed collect backups filtering and clippy * added test for filtered backups
This commit is contained in:
@@ -328,6 +328,21 @@ impl TermOutHandler {
|
||||
)
|
||||
.await;
|
||||
|
||||
let Some(handles) = self.handles.as_ref() else {
|
||||
// shouldn't ever happen, but we'll log and return early if it does
|
||||
log::error!("handles were unexpectedly None, this shouldn't happen");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if handles
|
||||
.filters
|
||||
.data
|
||||
.should_filter_response(&ferox_response, tx_stats.clone())
|
||||
{
|
||||
// response was filtered for one reason or another, don't process it
|
||||
continue;
|
||||
}
|
||||
|
||||
self.process_response(
|
||||
tx_stats.clone(),
|
||||
Box::new(ferox_response),
|
||||
|
||||
@@ -35,7 +35,7 @@ impl Document {
|
||||
fn add_term(&mut self, word: &str) {
|
||||
let term = Term::new(word);
|
||||
|
||||
let metadata = self.terms.entry(term).or_insert_with(TermMetaData::new);
|
||||
let metadata = self.terms.entry(term).or_default();
|
||||
*metadata.count_mut() += 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,11 +35,6 @@ pub(super) struct TermMetaData {
|
||||
}
|
||||
|
||||
impl TermMetaData {
|
||||
/// create a new metadata container
|
||||
pub(super) fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// number of times a `Term` has appeared in any `Document` within the corpus
|
||||
pub(super) fn document_frequency(&self) -> usize {
|
||||
self.term_frequencies().len()
|
||||
@@ -90,7 +85,7 @@ mod tests {
|
||||
#[test]
|
||||
/// test accessors for correctness
|
||||
fn nlp_term_metadata_accessor_test() {
|
||||
let mut metadata = TermMetaData::new();
|
||||
let mut metadata = TermMetaData::default();
|
||||
|
||||
*metadata.count_mut() += 1;
|
||||
assert_eq!(metadata.count(), 1);
|
||||
|
||||
@@ -251,60 +251,57 @@ impl FeroxScanner {
|
||||
// heuristics test block:
|
||||
let test = heuristics::HeuristicTests::new(self.handles.clone());
|
||||
|
||||
if let Ok(dirlist_result) = test.directory_listing(&self.target_url).await {
|
||||
if dirlist_result.is_some() {
|
||||
let dirlist_result = dirlist_result.unwrap();
|
||||
// at this point, we have a DirListingType, and it's not the None variant
|
||||
// which means we found directory listing based on the heuristic; now we need
|
||||
// to process the links that are available if --extract-links was used
|
||||
if let Ok(Some(dirlist_result)) = test.directory_listing(&self.target_url).await {
|
||||
// at this point, we have a DirListingType, and it's not the None variant
|
||||
// which means we found directory listing based on the heuristic; now we need
|
||||
// to process the links that are available if --extract-links was used
|
||||
|
||||
if self.handles.config.extract_links {
|
||||
let mut extractor = ExtractorBuilder::default()
|
||||
.response(&dirlist_result.response)
|
||||
.target(ExtractionTarget::DirectoryListing)
|
||||
.url(&self.target_url)
|
||||
.handles(self.handles.clone())
|
||||
.build()?;
|
||||
if self.handles.config.extract_links {
|
||||
let mut extractor = ExtractorBuilder::default()
|
||||
.response(&dirlist_result.response)
|
||||
.target(ExtractionTarget::DirectoryListing)
|
||||
.url(&self.target_url)
|
||||
.handles(self.handles.clone())
|
||||
.build()?;
|
||||
|
||||
let result = extractor.extract_from_dir_listing().await?;
|
||||
let result = extractor.extract_from_dir_listing().await?;
|
||||
|
||||
extraction_tasks.push(extractor.request_links(result).await?);
|
||||
extraction_tasks.push(extractor.request_links(result).await?);
|
||||
|
||||
log::trace!("exit: scan_url -> Directory listing heuristic");
|
||||
log::trace!("exit: scan_url -> Directory listing heuristic");
|
||||
|
||||
self.handles.stats.send(AddToF64Field(
|
||||
DirScanTimes,
|
||||
scan_timer.elapsed().as_secs_f64(),
|
||||
))?;
|
||||
self.handles.stats.send(AddToF64Field(
|
||||
DirScanTimes,
|
||||
scan_timer.elapsed().as_secs_f64(),
|
||||
))?;
|
||||
|
||||
self.handles.stats.send(SubtractFromUsizeField(
|
||||
TotalExpected,
|
||||
progress_bar.length().unwrap_or(0) as usize,
|
||||
))?;
|
||||
self.handles.stats.send(SubtractFromUsizeField(
|
||||
TotalExpected,
|
||||
progress_bar.length().unwrap_or(0) as usize,
|
||||
))?;
|
||||
}
|
||||
|
||||
let mut message = format!("=> {}", style("Directory listing").blue().bright());
|
||||
|
||||
if !self.handles.config.extract_links {
|
||||
write!(
|
||||
message,
|
||||
" (remove {} to scan)",
|
||||
style("--dont-extract-links").bright().yellow()
|
||||
)?;
|
||||
}
|
||||
|
||||
if !self.handles.config.force_recursion {
|
||||
for handle in extraction_tasks.into_iter().flatten() {
|
||||
_ = handle.await;
|
||||
}
|
||||
|
||||
let mut message = format!("=> {}", style("Directory listing").blue().bright());
|
||||
progress_bar.reset_eta();
|
||||
progress_bar.finish_with_message(message);
|
||||
|
||||
if !self.handles.config.extract_links {
|
||||
write!(
|
||||
message,
|
||||
" (remove {} to scan)",
|
||||
style("--dont-extract-links").bright().yellow()
|
||||
)?;
|
||||
}
|
||||
ferox_scan.finish()?;
|
||||
|
||||
if !self.handles.config.force_recursion {
|
||||
for handle in extraction_tasks.into_iter().flatten() {
|
||||
_ = handle.await;
|
||||
}
|
||||
|
||||
progress_bar.reset_eta();
|
||||
progress_bar.finish_with_message(message);
|
||||
|
||||
ferox_scan.finish()?;
|
||||
|
||||
return Ok(()); // nothing left to do if we found a dir listing
|
||||
}
|
||||
return Ok(()); // nothing left to do if we found a dir listing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -247,3 +247,46 @@ fn filters_similar_should_filter_response() {
|
||||
assert_eq!(not_similar.hits(), 1);
|
||||
teardown_tmp_directory(tmp_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// when using --collect-backups, should only see results in output
|
||||
/// when the response shouldn't be otherwise filtered
|
||||
fn collect_backups_should_be_filtered() {
|
||||
let srv = MockServer::start();
|
||||
let (tmp_dir, file) = setup_tmp_directory(&["LICENSE".to_string()], "wordlist").unwrap();
|
||||
|
||||
let mock = srv.mock(|when: httpmock::When, then| {
|
||||
when.method(GET).path("/LICENSE");
|
||||
then.status(200).body("this is a test");
|
||||
});
|
||||
|
||||
let mock_two = srv.mock(|when, then| {
|
||||
when.method(GET).path("/LICENSE.bak");
|
||||
then.status(201)
|
||||
.body("im a backup file, but filtered out because im not 200");
|
||||
});
|
||||
|
||||
let cmd = Command::cargo_bin("feroxbuster")
|
||||
.unwrap()
|
||||
.arg("--url")
|
||||
.arg(srv.url("/"))
|
||||
.arg("--wordlist")
|
||||
.arg(file.as_os_str())
|
||||
.arg("--status-codes")
|
||||
.arg("200")
|
||||
.arg("--collect-backups")
|
||||
.unwrap();
|
||||
|
||||
cmd.assert().success().stdout(
|
||||
predicate::str::contains("/LICENSE")
|
||||
.and(predicate::str::contains("200"))
|
||||
.and(predicate::str::contains("/LICENSE.bak"))
|
||||
.not()
|
||||
.and(predicate::str::contains("201"))
|
||||
.not(),
|
||||
);
|
||||
|
||||
assert_eq!(mock.hits(), 1);
|
||||
assert_eq!(mock_two.hits(), 1);
|
||||
teardown_tmp_directory(tmp_dir);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user