mirror of
https://github.com/epi052/feroxbuster.git
synced 2026-06-08 02:31:16 -03:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cfb006190 | ||
|
|
88cb2a81ca | ||
|
|
b1066cce42 | ||
|
|
0d0d3198e9 |
2
.github/stale.yml
vendored
2
.github/stale.yml
vendored
@@ -1,5 +1,5 @@
|
|||||||
# Number of days of inactivity before an issue becomes stale
|
# Number of days of inactivity before an issue becomes stale
|
||||||
daysUntilStale: 21
|
daysUntilStale: 14
|
||||||
# Number of days of inactivity before a stale issue is closed
|
# Number of days of inactivity before a stale issue is closed
|
||||||
daysUntilClose: 7
|
daysUntilClose: 7
|
||||||
# Issues with these labels will never be considered stale
|
# Issues with these labels will never be considered stale
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "feroxbuster"
|
name = "feroxbuster"
|
||||||
version = "1.10.2"
|
version = "1.10.3"
|
||||||
authors = ["Ben 'epi' Risher <epibar052@gmail.com>"]
|
authors = ["Ben 'epi' Risher <epibar052@gmail.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|||||||
BIN
img/insecure.png
Normal file
BIN
img/insecure.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 286 KiB |
11
src/main.rs
11
src/main.rs
@@ -176,6 +176,7 @@ async fn scan(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut tasks = vec![];
|
let mut tasks = vec![];
|
||||||
|
let num_targets = targets.len();
|
||||||
|
|
||||||
for target in targets {
|
for target in targets {
|
||||||
let word_clone = words.clone();
|
let word_clone = words.clone();
|
||||||
@@ -184,7 +185,15 @@ async fn scan(
|
|||||||
|
|
||||||
let task = tokio::spawn(async move {
|
let task = tokio::spawn(async move {
|
||||||
let base_depth = get_current_depth(&target);
|
let base_depth = get_current_depth(&target);
|
||||||
scan_url(&target, word_clone, base_depth, term_clone, file_clone).await;
|
scan_url(
|
||||||
|
&target,
|
||||||
|
word_clone,
|
||||||
|
base_depth,
|
||||||
|
num_targets,
|
||||||
|
term_clone,
|
||||||
|
file_clone,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
});
|
});
|
||||||
|
|
||||||
tasks.push(task);
|
tasks.push(task);
|
||||||
|
|||||||
@@ -97,14 +97,16 @@ fn spawn_recursion_handler(
|
|||||||
mut recursion_channel: UnboundedReceiver<String>,
|
mut recursion_channel: UnboundedReceiver<String>,
|
||||||
wordlist: Arc<HashSet<String>>,
|
wordlist: Arc<HashSet<String>>,
|
||||||
base_depth: usize,
|
base_depth: usize,
|
||||||
|
num_targets: usize,
|
||||||
tx_term: UnboundedSender<FeroxResponse>,
|
tx_term: UnboundedSender<FeroxResponse>,
|
||||||
tx_file: UnboundedSender<FeroxResponse>,
|
tx_file: UnboundedSender<FeroxResponse>,
|
||||||
) -> BoxFuture<'static, Vec<JoinHandle<()>>> {
|
) -> BoxFuture<'static, Vec<JoinHandle<()>>> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"enter: spawn_recursion_handler({:?}, wordlist[{} words...], {}, {:?}, {:?})",
|
"enter: spawn_recursion_handler({:?}, wordlist[{} words...], {}, {}, {:?}, {:?})",
|
||||||
recursion_channel,
|
recursion_channel,
|
||||||
wordlist.len(),
|
wordlist.len(),
|
||||||
base_depth,
|
base_depth,
|
||||||
|
num_targets,
|
||||||
tx_term,
|
tx_term,
|
||||||
tx_file
|
tx_file
|
||||||
);
|
);
|
||||||
@@ -132,6 +134,7 @@ fn spawn_recursion_handler(
|
|||||||
resp_clone.to_owned().as_str(),
|
resp_clone.to_owned().as_str(),
|
||||||
list_clone,
|
list_clone,
|
||||||
base_depth,
|
base_depth,
|
||||||
|
num_targets,
|
||||||
term_clone,
|
term_clone,
|
||||||
file_clone,
|
file_clone,
|
||||||
)
|
)
|
||||||
@@ -453,14 +456,16 @@ pub async fn scan_url(
|
|||||||
target_url: &str,
|
target_url: &str,
|
||||||
wordlist: Arc<HashSet<String>>,
|
wordlist: Arc<HashSet<String>>,
|
||||||
base_depth: usize,
|
base_depth: usize,
|
||||||
|
num_targets: usize,
|
||||||
tx_term: UnboundedSender<FeroxResponse>,
|
tx_term: UnboundedSender<FeroxResponse>,
|
||||||
tx_file: UnboundedSender<FeroxResponse>,
|
tx_file: UnboundedSender<FeroxResponse>,
|
||||||
) {
|
) {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"enter: scan_url({:?}, wordlist[{} words...], {}, {:?}, {:?})",
|
"enter: scan_url({:?}, wordlist[{} words...], {}, {}, {:?}, {:?})",
|
||||||
target_url,
|
target_url,
|
||||||
wordlist.len(),
|
wordlist.len(),
|
||||||
base_depth,
|
base_depth,
|
||||||
|
num_targets,
|
||||||
tx_term,
|
tx_term,
|
||||||
tx_file
|
tx_file
|
||||||
);
|
);
|
||||||
@@ -469,7 +474,7 @@ pub async fn scan_url(
|
|||||||
|
|
||||||
let (tx_dir, rx_dir): FeroxChannel<String> = mpsc::unbounded_channel();
|
let (tx_dir, rx_dir): FeroxChannel<String> = mpsc::unbounded_channel();
|
||||||
|
|
||||||
if CALL_COUNT.load(Ordering::Relaxed) == 0 {
|
if CALL_COUNT.load(Ordering::Relaxed) < num_targets {
|
||||||
CALL_COUNT.fetch_add(1, Ordering::Relaxed);
|
CALL_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
// this protection allows us to add the first scanned url to SCANNED_URLS
|
// this protection allows us to add the first scanned url to SCANNED_URLS
|
||||||
@@ -515,6 +520,7 @@ pub async fn scan_url(
|
|||||||
rx_dir,
|
rx_dir,
|
||||||
recurser_words,
|
recurser_words,
|
||||||
base_depth,
|
base_depth,
|
||||||
|
num_targets,
|
||||||
recurser_term_clone,
|
recurser_term_clone,
|
||||||
recurser_file_clone,
|
recurser_file_clone,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -90,6 +90,50 @@ fn test_one_good_and_one_bad_target_scan_succeeds() -> Result<(), Box<dyn std::e
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// test pipes two good targets to the scanner, expected result is that both targets
|
||||||
|
/// are scanned successfully and no error is reported (result of issue #169)
|
||||||
|
fn test_two_good_targets_scan_succeeds() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let srv = MockServer::start();
|
||||||
|
let srv2 = MockServer::start();
|
||||||
|
|
||||||
|
let urls = vec![srv.url("/"), srv2.url("/"), String::from("LICENSE")];
|
||||||
|
let (tmp_dir, file) = setup_tmp_directory(&urls, "wordlist")?;
|
||||||
|
|
||||||
|
let mock = srv.mock(|when, then| {
|
||||||
|
when.method(GET).path("/LICENSE");
|
||||||
|
then.status(200).body("this is a test");
|
||||||
|
});
|
||||||
|
|
||||||
|
let mock2 = srv2.mock(|when, then| {
|
||||||
|
when.method(GET).path("/LICENSE");
|
||||||
|
then.status(403).body("this also is a test");
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut cmd = Command::cargo_bin("feroxbuster").unwrap();
|
||||||
|
|
||||||
|
cmd.arg("--stdin")
|
||||||
|
.arg("--wordlist")
|
||||||
|
.arg(file.as_os_str())
|
||||||
|
.pipe_stdin(file)
|
||||||
|
.unwrap()
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout(
|
||||||
|
predicate::str::contains("/LICENSE")
|
||||||
|
.and(predicate::str::contains("200"))
|
||||||
|
.and(predicate::str::contains("403"))
|
||||||
|
.and(predicate::str::contains("14c"))
|
||||||
|
.and(predicate::str::contains("19c")),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(mock.hits(), 1);
|
||||||
|
assert_eq!(mock2.hits(), 1);
|
||||||
|
|
||||||
|
teardown_tmp_directory(tmp_dir);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
/// test finds a static wildcard and reports as much to stdout
|
/// test finds a static wildcard and reports as much to stdout
|
||||||
fn test_static_wildcard_request_found() -> Result<(), Box<dyn std::error::Error>> {
|
fn test_static_wildcard_request_found() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|||||||
Reference in New Issue
Block a user