mirror of
https://github.com/epi052/feroxbuster.git
synced 2026-05-29 18:51:12 -03:00
Init commit for
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -602,7 +602,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "feroxbuster"
|
||||
version = "2.4.2"
|
||||
version = "2.5.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "feroxbuster"
|
||||
version = "2.4.2"
|
||||
version = "2.5.0"
|
||||
authors = ["Ben 'epi' Risher <epibar052@gmail.com>"]
|
||||
license = "MIT"
|
||||
edition = "2018"
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
# insecure = true
|
||||
# extensions = ["php", "html"]
|
||||
# methods = ["GET", "POST"]
|
||||
# data = [11, 12, 13, 14, 15]
|
||||
# url_denylist = ["http://dont-scan.me", "https://also-not.me"]
|
||||
# regex_denylist = ["/deny.*"]
|
||||
# no_recursion = true
|
||||
|
||||
@@ -43,6 +43,7 @@ _feroxbuster() {
|
||||
'*--extensions=[File extension(s) to search for (ex: -x php -x pdf js)]' \
|
||||
'*-m+[HTTP request method(s) to search for (default: \[GET\])]' \
|
||||
'*--methods=[HTTP request method(s) to search for (default: \[GET\])]' \
|
||||
'--data=[HTTP Body data (default: empty)]' \
|
||||
'*--dont-scan=[URL(s) or Regex Pattern(s) to exclude from recursion/scans]' \
|
||||
'*-H+[Specify HTTP headers (ex: -H Header:val '\''stuff: things'\'')]' \
|
||||
'*--headers=[Specify HTTP headers (ex: -H Header:val '\''stuff: things'\'')]' \
|
||||
|
||||
@@ -48,6 +48,7 @@ Register-ArgumentCompleter -Native -CommandName 'feroxbuster' -ScriptBlock {
|
||||
[CompletionResult]::new('--extensions', 'extensions', [CompletionResultType]::ParameterName, 'File extension(s) to search for (ex: -x php -x pdf js)')
|
||||
[CompletionResult]::new('-m', 'm', [CompletionResultType]::ParameterName, 'HTTP request method(s) to search for (default: [GET])')
|
||||
[CompletionResult]::new('--methods', 'methods', [CompletionResultType]::ParameterName, 'HTTP request method(s) to search for (default: [GET])')
|
||||
[CompletionResult]::new('--data', 'data', [CompletionResultType]::ParameterName, 'HTTP Body data (default: empty)')
|
||||
[CompletionResult]::new('--dont-scan', 'dont-scan', [CompletionResultType]::ParameterName, 'URL(s) or Regex Pattern(s) to exclude from recursion/scans')
|
||||
[CompletionResult]::new('-H', 'H', [CompletionResultType]::ParameterName, 'Specify HTTP headers (ex: -H Header:val ''stuff: things'')')
|
||||
[CompletionResult]::new('--headers', 'headers', [CompletionResultType]::ParameterName, 'Specify HTTP headers (ex: -H Header:val ''stuff: things'')')
|
||||
|
||||
@@ -20,7 +20,7 @@ _feroxbuster() {
|
||||
|
||||
case "${cmd}" in
|
||||
feroxbuster)
|
||||
opts=" -v -q -D -A -r -k -n -f -e -h -V -w -u -t -d -T -p -P -R -s -o -a -x -m -H -Q -S -X -W -N -C -L --verbosity --silent --quiet --auto-tune --auto-bail --json --dont-filter --random-agent --redirects --insecure --no-recursion --add-slash --stdin --extract-links --help --version --wordlist --url --threads --depth --timeout --proxy --replay-proxy --replay-codes --status-codes --output --resume-from --debug-log --user-agent --extensions --methods --dont-scan --headers --query --filter-size --filter-regex --filter-words --filter-lines --filter-status --filter-similar-to --scan-limit --parallel --rate-limit --time-limit "
|
||||
opts=" -v -q -D -A -r -k -n -f -e -h -V -w -u -t -d -T -p -P -R -s -o -a -x -m -H -Q -S -X -W -N -C -L --verbosity --silent --quiet --auto-tune --auto-bail --json --dont-filter --random-agent --redirects --insecure --no-recursion --add-slash --stdin --extract-links --help --version --wordlist --url --threads --depth --timeout --proxy --replay-proxy --replay-codes --status-codes --output --resume-from --debug-log --user-agent --extensions --methods --data --dont-scan --headers --query --filter-size --filter-regex --filter-words --filter-lines --filter-status --filter-similar-to --scan-limit --parallel --rate-limit --time-limit "
|
||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
@@ -139,6 +139,10 @@ _feroxbuster() {
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--data)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--dont-scan)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
|
||||
@@ -13,6 +13,7 @@ complete -c feroxbuster -n "__fish_use_subcommand" -l debug-log -d 'Output file
|
||||
complete -c feroxbuster -n "__fish_use_subcommand" -s a -l user-agent -d 'Sets the User-Agent (default: feroxbuster/VERSION)'
|
||||
complete -c feroxbuster -n "__fish_use_subcommand" -s x -l extensions -d 'File extension(s) to search for (ex: -x php -x pdf js)'
|
||||
complete -c feroxbuster -n "__fish_use_subcommand" -s m -l methods -d 'HTTP request method(s) to search for (default: [GET])'
|
||||
complete -c feroxbuster -n "__fish_use_subcommand" -l data -d 'HTTP Body data (default: empty)'
|
||||
complete -c feroxbuster -n "__fish_use_subcommand" -l dont-scan -d 'URL(s) or Regex Pattern(s) to exclude from recursion/scans'
|
||||
complete -c feroxbuster -n "__fish_use_subcommand" -s H -l headers -d 'Specify HTTP headers (ex: -H Header:val \'stuff: things\')'
|
||||
complete -c feroxbuster -n "__fish_use_subcommand" -s Q -l query -d 'Specify URL query parameters (ex: -Q token=stuff -Q secret=key)'
|
||||
|
||||
@@ -101,6 +101,9 @@ pub struct Banner {
|
||||
/// represents Configuration.methods
|
||||
methods: BannerEntry,
|
||||
|
||||
/// represents Configuration.data
|
||||
data: BannerEntry,
|
||||
|
||||
/// represents Configuration.insecure
|
||||
insecure: BannerEntry,
|
||||
|
||||
@@ -310,6 +313,11 @@ impl Banner {
|
||||
"HTTP methods",
|
||||
&format!("[{}]", config.methods.join(", ")),
|
||||
);
|
||||
let data = BannerEntry::new(
|
||||
"💣",
|
||||
"HTTP Body data",
|
||||
&String::from_utf8_lossy(&config.data),
|
||||
);
|
||||
let insecure = BannerEntry::new("🔓", "Insecure", &config.insecure.to_string());
|
||||
let redirects = BannerEntry::new("📍", "Follow Redirects", &config.redirects.to_string());
|
||||
let dont_filter =
|
||||
@@ -348,6 +356,7 @@ impl Banner {
|
||||
debug_log,
|
||||
extensions,
|
||||
methods,
|
||||
data,
|
||||
insecure,
|
||||
dont_filter,
|
||||
redirects,
|
||||
@@ -404,7 +413,7 @@ by Ben "epi" Risher {} ver: {}"#,
|
||||
|
||||
let api_url = Url::parse(url)?;
|
||||
|
||||
let result = logged_request(&api_url, DEFAULT_METHOD, handles.clone()).await?;
|
||||
let result = logged_request(&api_url, DEFAULT_METHOD, None, handles.clone()).await?;
|
||||
let body = result.text().await?;
|
||||
|
||||
let json_response: Value = serde_json::from_str(&body)?;
|
||||
@@ -538,6 +547,10 @@ by Ben "epi" Risher {} ver: {}"#,
|
||||
writeln!(&mut writer, "{}", self.methods)?;
|
||||
}
|
||||
|
||||
if !config.data.is_empty() {
|
||||
writeln!(&mut writer, "{}", self.data)?;
|
||||
}
|
||||
|
||||
if config.insecure {
|
||||
writeln!(&mut writer, "{}", self.insecure)?;
|
||||
}
|
||||
|
||||
@@ -173,9 +173,13 @@ pub struct Configuration {
|
||||
|
||||
/// HTTP requests methods(s) to search for
|
||||
/// To make this serialisible will store as String
|
||||
#[serde(default)]
|
||||
#[serde(default = "methods")]
|
||||
pub methods: Vec<String>,
|
||||
|
||||
/// HTTP Body data to send during request
|
||||
#[serde(default)]
|
||||
pub data: Vec<u8>,
|
||||
|
||||
/// HTTP headers to be used in each request
|
||||
#[serde(default)]
|
||||
pub headers: HashMap<String, String>,
|
||||
@@ -322,6 +326,7 @@ impl Default for Configuration {
|
||||
queries: Vec::new(),
|
||||
extensions: Vec::new(),
|
||||
methods: methods,
|
||||
data: Vec::new(),
|
||||
filter_size: Vec::new(),
|
||||
filter_regex: Vec::new(),
|
||||
url_denylist: Vec::new(),
|
||||
@@ -365,6 +370,7 @@ impl Configuration {
|
||||
/// - **insecure**: `false` (don't be insecure, i.e. don't allow invalid certs)
|
||||
/// - **extensions**: `None`
|
||||
/// - **methods**: [`DEFAULT_METHOD`]
|
||||
/// - **data**: `None`
|
||||
/// - **url_denylist**: `None`
|
||||
/// - **regex_denylist**: `None`
|
||||
/// - **filter_size**: `None`
|
||||
@@ -576,6 +582,10 @@ impl Configuration {
|
||||
.collect();
|
||||
}
|
||||
|
||||
if let Some(url) = args.value_of("data") {
|
||||
config.data = url.as_bytes().to_vec();
|
||||
}
|
||||
|
||||
if args.is_present("stdin") {
|
||||
config.stdin = true;
|
||||
} else if let Some(url) = args.value_of("url") {
|
||||
@@ -854,6 +864,7 @@ impl Configuration {
|
||||
update_if_not_default!(&mut conf.extract_links, new.extract_links, false);
|
||||
update_if_not_default!(&mut conf.extensions, new.extensions, Vec::<String>::new());
|
||||
update_if_not_default!(&mut conf.methods, new.methods, Vec::<String>::new());
|
||||
update_if_not_default!(&mut conf.data, new.data, Vec::<u8>::new());
|
||||
update_if_not_default!(&mut conf.url_denylist, new.url_denylist, Vec::<Url>::new());
|
||||
if !new.regex_denylist.is_empty() {
|
||||
// cant use the update_if_not_default macro due to the following error
|
||||
|
||||
@@ -32,6 +32,7 @@ fn setup_config_test() -> Configuration {
|
||||
insecure = true
|
||||
extensions = ["html", "php", "js"]
|
||||
methods = ["GET", "PUT", "DELETE"]
|
||||
data = [31, 32, 33, 34]
|
||||
url_denylist = ["http://dont-scan.me", "https://also-not.me"]
|
||||
regex_denylist = ["/deny.*"]
|
||||
headers = {stuff = "things", mostuff = "mothings"}
|
||||
@@ -97,7 +98,8 @@ fn default_configuration() {
|
||||
assert_eq!(config.queries, Vec::new());
|
||||
assert_eq!(config.filter_size, Vec::<u64>::new());
|
||||
assert_eq!(config.extensions, Vec::<String>::new());
|
||||
assert_eq!(config.methods, Vec::<String>::new());
|
||||
assert_eq!(config.methods, vec!["GET"]);
|
||||
assert_eq!(config.data, Vec::<u8>::new());
|
||||
assert_eq!(config.url_denylist, Vec::<Url>::new());
|
||||
assert_eq!(config.filter_regex, Vec::<String>::new());
|
||||
assert_eq!(config.filter_similar, Vec::<String>::new());
|
||||
@@ -303,6 +305,14 @@ fn config_reads_methods() {
|
||||
assert_eq!(config.methods, vec!["GET", "PUT", "DELETE"]);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
/// parse the test config and see that the value parsed is correct
|
||||
fn config_reads_data() {
|
||||
let config = setup_config_test();
|
||||
assert_eq!(config.data, vec![31, 32, 33, 34]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// parse the test config and see that the value parsed is correct
|
||||
fn config_reads_regex_denylist() {
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
statistics::StatField::ResourcesDiscovered,
|
||||
traits::FeroxSerialize,
|
||||
utils::{ferox_print, fmt_err, make_request, open_file, write_to},
|
||||
CommandReceiver, CommandSender, Joiner, DEFAULT_METHOD,
|
||||
CommandReceiver, CommandSender, Joiner
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -214,7 +214,8 @@ impl TermOutHandler {
|
||||
make_request(
|
||||
self.config.replay_client.as_ref().unwrap(),
|
||||
resp.url(),
|
||||
DEFAULT_METHOD,
|
||||
&resp.method().as_str(),
|
||||
None,
|
||||
self.config.output_level,
|
||||
&self.config,
|
||||
tx_stats.clone(),
|
||||
|
||||
@@ -325,7 +325,8 @@ impl<'a> Extractor<'a> {
|
||||
}
|
||||
|
||||
// make the request and store the response
|
||||
let new_response = logged_request(&new_url, DEFAULT_METHOD, self.handles.clone()).await?;
|
||||
let new_response =
|
||||
logged_request(&new_url, DEFAULT_METHOD, None, self.handles.clone()).await?;
|
||||
|
||||
let new_ferox_response = FeroxResponse::from(
|
||||
new_response,
|
||||
@@ -411,6 +412,7 @@ impl<'a> Extractor<'a> {
|
||||
&client,
|
||||
&url,
|
||||
DEFAULT_METHOD,
|
||||
None,
|
||||
self.handles.config.output_level,
|
||||
&self.handles.config,
|
||||
self.handles.stats.tx.clone(),
|
||||
|
||||
@@ -224,6 +224,7 @@ async fn extractor_get_links_with_absolute_url_that_differs_from_target_domain()
|
||||
&client,
|
||||
&url,
|
||||
DEFAULT_METHOD,
|
||||
None,
|
||||
OutputLevel::Default,
|
||||
&config,
|
||||
tx_stats.clone(),
|
||||
|
||||
@@ -72,7 +72,7 @@ pub async fn initialize(handles: Arc<Handles>) -> Result<()> {
|
||||
let url = skip_fail!(Url::parse(similarity_filter));
|
||||
|
||||
// attempt to request the given url
|
||||
let resp = skip_fail!(logged_request(&url, DEFAULT_METHOD, handles.clone()).await);
|
||||
let resp = skip_fail!(logged_request(&url, DEFAULT_METHOD, None, handles.clone()).await);
|
||||
|
||||
// if successful, create a filter based on the response's body
|
||||
let fr = FeroxResponse::from(
|
||||
|
||||
@@ -122,6 +122,7 @@ fn wildcard_should_filter_when_static_wildcard_found() {
|
||||
size: 83,
|
||||
dynamic: 0,
|
||||
dont_filter: false,
|
||||
method: "GET".to_owned(),
|
||||
};
|
||||
|
||||
assert!(filter.should_filter_response(&resp));
|
||||
@@ -152,6 +153,7 @@ fn wildcard_should_filter_when_dynamic_wildcard_found() {
|
||||
size: 0,
|
||||
dynamic: 59, // content-length - 5 (len('stuff'))
|
||||
dont_filter: false,
|
||||
method: "GET".to_owned(),
|
||||
};
|
||||
|
||||
println!("resp: {:?}: filter: {:?}", resp, filter);
|
||||
|
||||
@@ -90,11 +90,16 @@ impl HeuristicTests {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let data = match self.handles.config.data.is_empty() {
|
||||
true => None,
|
||||
false => Some(&self.handles.config.data[..]),
|
||||
};
|
||||
|
||||
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(), 1)
|
||||
.make_wildcard_request(&ferox_url, method.as_str(), data, 1)
|
||||
.await?;
|
||||
|
||||
// found a wildcard response
|
||||
@@ -111,7 +116,7 @@ impl HeuristicTests {
|
||||
// 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(), 3)
|
||||
.make_wildcard_request(&ferox_url, method.as_str(), data, 3)
|
||||
.await?;
|
||||
|
||||
let wc2_length = resp_two.content_length();
|
||||
@@ -161,6 +166,7 @@ impl HeuristicTests {
|
||||
&self,
|
||||
target: &FeroxUrl,
|
||||
method: &str,
|
||||
data: Option<&[u8]>,
|
||||
length: usize,
|
||||
) -> Result<FeroxResponse> {
|
||||
log::trace!("enter: make_wildcard_request({}, {})", target, length);
|
||||
@@ -176,8 +182,13 @@ impl HeuristicTests {
|
||||
|
||||
let nonexistent_url = target.format(&unique_str, slash)?;
|
||||
|
||||
let response =
|
||||
logged_request(&nonexistent_url.to_owned(), method, self.handles.clone()).await?;
|
||||
let response = logged_request(
|
||||
&nonexistent_url.to_owned(),
|
||||
method,
|
||||
data,
|
||||
self.handles.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if self
|
||||
.handles
|
||||
@@ -235,7 +246,7 @@ impl HeuristicTests {
|
||||
let url = FeroxUrl::from_string(target_url, self.handles.clone());
|
||||
let request = skip_fail!(url.format("", None));
|
||||
|
||||
let result = logged_request(&request, DEFAULT_METHOD, self.handles.clone()).await;
|
||||
let result = logged_request(&request, DEFAULT_METHOD, None, self.handles.clone()).await;
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
|
||||
@@ -239,6 +239,15 @@ pub fn initialize() -> App<'static, 'static> {
|
||||
"HTTP request method(s) to search for (default: [GET])",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("data")
|
||||
.long("data")
|
||||
.value_name("DATA")
|
||||
.takes_value(true)
|
||||
.help(
|
||||
"HTTP Body data (default: empty)",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("url_denylist")
|
||||
.long("dont-scan")
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
statistics::{StatError::Other, StatField::TotalExpected},
|
||||
url::FeroxUrl,
|
||||
utils::logged_request,
|
||||
HIGH_ERROR_RATIO,
|
||||
HIGH_ERROR_RATIO
|
||||
};
|
||||
|
||||
use super::{policy_data::PolicyData, FeroxScanner, PolicyTrigger};
|
||||
@@ -41,6 +41,9 @@ pub(super) struct Requester {
|
||||
/// HTTP methods what will be use for scan
|
||||
methods: Vec<String>,
|
||||
|
||||
/// HTTP body data
|
||||
data: Vec<u8>,
|
||||
|
||||
/// limits requests per second if present
|
||||
rate_limiter: RwLock<Option<LeakyBucket>>,
|
||||
|
||||
@@ -89,6 +92,7 @@ impl Requester {
|
||||
target_url: scanner.target_url.to_owned(),
|
||||
tuning_lock: Mutex::new(0),
|
||||
methods: scanner.handles.config.methods.clone(),
|
||||
data: scanner.handles.config.data.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -335,7 +339,13 @@ impl Requester {
|
||||
continue;
|
||||
}
|
||||
|
||||
let response = logged_request(&url, method.as_str(), self.handles.clone()).await?;
|
||||
let response = logged_request(
|
||||
&url,
|
||||
method.as_str(),
|
||||
Some(&self.data[..]),
|
||||
self.handles.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if (should_tune || self.handles.config.auto_bail)
|
||||
&& !atomic_load!(self.policy_data.cooling_down, Ordering::SeqCst)
|
||||
@@ -444,6 +454,7 @@ mod tests {
|
||||
filters,
|
||||
scan_manager::{ScanOrder, ScanType},
|
||||
statistics::StatError,
|
||||
DEFAULT_METHOD
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@@ -590,7 +601,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: Arc::new(FeroxScan::default()),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: Default::default(),
|
||||
};
|
||||
@@ -619,7 +630,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: ferox_scan.clone(),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: Default::default(),
|
||||
};
|
||||
@@ -645,7 +656,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: ferox_scan.clone(),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: Default::default(),
|
||||
};
|
||||
@@ -686,7 +697,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: ferox_scan.clone(),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: Default::default(),
|
||||
};
|
||||
@@ -742,7 +753,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: req_clone,
|
||||
target_url: "http://one/one/stuff.php".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: Default::default(),
|
||||
};
|
||||
@@ -777,7 +788,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: Arc::new(FeroxScan::default()),
|
||||
target_url: "http://one/one/stuff.php".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: Default::default(),
|
||||
};
|
||||
@@ -800,7 +811,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: Arc::new(FeroxScan::default()),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: Default::default(),
|
||||
};
|
||||
@@ -824,7 +835,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: Arc::new(FeroxScan::default()),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: PolicyData::new(RequesterPolicy::AutoBail, 7),
|
||||
});
|
||||
@@ -855,7 +866,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: Arc::new(FeroxScan::default()),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: PolicyData::new(RequesterPolicy::AutoBail, 7),
|
||||
};
|
||||
@@ -894,7 +905,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: Arc::new(scan),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(Some(limiter)),
|
||||
policy_data: PolicyData::new(RequesterPolicy::AutoBail, 7),
|
||||
};
|
||||
@@ -931,7 +942,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: Arc::new(scan),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: PolicyData::new(RequesterPolicy::AutoBail, 7),
|
||||
};
|
||||
@@ -960,7 +971,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: Arc::new(FeroxScan::default()),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(None),
|
||||
policy_data: PolicyData::new(RequesterPolicy::AutoBail, 7),
|
||||
};
|
||||
@@ -1004,7 +1015,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: Arc::new(FeroxScan::default()),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(Some(limiter)),
|
||||
policy_data: PolicyData::new(RequesterPolicy::AutoBail, 7),
|
||||
};
|
||||
@@ -1048,7 +1059,7 @@ mod tests {
|
||||
tuning_lock: Mutex::new(0),
|
||||
ferox_scan: scan.clone(),
|
||||
target_url: "http://localhost".to_string(),
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],
|
||||
methods: vec![DEFAULT_METHOD.to_owned()],data: vec![],
|
||||
rate_limiter: RwLock::new(Some(limiter)),
|
||||
policy_data: PolicyData::new(RequesterPolicy::AutoTune, 4),
|
||||
};
|
||||
|
||||
14
src/utils.rs
14
src/utils.rs
@@ -95,12 +95,17 @@ pub fn ferox_print(msg: &str, bar: &ProgressBar) {
|
||||
|
||||
/// wrapper for make_request used to pass error/response codes to FeroxScans for per-scan stats
|
||||
/// tracking of information related to auto-tune/bail
|
||||
pub async fn logged_request(url: &Url, method: &str, handles: Arc<Handles>) -> Result<Response> {
|
||||
pub async fn logged_request(
|
||||
url: &Url,
|
||||
method: &str,
|
||||
data: Option<&[u8]>,
|
||||
handles: Arc<Handles>,
|
||||
) -> Result<Response> {
|
||||
let client = &handles.config.client;
|
||||
let level = handles.config.output_level;
|
||||
let tx_stats = handles.stats.tx.clone();
|
||||
|
||||
let response = make_request(client, url, method, level, &handles.config, tx_stats).await;
|
||||
let response = make_request(client, url, method, data, level, &handles.config, tx_stats).await;
|
||||
|
||||
let scans = handles.ferox_scans()?;
|
||||
match response {
|
||||
@@ -126,6 +131,7 @@ pub async fn make_request(
|
||||
client: &Client,
|
||||
url: &Url,
|
||||
method: &str,
|
||||
data: Option<&[u8]>,
|
||||
output_level: OutputLevel,
|
||||
config: &Configuration,
|
||||
tx_stats: UnboundedSender<Command>,
|
||||
@@ -138,6 +144,10 @@ pub async fn make_request(
|
||||
);
|
||||
|
||||
let mut request = client.request(Method::from_bytes(method.as_bytes())?, url.to_owned());
|
||||
if let Some(body_data) = data {
|
||||
//TODO: Find the way how to improve this block
|
||||
request = request.body(body_data.to_vec());
|
||||
}
|
||||
|
||||
if config.random_agent {
|
||||
let index = unsafe {
|
||||
|
||||
@@ -1060,3 +1060,34 @@ fn banner_prints_methods() {
|
||||
.and(predicate::str::contains("─┴─")),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// test allows non-existent wordlist to trigger the banner printing to stderr
|
||||
/// expect to see all mandatory prints + data body
|
||||
fn banner_prints_data() {
|
||||
Command::cargo_bin("feroxbuster")
|
||||
.unwrap()
|
||||
.arg("--url")
|
||||
.arg("http://localhost")
|
||||
.arg("-m")
|
||||
.arg("PUT")
|
||||
.arg("--methods")
|
||||
.arg("POST")
|
||||
.arg("--data")
|
||||
.arg("some_data")
|
||||
.assert()
|
||||
.success()
|
||||
.stderr(
|
||||
predicate::str::contains("─┬─")
|
||||
.and(predicate::str::contains("Target Url"))
|
||||
.and(predicate::str::contains("http://localhost"))
|
||||
.and(predicate::str::contains("Threads"))
|
||||
.and(predicate::str::contains("Wordlist"))
|
||||
.and(predicate::str::contains("Status Codes"))
|
||||
.and(predicate::str::contains("Timeout (secs)"))
|
||||
.and(predicate::str::contains("User-Agent"))
|
||||
.and(predicate::str::contains("HTTP Body data"))
|
||||
.and(predicate::str::contains("some_data"))
|
||||
.and(predicate::str::contains("─┴─")),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user