mirror of
https://github.com/epi052/feroxbuster.git
synced 2026-06-03 23:11:12 -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
|
||||
daysUntilStale: 21
|
||||
daysUntilStale: 14
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "feroxbuster"
|
||||
version = "1.10.2"
|
||||
version = "1.10.3"
|
||||
authors = ["Ben 'epi' Risher <epibar052@gmail.com>"]
|
||||
license = "MIT"
|
||||
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 num_targets = targets.len();
|
||||
|
||||
for target in targets {
|
||||
let word_clone = words.clone();
|
||||
@@ -184,7 +185,15 @@ async fn scan(
|
||||
|
||||
let task = tokio::spawn(async move {
|
||||
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);
|
||||
|
||||
@@ -97,14 +97,16 @@ fn spawn_recursion_handler(
|
||||
mut recursion_channel: UnboundedReceiver<String>,
|
||||
wordlist: Arc<HashSet<String>>,
|
||||
base_depth: usize,
|
||||
num_targets: usize,
|
||||
tx_term: UnboundedSender<FeroxResponse>,
|
||||
tx_file: UnboundedSender<FeroxResponse>,
|
||||
) -> BoxFuture<'static, Vec<JoinHandle<()>>> {
|
||||
log::trace!(
|
||||
"enter: spawn_recursion_handler({:?}, wordlist[{} words...], {}, {:?}, {:?})",
|
||||
"enter: spawn_recursion_handler({:?}, wordlist[{} words...], {}, {}, {:?}, {:?})",
|
||||
recursion_channel,
|
||||
wordlist.len(),
|
||||
base_depth,
|
||||
num_targets,
|
||||
tx_term,
|
||||
tx_file
|
||||
);
|
||||
@@ -132,6 +134,7 @@ fn spawn_recursion_handler(
|
||||
resp_clone.to_owned().as_str(),
|
||||
list_clone,
|
||||
base_depth,
|
||||
num_targets,
|
||||
term_clone,
|
||||
file_clone,
|
||||
)
|
||||
@@ -453,14 +456,16 @@ pub async fn scan_url(
|
||||
target_url: &str,
|
||||
wordlist: Arc<HashSet<String>>,
|
||||
base_depth: usize,
|
||||
num_targets: usize,
|
||||
tx_term: UnboundedSender<FeroxResponse>,
|
||||
tx_file: UnboundedSender<FeroxResponse>,
|
||||
) {
|
||||
log::trace!(
|
||||
"enter: scan_url({:?}, wordlist[{} words...], {}, {:?}, {:?})",
|
||||
"enter: scan_url({:?}, wordlist[{} words...], {}, {}, {:?}, {:?})",
|
||||
target_url,
|
||||
wordlist.len(),
|
||||
base_depth,
|
||||
num_targets,
|
||||
tx_term,
|
||||
tx_file
|
||||
);
|
||||
@@ -469,7 +474,7 @@ pub async fn scan_url(
|
||||
|
||||
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);
|
||||
|
||||
// this protection allows us to add the first scanned url to SCANNED_URLS
|
||||
@@ -515,6 +520,7 @@ pub async fn scan_url(
|
||||
rx_dir,
|
||||
recurser_words,
|
||||
base_depth,
|
||||
num_targets,
|
||||
recurser_term_clone,
|
||||
recurser_file_clone,
|
||||
)
|
||||
|
||||
@@ -90,6 +90,50 @@ fn test_one_good_and_one_bad_target_scan_succeeds() -> Result<(), Box<dyn std::e
|
||||
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 finds a static wildcard and reports as much to stdout
|
||||
fn test_static_wildcard_request_found() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
Reference in New Issue
Block a user