mirror of
https://github.com/epi052/feroxbuster.git
synced 2026-05-31 03:51:12 -03:00
Merge branch 'main' of github.com:godylockz/feroxbuster into ferox-parsehtml
This commit is contained in:
110
Cargo.lock
generated
110
Cargo.lock
generated
@@ -11,15 +11,6 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ansi_term"
|
|
||||||
version = "0.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.52"
|
version = "1.0.52"
|
||||||
@@ -47,9 +38,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assert_cmd"
|
name = "assert_cmd"
|
||||||
version = "2.0.2"
|
version = "2.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e996dc7940838b7ef1096b882e29ec30a3149a3a443cdc8dba19ed382eca1fe2"
|
checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bstr",
|
"bstr",
|
||||||
"doc-comment",
|
"doc-comment",
|
||||||
@@ -332,17 +323,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.34.0"
|
version = "3.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
checksum = "12e8611f9ae4e068fa3e56931fded356ff745e70987ff76924a6e0ab1c8ef2e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"indexmap",
|
||||||
|
"lazy_static",
|
||||||
|
"os_str_bytes",
|
||||||
"strsim",
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
|
"terminal_size",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"unicode-width",
|
]
|
||||||
"vec_map",
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_complete"
|
||||||
|
version = "3.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fff450c061c4de8162fd6fa0a7a73f70f10c211869a34897724823ed9ec0046"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -601,6 +603,7 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"clap",
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
"console",
|
"console",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
@@ -798,20 +801,9 @@ checksum = "8fb6c4351f4f134772edf9bcd17de13b7fbcb2c56928b440d6823bd4dc9ebd80"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.16"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -915,9 +907,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpmock"
|
name = "httpmock"
|
||||||
version = "0.6.5"
|
version = "0.6.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a24a520a3193799852cc4baf0d8356d7578a8847dfc5603d087529f099661e42"
|
checksum = "c159c4fc205e6c1a9b325cb7ec135d13b5f47188ce175dabb76ec847f331d9bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert-json-diff",
|
"assert-json-diff",
|
||||||
"async-object-pool",
|
"async-object-pool",
|
||||||
@@ -932,13 +924,13 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
"levenshtein",
|
"levenshtein",
|
||||||
"log",
|
"log",
|
||||||
"qstring",
|
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_regex",
|
"serde_regex",
|
||||||
"similar",
|
"similar",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1383,9 +1375,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-src"
|
name = "openssl-src"
|
||||||
@@ -1410,6 +1402,15 @@ dependencies = [
|
|||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking"
|
name = "parking"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -1566,9 +1567,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "predicates"
|
name = "predicates"
|
||||||
version = "2.1.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95e5a7689e456ab905c22c2b48225bb921aba7c8dfa58440d68ba13f6222a715"
|
checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"difflib",
|
"difflib",
|
||||||
"float-cmp",
|
"float-cmp",
|
||||||
@@ -1580,15 +1581,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "predicates-core"
|
name = "predicates-core"
|
||||||
version = "1.0.2"
|
version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
|
checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "predicates-tree"
|
name = "predicates-tree"
|
||||||
version = "1.0.4"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "338c7be2905b732ae3984a2f40032b5e94fd8f52505b186c7d4d68d193445df7"
|
checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"predicates-core",
|
"predicates-core",
|
||||||
"termtree",
|
"termtree",
|
||||||
@@ -1603,15 +1604,6 @@ dependencies = [
|
|||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "qstring"
|
|
||||||
version = "0.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e"
|
|
||||||
dependencies = [
|
|
||||||
"percent-encoding",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
@@ -1945,9 +1937,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.7.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
@@ -1987,9 +1979,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.8.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
@@ -2065,11 +2057,11 @@ checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.14.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-width",
|
"terminal_size",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2338,12 +2330,6 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vec_map"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "feroxbuster"
|
name = "feroxbuster"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
authors = ["Ben 'epi' Risher <epibar052@gmail.com>"]
|
authors = ["Ben 'epi' Risher (@epi052)"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
homepage = "https://github.com/epi052/feroxbuster"
|
homepage = "https://github.com/epi052/feroxbuster"
|
||||||
repository = "https://github.com/epi052/feroxbuster"
|
repository = "https://github.com/epi052/feroxbuster"
|
||||||
description = "A fast, simple, recursive content discovery tool."
|
description = "A fast, simple, recursive content discovery tool."
|
||||||
@@ -16,7 +16,8 @@ build = "build.rs"
|
|||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
clap = "2.33"
|
clap = {version = "3.0", features = ["cargo"]}
|
||||||
|
clap_complete = "3.0"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
dirs = "4.0"
|
dirs = "4.0"
|
||||||
@@ -31,7 +32,7 @@ env_logger = "0.9"
|
|||||||
reqwest = { version = "0.11", features = ["socks"] }
|
reqwest = { version = "0.11", features = ["socks"] }
|
||||||
url = { version = "2.2", features = ["serde"]} # uses feature unification to add 'serde' to reqwest::Url
|
url = { version = "2.2", features = ["serde"]} # uses feature unification to add 'serde' to reqwest::Url
|
||||||
serde_regex = "1.1"
|
serde_regex = "1.1"
|
||||||
clap = "2.34"
|
clap = {version = "3.0", features = ["wrap_help", "cargo"]}
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
|
|||||||
21
build.rs
21
build.rs
@@ -1,9 +1,7 @@
|
|||||||
use std::fs::{copy, create_dir_all, OpenOptions};
|
use std::fs::{copy, create_dir_all, OpenOptions};
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
extern crate clap;
|
|
||||||
extern crate dirs;
|
|
||||||
|
|
||||||
use clap::Shell;
|
use clap_complete::{generate_to, shells};
|
||||||
|
|
||||||
include!("src/parser.rs");
|
include!("src/parser.rs");
|
||||||
|
|
||||||
@@ -18,11 +16,20 @@ fn main() {
|
|||||||
|
|
||||||
let mut app = initialize();
|
let mut app = initialize();
|
||||||
|
|
||||||
let shells: [Shell; 4] = [Shell::Bash, Shell::Fish, Shell::Zsh, Shell::PowerShell];
|
let path = generate_to(shells::Bash, &mut app, "feroxbuster", outdir).unwrap();
|
||||||
|
println!("cargo:warning=completion file is generated: {path:?}");
|
||||||
|
|
||||||
for shell in &shells {
|
let path = generate_to(shells::Zsh, &mut app, "feroxbuster", outdir).unwrap();
|
||||||
app.gen_completions("feroxbuster", *shell, outdir);
|
println!("cargo:warning=completion file is generated: {path:?}");
|
||||||
}
|
|
||||||
|
let path = generate_to(shells::Zsh, &mut app, "feroxbuster", outdir).unwrap();
|
||||||
|
println!("cargo:warning=completion file is generated: {path:?}");
|
||||||
|
|
||||||
|
let path = generate_to(shells::PowerShell, &mut app, "feroxbuster", outdir).unwrap();
|
||||||
|
println!("cargo:warning=completion file is generated: {path:?}");
|
||||||
|
|
||||||
|
let path = generate_to(shells::Elvish, &mut app, "feroxbuster", outdir).unwrap();
|
||||||
|
println!("cargo:warning=completion file is generated: {path:?}");
|
||||||
|
|
||||||
// 0xdf pointed out an oddity when tab-completing options that expect file paths, the fix we
|
// 0xdf pointed out an oddity when tab-completing options that expect file paths, the fix we
|
||||||
// landed on was to add -o plusdirs to the bash completion script. The following code aims to
|
// landed on was to add -o plusdirs to the bash completion script. The following code aims to
|
||||||
|
|||||||
@@ -15,95 +15,92 @@ _feroxbuster() {
|
|||||||
|
|
||||||
local context curcontext="$curcontext" state line
|
local context curcontext="$curcontext" state line
|
||||||
_arguments "${_arguments_options[@]}" \
|
_arguments "${_arguments_options[@]}" \
|
||||||
'-w+[Path to the wordlist]' \
|
'-u+[The target URL (required, unless \[--stdin || --resume-from\] used)]:URL:_urls' \
|
||||||
'--wordlist=[Path to the wordlist]' \
|
'--url=[The target URL (required, unless \[--stdin || --resume-from\] used)]:URL:_urls' \
|
||||||
'*-u+[The target URL(s) (required, unless --stdin used)]' \
|
'(-u --url)--resume-from=[State file from which to resume a partially complete scan (ex. --resume-from ferox-1606586780.state)]:STATE_FILE:_files' \
|
||||||
'*--url=[The target URL(s) (required, unless --stdin used)]' \
|
'-p+[Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)]:PROXY:_urls' \
|
||||||
'-t+[Number of concurrent threads (default: 50)]' \
|
'--proxy=[Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)]:PROXY:_urls' \
|
||||||
'--threads=[Number of concurrent threads (default: 50)]' \
|
'-P+[Send only unfiltered requests through a Replay Proxy, instead of all requests]:REPLAY_PROXY:_urls' \
|
||||||
'-d+[Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)]' \
|
'--replay-proxy=[Send only unfiltered requests through a Replay Proxy, instead of all requests]:REPLAY_PROXY:_urls' \
|
||||||
'--depth=[Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)]' \
|
'*-R+[Status Codes to send through a Replay Proxy when found (default: --status-codes value)]:REPLAY_CODE: ' \
|
||||||
'-T+[Number of seconds before a request times out (default: 7)]' \
|
'*--replay-codes=[Status Codes to send through a Replay Proxy when found (default: --status-codes value)]:REPLAY_CODE: ' \
|
||||||
'--timeout=[Number of seconds before a request times out (default: 7)]' \
|
'-a+[Sets the User-Agent (default: feroxbuster/2.5.0)]:USER_AGENT: ' \
|
||||||
'-p+[Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)]' \
|
'--user-agent=[Sets the User-Agent (default: feroxbuster/2.5.0)]:USER_AGENT: ' \
|
||||||
'--proxy=[Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)]' \
|
'*-x+[File extension(s) to search for (ex: -x php -x pdf js)]:FILE_EXTENSION: ' \
|
||||||
'-P+[Send only unfiltered requests through a Replay Proxy, instead of all requests]' \
|
'*--extensions=[File extension(s) to search for (ex: -x php -x pdf js)]:FILE_EXTENSION: ' \
|
||||||
'--replay-proxy=[Send only unfiltered requests through a Replay Proxy, instead of all requests]' \
|
'*-m+[Which HTTP request method(s) should be sent (default: GET)]:HTTP_METHODS: ' \
|
||||||
'*-R+[Status Codes to send through a Replay Proxy when found (default: --status-codes value)]' \
|
'*--methods=[Which HTTP request method(s) should be sent (default: GET)]:HTTP_METHODS: ' \
|
||||||
'*--replay-codes=[Status Codes to send through a Replay Proxy when found (default: --status-codes value)]' \
|
'--data=[Request'\''s Body; can read data from a file if input starts with an @ (ex: @post.bin)]:DATA: ' \
|
||||||
'*-s+[Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)]' \
|
'*-H+[Specify HTTP headers to be used in each request (ex: -H Header:val -H '\''stuff: things'\'')]:HEADER: ' \
|
||||||
'*--status-codes=[Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)]' \
|
'*--headers=[Specify HTTP headers to be used in each request (ex: -H Header:val -H '\''stuff: things'\'')]:HEADER: ' \
|
||||||
'-o+[Output file to write results to (use w/ --json for JSON entries)]' \
|
'*-b+[Specify HTTP cookies to be used in each request (ex: -b stuff=things)]:COOKIE: ' \
|
||||||
'--output=[Output file to write results to (use w/ --json for JSON entries)]' \
|
'*--cookies=[Specify HTTP cookies to be used in each request (ex: -b stuff=things)]:COOKIE: ' \
|
||||||
'(-u --url)--resume-from=[State file from which to resume a partially complete scan (ex. --resume-from ferox-1606586780.state)]' \
|
'*-Q+[Request'\''s URL query parameters (ex: -Q token=stuff -Q secret=key)]:QUERY: ' \
|
||||||
'--debug-log=[Output file to write log entries (use w/ --json for JSON entries)]' \
|
'*--query=[Request'\''s URL query parameters (ex: -Q token=stuff -Q secret=key)]:QUERY: ' \
|
||||||
'-a+[Sets the User-Agent (default: feroxbuster/VERSION)]' \
|
'*--dont-scan=[URL(s) or Regex Pattern(s) to exclude from recursion/scans]:URL: ' \
|
||||||
'--user-agent=[Sets the User-Agent (default: feroxbuster/VERSION)]' \
|
'*-S+[Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)]:SIZE: ' \
|
||||||
'*-x+[File extension(s) to search for (ex: -x php -x pdf js)]' \
|
'*--filter-size=[Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)]:SIZE: ' \
|
||||||
'*--extensions=[File extension(s) to search for (ex: -x php -x pdf js)]' \
|
'*-X+[Filter out messages via regular expression matching on the response'\''s body (ex: -X '\''^ignore me$'\'')]:REGEX: ' \
|
||||||
'*-m+[HTTP request method(s) (default: GET)]' \
|
'*--filter-regex=[Filter out messages via regular expression matching on the response'\''s body (ex: -X '\''^ignore me$'\'')]:REGEX: ' \
|
||||||
'*--methods=[HTTP request method(s) (default: GET)]' \
|
'*-W+[Filter out messages of a particular word count (ex: -W 312 -W 91,82)]:WORDS: ' \
|
||||||
'--data=[HTTP Body data; can read data from a file if input starts with an @ (ex: @post.bin)]' \
|
'*--filter-words=[Filter out messages of a particular word count (ex: -W 312 -W 91,82)]:WORDS: ' \
|
||||||
'*--dont-scan=[URL(s) or Regex Pattern(s) to exclude from recursion/scans]' \
|
'*-N+[Filter out messages of a particular line count (ex: -N 20 -N 31,30)]:LINES: ' \
|
||||||
'*-H+[Specify HTTP headers (ex: -H Header:val '\''stuff: things'\'')]' \
|
'*--filter-lines=[Filter out messages of a particular line count (ex: -N 20 -N 31,30)]:LINES: ' \
|
||||||
'*--headers=[Specify HTTP headers (ex: -H Header:val '\''stuff: things'\'')]' \
|
'*-C+[Filter out status codes (deny list) (ex: -C 200 -C 401)]:STATUS_CODE: ' \
|
||||||
'*-b+[Specify HTTP cookies (ex: -b stuff=things)]' \
|
'*--filter-status=[Filter out status codes (deny list) (ex: -C 200 -C 401)]:STATUS_CODE: ' \
|
||||||
'*--cookies=[Specify HTTP cookies (ex: -b stuff=things)]' \
|
'*--filter-similar-to=[Filter out pages that are similar to the given page (ex. --filter-similar-to http://site.xyz/soft404)]:UNWANTED_PAGE:_urls' \
|
||||||
'*-Q+[Specify URL query parameters (ex: -Q token=stuff -Q secret=key)]' \
|
'*-s+[Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)]:STATUS_CODE: ' \
|
||||||
'*--query=[Specify URL query parameters (ex: -Q token=stuff -Q secret=key)]' \
|
'*--status-codes=[Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)]:STATUS_CODE: ' \
|
||||||
'*-S+[Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)]' \
|
'-T+[Number of seconds before a client'\''s request times out (default: 7)]:SECONDS: ' \
|
||||||
'*--filter-size=[Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)]' \
|
'--timeout=[Number of seconds before a client'\''s request times out (default: 7)]:SECONDS: ' \
|
||||||
'*-X+[Filter out messages via regular expression matching on the response'\''s body (ex: -X '\''^ignore me$'\'')]' \
|
'-t+[Number of concurrent threads (default: 50)]:THREADS: ' \
|
||||||
'*--filter-regex=[Filter out messages via regular expression matching on the response'\''s body (ex: -X '\''^ignore me$'\'')]' \
|
'--threads=[Number of concurrent threads (default: 50)]:THREADS: ' \
|
||||||
'*-W+[Filter out messages of a particular word count (ex: -W 312 -W 91,82)]' \
|
'-d+[Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)]:RECURSION_DEPTH: ' \
|
||||||
'*--filter-words=[Filter out messages of a particular word count (ex: -W 312 -W 91,82)]' \
|
'--depth=[Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)]:RECURSION_DEPTH: ' \
|
||||||
'*-N+[Filter out messages of a particular line count (ex: -N 20 -N 31,30)]' \
|
'-L+[Limit total number of concurrent scans (default: 0, i.e. no limit)]:SCAN_LIMIT: ' \
|
||||||
'*--filter-lines=[Filter out messages of a particular line count (ex: -N 20 -N 31,30)]' \
|
'--scan-limit=[Limit total number of concurrent scans (default: 0, i.e. no limit)]:SCAN_LIMIT: ' \
|
||||||
'*-C+[Filter out status codes (deny list) (ex: -C 200 -C 401)]' \
|
'--parallel=[Run parallel feroxbuster instances (one child process per url passed via stdin)]:PARALLEL_SCANS: ' \
|
||||||
'*--filter-status=[Filter out status codes (deny list) (ex: -C 200 -C 401)]' \
|
'(--auto-tune)--rate-limit=[Limit number of requests per second (per directory) (default: 0, i.e. no limit)]:RATE_LIMIT: ' \
|
||||||
'*--filter-similar-to=[Filter out pages that are similar to the given page (ex. --filter-similar-to http://site.xyz/soft404)]' \
|
'--time-limit=[Limit total run time of all scans (ex: --time-limit 10m)]:TIME_SPEC: ' \
|
||||||
'-L+[Limit total number of concurrent scans (default: 0, i.e. no limit)]' \
|
'-w+[Path to the wordlist]:FILE:_files' \
|
||||||
'--scan-limit=[Limit total number of concurrent scans (default: 0, i.e. no limit)]' \
|
'--wordlist=[Path to the wordlist]:FILE:_files' \
|
||||||
'--parallel=[Run parallel feroxbuster instances (one child process per url passed via stdin)]' \
|
'-o+[Output file to write results to (use w/ --json for JSON entries)]:FILE:_files' \
|
||||||
'(--auto-tune)--rate-limit=[Limit number of requests per second (per directory) (default: 0, i.e. no limit)]' \
|
'--output=[Output file to write results to (use w/ --json for JSON entries)]:FILE:_files' \
|
||||||
'--time-limit=[Limit total run time of all scans (ex: --time-limit 10m)]' \
|
'--debug-log=[Output file to write log entries (use w/ --json for JSON entries)]:FILE:_files' \
|
||||||
|
'-h[Print help information]' \
|
||||||
|
'--help[Print help information]' \
|
||||||
|
'-V[Print version information]' \
|
||||||
|
'--version[Print version information]' \
|
||||||
|
'(-u --url)--stdin[Read url(s) from STDIN]' \
|
||||||
|
'-A[Use a random User-Agent]' \
|
||||||
|
'--random-agent[Use a random User-Agent]' \
|
||||||
|
'-f[Append / to each request'\''s URL]' \
|
||||||
|
'--add-slash[Append / to each request'\''s URL]' \
|
||||||
|
'-r[Allow client to follow redirects]' \
|
||||||
|
'--redirects[Allow client to follow redirects]' \
|
||||||
|
'-k[Disables TLS certificate validation in the client]' \
|
||||||
|
'--insecure[Disables TLS certificate validation in the client]' \
|
||||||
|
'-n[Do not scan recursively]' \
|
||||||
|
'--no-recursion[Do not scan recursively]' \
|
||||||
|
'-e[Extract links from response body (html, javascript, etc...); make new requests based on findings]' \
|
||||||
|
'--extract-links[Extract links from response body (html, javascript, etc...); make new requests based on findings]' \
|
||||||
|
'(--auto-bail)--auto-tune[Automatically lower scan rate when an excessive amount of errors are encountered]' \
|
||||||
|
'--auto-bail[Automatically stop scanning when an excessive amount of errors are encountered]' \
|
||||||
|
'-D[Don'\''t auto-filter wildcard responses]' \
|
||||||
|
'--dont-filter[Don'\''t auto-filter wildcard responses]' \
|
||||||
'(--silent)*-v[Increase verbosity level (use -vv or more for greater effect. \[CAUTION\] 4 -v'\''s is probably too much)]' \
|
'(--silent)*-v[Increase verbosity level (use -vv or more for greater effect. \[CAUTION\] 4 -v'\''s is probably too much)]' \
|
||||||
'(--silent)*--verbosity[Increase verbosity level (use -vv or more for greater effect. \[CAUTION\] 4 -v'\''s is probably too much)]' \
|
'(--silent)*--verbosity[Increase verbosity level (use -vv or more for greater effect. \[CAUTION\] 4 -v'\''s is probably too much)]' \
|
||||||
'(-q --quiet)--silent[Only print URLs + turn off logging (good for piping a list of urls to other commands)]' \
|
'(-q --quiet)--silent[Only print URLs + turn off logging (good for piping a list of urls to other commands)]' \
|
||||||
'-q[Hide progress bars and banner (good for tmux windows w/ notifications)]' \
|
'-q[Hide progress bars and banner (good for tmux windows w/ notifications)]' \
|
||||||
'--quiet[Hide progress bars and banner (good for tmux windows w/ notifications)]' \
|
'--quiet[Hide progress bars and banner (good for tmux windows w/ notifications)]' \
|
||||||
'(--auto-bail)--auto-tune[Automatically lower scan rate when an excessive amount of errors are encountered]' \
|
|
||||||
'--auto-bail[Automatically stop scanning when an excessive amount of errors are encountered]' \
|
|
||||||
'--json[Emit JSON logs to --output and --debug-log instead of normal text]' \
|
'--json[Emit JSON logs to --output and --debug-log instead of normal text]' \
|
||||||
'-D[Don'\''t auto-filter wildcard responses]' \
|
|
||||||
'--dont-filter[Don'\''t auto-filter wildcard responses]' \
|
|
||||||
'-A[Use a random User-Agent]' \
|
|
||||||
'--random-agent[Use a random User-Agent]' \
|
|
||||||
'-r[Follow redirects]' \
|
|
||||||
'--redirects[Follow redirects]' \
|
|
||||||
'-k[Disables TLS certificate validation]' \
|
|
||||||
'--insecure[Disables TLS certificate validation]' \
|
|
||||||
'-n[Do not scan recursively]' \
|
|
||||||
'--no-recursion[Do not scan recursively]' \
|
|
||||||
'-f[Append / to each request]' \
|
|
||||||
'--add-slash[Append / to each request]' \
|
|
||||||
'(-u --url)--stdin[Read url(s) from STDIN]' \
|
|
||||||
'-e[Extract links from response body (html, javascript, etc...); make new requests based on findings (default: false)]' \
|
|
||||||
'--extract-links[Extract links from response body (html, javascript, etc...); make new requests based on findings (default: false)]' \
|
|
||||||
'-h[Prints help information]' \
|
|
||||||
'--help[Prints help information]' \
|
|
||||||
'-V[Prints version information]' \
|
|
||||||
'--version[Prints version information]' \
|
|
||||||
&& ret=0
|
&& ret=0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(( $+functions[_feroxbuster_commands] )) ||
|
(( $+functions[_feroxbuster_commands] )) ||
|
||||||
_feroxbuster_commands() {
|
_feroxbuster_commands() {
|
||||||
local commands; commands=(
|
local commands; commands=()
|
||||||
|
|
||||||
)
|
|
||||||
_describe -t commands 'feroxbuster commands' commands "$@"
|
_describe -t commands 'feroxbuster commands' commands "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
_feroxbuster "$@"
|
_feroxbuster "$@"
|
||||||
|
|||||||
@@ -20,42 +20,29 @@ Register-ArgumentCompleter -Native -CommandName 'feroxbuster' -ScriptBlock {
|
|||||||
|
|
||||||
$completions = @(switch ($command) {
|
$completions = @(switch ($command) {
|
||||||
'feroxbuster' {
|
'feroxbuster' {
|
||||||
[CompletionResult]::new('-w', 'w', [CompletionResultType]::ParameterName, 'Path to the wordlist')
|
[CompletionResult]::new('-u', 'u', [CompletionResultType]::ParameterName, 'The target URL (required, unless [--stdin || --resume-from] used)')
|
||||||
[CompletionResult]::new('--wordlist', 'wordlist', [CompletionResultType]::ParameterName, 'Path to the wordlist')
|
[CompletionResult]::new('--url', 'url', [CompletionResultType]::ParameterName, 'The target URL (required, unless [--stdin || --resume-from] used)')
|
||||||
[CompletionResult]::new('-u', 'u', [CompletionResultType]::ParameterName, 'The target URL(s) (required, unless --stdin used)')
|
[CompletionResult]::new('--resume-from', 'resume-from', [CompletionResultType]::ParameterName, 'State file from which to resume a partially complete scan (ex. --resume-from ferox-1606586780.state)')
|
||||||
[CompletionResult]::new('--url', 'url', [CompletionResultType]::ParameterName, 'The target URL(s) (required, unless --stdin used)')
|
|
||||||
[CompletionResult]::new('-t', 't', [CompletionResultType]::ParameterName, 'Number of concurrent threads (default: 50)')
|
|
||||||
[CompletionResult]::new('--threads', 'threads', [CompletionResultType]::ParameterName, 'Number of concurrent threads (default: 50)')
|
|
||||||
[CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)')
|
|
||||||
[CompletionResult]::new('--depth', 'depth', [CompletionResultType]::ParameterName, 'Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)')
|
|
||||||
[CompletionResult]::new('-T', 'T', [CompletionResultType]::ParameterName, 'Number of seconds before a request times out (default: 7)')
|
|
||||||
[CompletionResult]::new('--timeout', 'timeout', [CompletionResultType]::ParameterName, 'Number of seconds before a request times out (default: 7)')
|
|
||||||
[CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)')
|
[CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)')
|
||||||
[CompletionResult]::new('--proxy', 'proxy', [CompletionResultType]::ParameterName, 'Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)')
|
[CompletionResult]::new('--proxy', 'proxy', [CompletionResultType]::ParameterName, 'Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)')
|
||||||
[CompletionResult]::new('-P', 'P', [CompletionResultType]::ParameterName, 'Send only unfiltered requests through a Replay Proxy, instead of all requests')
|
[CompletionResult]::new('-P', 'P', [CompletionResultType]::ParameterName, 'Send only unfiltered requests through a Replay Proxy, instead of all requests')
|
||||||
[CompletionResult]::new('--replay-proxy', 'replay-proxy', [CompletionResultType]::ParameterName, 'Send only unfiltered requests through a Replay Proxy, instead of all requests')
|
[CompletionResult]::new('--replay-proxy', 'replay-proxy', [CompletionResultType]::ParameterName, 'Send only unfiltered requests through a Replay Proxy, instead of all requests')
|
||||||
[CompletionResult]::new('-R', 'R', [CompletionResultType]::ParameterName, 'Status Codes to send through a Replay Proxy when found (default: --status-codes value)')
|
[CompletionResult]::new('-R', 'R', [CompletionResultType]::ParameterName, 'Status Codes to send through a Replay Proxy when found (default: --status-codes value)')
|
||||||
[CompletionResult]::new('--replay-codes', 'replay-codes', [CompletionResultType]::ParameterName, 'Status Codes to send through a Replay Proxy when found (default: --status-codes value)')
|
[CompletionResult]::new('--replay-codes', 'replay-codes', [CompletionResultType]::ParameterName, 'Status Codes to send through a Replay Proxy when found (default: --status-codes value)')
|
||||||
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)')
|
[CompletionResult]::new('-a', 'a', [CompletionResultType]::ParameterName, 'Sets the User-Agent (default: feroxbuster/2.5.0)')
|
||||||
[CompletionResult]::new('--status-codes', 'status-codes', [CompletionResultType]::ParameterName, 'Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)')
|
[CompletionResult]::new('--user-agent', 'user-agent', [CompletionResultType]::ParameterName, 'Sets the User-Agent (default: feroxbuster/2.5.0)')
|
||||||
[CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'Output file to write results to (use w/ --json for JSON entries)')
|
|
||||||
[CompletionResult]::new('--output', 'output', [CompletionResultType]::ParameterName, 'Output file to write results to (use w/ --json for JSON entries)')
|
|
||||||
[CompletionResult]::new('--resume-from', 'resume-from', [CompletionResultType]::ParameterName, 'State file from which to resume a partially complete scan (ex. --resume-from ferox-1606586780.state)')
|
|
||||||
[CompletionResult]::new('--debug-log', 'debug-log', [CompletionResultType]::ParameterName, 'Output file to write log entries (use w/ --json for JSON entries)')
|
|
||||||
[CompletionResult]::new('-a', 'a', [CompletionResultType]::ParameterName, 'Sets the User-Agent (default: feroxbuster/VERSION)')
|
|
||||||
[CompletionResult]::new('--user-agent', 'user-agent', [CompletionResultType]::ParameterName, 'Sets the User-Agent (default: feroxbuster/VERSION)')
|
|
||||||
[CompletionResult]::new('-x', 'x', [CompletionResultType]::ParameterName, 'File extension(s) to search for (ex: -x php -x pdf js)')
|
[CompletionResult]::new('-x', 'x', [CompletionResultType]::ParameterName, 'File extension(s) to search for (ex: -x php -x pdf js)')
|
||||||
[CompletionResult]::new('--extensions', 'extensions', [CompletionResultType]::ParameterName, 'File extension(s) to search for (ex: -x php -x pdf js)')
|
[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) (default: GET)')
|
[CompletionResult]::new('-m', 'm', [CompletionResultType]::ParameterName, 'Which HTTP request method(s) should be sent (default: GET)')
|
||||||
[CompletionResult]::new('--methods', 'methods', [CompletionResultType]::ParameterName, 'HTTP request method(s) (default: GET)')
|
[CompletionResult]::new('--methods', 'methods', [CompletionResultType]::ParameterName, 'Which HTTP request method(s) should be sent (default: GET)')
|
||||||
[CompletionResult]::new('--data', 'data', [CompletionResultType]::ParameterName, 'HTTP Body data; can read data from a file if input starts with an @ (ex: @post.bin)')
|
[CompletionResult]::new('--data', 'data', [CompletionResultType]::ParameterName, 'Request''s Body; can read data from a file if input starts with an @ (ex: @post.bin)')
|
||||||
|
[CompletionResult]::new('-H', 'H', [CompletionResultType]::ParameterName, 'Specify HTTP headers to be used in each request (ex: -H Header:val -H ''stuff: things'')')
|
||||||
|
[CompletionResult]::new('--headers', 'headers', [CompletionResultType]::ParameterName, 'Specify HTTP headers to be used in each request (ex: -H Header:val -H ''stuff: things'')')
|
||||||
|
[CompletionResult]::new('-b', 'b', [CompletionResultType]::ParameterName, 'Specify HTTP cookies to be used in each request (ex: -b stuff=things)')
|
||||||
|
[CompletionResult]::new('--cookies', 'cookies', [CompletionResultType]::ParameterName, 'Specify HTTP cookies to be used in each request (ex: -b stuff=things)')
|
||||||
|
[CompletionResult]::new('-Q', 'Q', [CompletionResultType]::ParameterName, 'Request''s URL query parameters (ex: -Q token=stuff -Q secret=key)')
|
||||||
|
[CompletionResult]::new('--query', 'query', [CompletionResultType]::ParameterName, 'Request''s URL query parameters (ex: -Q token=stuff -Q secret=key)')
|
||||||
[CompletionResult]::new('--dont-scan', 'dont-scan', [CompletionResultType]::ParameterName, 'URL(s) or Regex Pattern(s) to exclude from recursion/scans')
|
[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'')')
|
|
||||||
[CompletionResult]::new('-b', 'b', [CompletionResultType]::ParameterName, 'Specify HTTP cookies (ex: -b stuff=things)')
|
|
||||||
[CompletionResult]::new('--cookies', 'cookies', [CompletionResultType]::ParameterName, 'Specify HTTP cookies (ex: -b stuff=things)')
|
|
||||||
[CompletionResult]::new('-Q', 'Q', [CompletionResultType]::ParameterName, 'Specify URL query parameters (ex: -Q token=stuff -Q secret=key)')
|
|
||||||
[CompletionResult]::new('--query', 'query', [CompletionResultType]::ParameterName, 'Specify URL query parameters (ex: -Q token=stuff -Q secret=key)')
|
|
||||||
[CompletionResult]::new('-S', 'S', [CompletionResultType]::ParameterName, 'Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)')
|
[CompletionResult]::new('-S', 'S', [CompletionResultType]::ParameterName, 'Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)')
|
||||||
[CompletionResult]::new('--filter-size', 'filter-size', [CompletionResultType]::ParameterName, 'Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)')
|
[CompletionResult]::new('--filter-size', 'filter-size', [CompletionResultType]::ParameterName, 'Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)')
|
||||||
[CompletionResult]::new('-X', 'X', [CompletionResultType]::ParameterName, 'Filter out messages via regular expression matching on the response''s body (ex: -X ''^ignore me$'')')
|
[CompletionResult]::new('-X', 'X', [CompletionResultType]::ParameterName, 'Filter out messages via regular expression matching on the response''s body (ex: -X ''^ignore me$'')')
|
||||||
@@ -67,38 +54,51 @@ Register-ArgumentCompleter -Native -CommandName 'feroxbuster' -ScriptBlock {
|
|||||||
[CompletionResult]::new('-C', 'C', [CompletionResultType]::ParameterName, 'Filter out status codes (deny list) (ex: -C 200 -C 401)')
|
[CompletionResult]::new('-C', 'C', [CompletionResultType]::ParameterName, 'Filter out status codes (deny list) (ex: -C 200 -C 401)')
|
||||||
[CompletionResult]::new('--filter-status', 'filter-status', [CompletionResultType]::ParameterName, 'Filter out status codes (deny list) (ex: -C 200 -C 401)')
|
[CompletionResult]::new('--filter-status', 'filter-status', [CompletionResultType]::ParameterName, 'Filter out status codes (deny list) (ex: -C 200 -C 401)')
|
||||||
[CompletionResult]::new('--filter-similar-to', 'filter-similar-to', [CompletionResultType]::ParameterName, 'Filter out pages that are similar to the given page (ex. --filter-similar-to http://site.xyz/soft404)')
|
[CompletionResult]::new('--filter-similar-to', 'filter-similar-to', [CompletionResultType]::ParameterName, 'Filter out pages that are similar to the given page (ex. --filter-similar-to http://site.xyz/soft404)')
|
||||||
|
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)')
|
||||||
|
[CompletionResult]::new('--status-codes', 'status-codes', [CompletionResultType]::ParameterName, 'Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)')
|
||||||
|
[CompletionResult]::new('-T', 'T', [CompletionResultType]::ParameterName, 'Number of seconds before a client''s request times out (default: 7)')
|
||||||
|
[CompletionResult]::new('--timeout', 'timeout', [CompletionResultType]::ParameterName, 'Number of seconds before a client''s request times out (default: 7)')
|
||||||
|
[CompletionResult]::new('-t', 't', [CompletionResultType]::ParameterName, 'Number of concurrent threads (default: 50)')
|
||||||
|
[CompletionResult]::new('--threads', 'threads', [CompletionResultType]::ParameterName, 'Number of concurrent threads (default: 50)')
|
||||||
|
[CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)')
|
||||||
|
[CompletionResult]::new('--depth', 'depth', [CompletionResultType]::ParameterName, 'Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)')
|
||||||
[CompletionResult]::new('-L', 'L', [CompletionResultType]::ParameterName, 'Limit total number of concurrent scans (default: 0, i.e. no limit)')
|
[CompletionResult]::new('-L', 'L', [CompletionResultType]::ParameterName, 'Limit total number of concurrent scans (default: 0, i.e. no limit)')
|
||||||
[CompletionResult]::new('--scan-limit', 'scan-limit', [CompletionResultType]::ParameterName, 'Limit total number of concurrent scans (default: 0, i.e. no limit)')
|
[CompletionResult]::new('--scan-limit', 'scan-limit', [CompletionResultType]::ParameterName, 'Limit total number of concurrent scans (default: 0, i.e. no limit)')
|
||||||
[CompletionResult]::new('--parallel', 'parallel', [CompletionResultType]::ParameterName, 'Run parallel feroxbuster instances (one child process per url passed via stdin)')
|
[CompletionResult]::new('--parallel', 'parallel', [CompletionResultType]::ParameterName, 'Run parallel feroxbuster instances (one child process per url passed via stdin)')
|
||||||
[CompletionResult]::new('--rate-limit', 'rate-limit', [CompletionResultType]::ParameterName, 'Limit number of requests per second (per directory) (default: 0, i.e. no limit)')
|
[CompletionResult]::new('--rate-limit', 'rate-limit', [CompletionResultType]::ParameterName, 'Limit number of requests per second (per directory) (default: 0, i.e. no limit)')
|
||||||
[CompletionResult]::new('--time-limit', 'time-limit', [CompletionResultType]::ParameterName, 'Limit total run time of all scans (ex: --time-limit 10m)')
|
[CompletionResult]::new('--time-limit', 'time-limit', [CompletionResultType]::ParameterName, 'Limit total run time of all scans (ex: --time-limit 10m)')
|
||||||
|
[CompletionResult]::new('-w', 'w', [CompletionResultType]::ParameterName, 'Path to the wordlist')
|
||||||
|
[CompletionResult]::new('--wordlist', 'wordlist', [CompletionResultType]::ParameterName, 'Path to the wordlist')
|
||||||
|
[CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'Output file to write results to (use w/ --json for JSON entries)')
|
||||||
|
[CompletionResult]::new('--output', 'output', [CompletionResultType]::ParameterName, 'Output file to write results to (use w/ --json for JSON entries)')
|
||||||
|
[CompletionResult]::new('--debug-log', 'debug-log', [CompletionResultType]::ParameterName, 'Output file to write log entries (use w/ --json for JSON entries)')
|
||||||
|
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
|
||||||
|
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
|
||||||
|
[CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
|
||||||
|
[CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
|
||||||
|
[CompletionResult]::new('--stdin', 'stdin', [CompletionResultType]::ParameterName, 'Read url(s) from STDIN')
|
||||||
|
[CompletionResult]::new('-A', 'A', [CompletionResultType]::ParameterName, 'Use a random User-Agent')
|
||||||
|
[CompletionResult]::new('--random-agent', 'random-agent', [CompletionResultType]::ParameterName, 'Use a random User-Agent')
|
||||||
|
[CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'Append / to each request''s URL')
|
||||||
|
[CompletionResult]::new('--add-slash', 'add-slash', [CompletionResultType]::ParameterName, 'Append / to each request''s URL')
|
||||||
|
[CompletionResult]::new('-r', 'r', [CompletionResultType]::ParameterName, 'Allow client to follow redirects')
|
||||||
|
[CompletionResult]::new('--redirects', 'redirects', [CompletionResultType]::ParameterName, 'Allow client to follow redirects')
|
||||||
|
[CompletionResult]::new('-k', 'k', [CompletionResultType]::ParameterName, 'Disables TLS certificate validation in the client')
|
||||||
|
[CompletionResult]::new('--insecure', 'insecure', [CompletionResultType]::ParameterName, 'Disables TLS certificate validation in the client')
|
||||||
|
[CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'Do not scan recursively')
|
||||||
|
[CompletionResult]::new('--no-recursion', 'no-recursion', [CompletionResultType]::ParameterName, 'Do not scan recursively')
|
||||||
|
[CompletionResult]::new('-e', 'e', [CompletionResultType]::ParameterName, 'Extract links from response body (html, javascript, etc...); make new requests based on findings')
|
||||||
|
[CompletionResult]::new('--extract-links', 'extract-links', [CompletionResultType]::ParameterName, 'Extract links from response body (html, javascript, etc...); make new requests based on findings')
|
||||||
|
[CompletionResult]::new('--auto-tune', 'auto-tune', [CompletionResultType]::ParameterName, 'Automatically lower scan rate when an excessive amount of errors are encountered')
|
||||||
|
[CompletionResult]::new('--auto-bail', 'auto-bail', [CompletionResultType]::ParameterName, 'Automatically stop scanning when an excessive amount of errors are encountered')
|
||||||
|
[CompletionResult]::new('-D', 'D', [CompletionResultType]::ParameterName, 'Don''t auto-filter wildcard responses')
|
||||||
|
[CompletionResult]::new('--dont-filter', 'dont-filter', [CompletionResultType]::ParameterName, 'Don''t auto-filter wildcard responses')
|
||||||
[CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'Increase verbosity level (use -vv or more for greater effect. [CAUTION] 4 -v''s is probably too much)')
|
[CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'Increase verbosity level (use -vv or more for greater effect. [CAUTION] 4 -v''s is probably too much)')
|
||||||
[CompletionResult]::new('--verbosity', 'verbosity', [CompletionResultType]::ParameterName, 'Increase verbosity level (use -vv or more for greater effect. [CAUTION] 4 -v''s is probably too much)')
|
[CompletionResult]::new('--verbosity', 'verbosity', [CompletionResultType]::ParameterName, 'Increase verbosity level (use -vv or more for greater effect. [CAUTION] 4 -v''s is probably too much)')
|
||||||
[CompletionResult]::new('--silent', 'silent', [CompletionResultType]::ParameterName, 'Only print URLs + turn off logging (good for piping a list of urls to other commands)')
|
[CompletionResult]::new('--silent', 'silent', [CompletionResultType]::ParameterName, 'Only print URLs + turn off logging (good for piping a list of urls to other commands)')
|
||||||
[CompletionResult]::new('-q', 'q', [CompletionResultType]::ParameterName, 'Hide progress bars and banner (good for tmux windows w/ notifications)')
|
[CompletionResult]::new('-q', 'q', [CompletionResultType]::ParameterName, 'Hide progress bars and banner (good for tmux windows w/ notifications)')
|
||||||
[CompletionResult]::new('--quiet', 'quiet', [CompletionResultType]::ParameterName, 'Hide progress bars and banner (good for tmux windows w/ notifications)')
|
[CompletionResult]::new('--quiet', 'quiet', [CompletionResultType]::ParameterName, 'Hide progress bars and banner (good for tmux windows w/ notifications)')
|
||||||
[CompletionResult]::new('--auto-tune', 'auto-tune', [CompletionResultType]::ParameterName, 'Automatically lower scan rate when an excessive amount of errors are encountered')
|
|
||||||
[CompletionResult]::new('--auto-bail', 'auto-bail', [CompletionResultType]::ParameterName, 'Automatically stop scanning when an excessive amount of errors are encountered')
|
|
||||||
[CompletionResult]::new('--json', 'json', [CompletionResultType]::ParameterName, 'Emit JSON logs to --output and --debug-log instead of normal text')
|
[CompletionResult]::new('--json', 'json', [CompletionResultType]::ParameterName, 'Emit JSON logs to --output and --debug-log instead of normal text')
|
||||||
[CompletionResult]::new('-D', 'D', [CompletionResultType]::ParameterName, 'Don''t auto-filter wildcard responses')
|
|
||||||
[CompletionResult]::new('--dont-filter', 'dont-filter', [CompletionResultType]::ParameterName, 'Don''t auto-filter wildcard responses')
|
|
||||||
[CompletionResult]::new('-A', 'A', [CompletionResultType]::ParameterName, 'Use a random User-Agent')
|
|
||||||
[CompletionResult]::new('--random-agent', 'random-agent', [CompletionResultType]::ParameterName, 'Use a random User-Agent')
|
|
||||||
[CompletionResult]::new('-r', 'r', [CompletionResultType]::ParameterName, 'Follow redirects')
|
|
||||||
[CompletionResult]::new('--redirects', 'redirects', [CompletionResultType]::ParameterName, 'Follow redirects')
|
|
||||||
[CompletionResult]::new('-k', 'k', [CompletionResultType]::ParameterName, 'Disables TLS certificate validation')
|
|
||||||
[CompletionResult]::new('--insecure', 'insecure', [CompletionResultType]::ParameterName, 'Disables TLS certificate validation')
|
|
||||||
[CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'Do not scan recursively')
|
|
||||||
[CompletionResult]::new('--no-recursion', 'no-recursion', [CompletionResultType]::ParameterName, 'Do not scan recursively')
|
|
||||||
[CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'Append / to each request')
|
|
||||||
[CompletionResult]::new('--add-slash', 'add-slash', [CompletionResultType]::ParameterName, 'Append / to each request')
|
|
||||||
[CompletionResult]::new('--stdin', 'stdin', [CompletionResultType]::ParameterName, 'Read url(s) from STDIN')
|
|
||||||
[CompletionResult]::new('-e', 'e', [CompletionResultType]::ParameterName, 'Extract links from response body (html, javascript, etc...); make new requests based on findings (default: false)')
|
|
||||||
[CompletionResult]::new('--extract-links', 'extract-links', [CompletionResultType]::ParameterName, 'Extract links from response body (html, javascript, etc...); make new requests based on findings (default: false)')
|
|
||||||
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information')
|
|
||||||
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information')
|
|
||||||
[CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information')
|
|
||||||
[CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information')
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ _feroxbuster() {
|
|||||||
for i in ${COMP_WORDS[@]}
|
for i in ${COMP_WORDS[@]}
|
||||||
do
|
do
|
||||||
case "${i}" in
|
case "${i}" in
|
||||||
feroxbuster)
|
"$1")
|
||||||
cmd="feroxbuster"
|
cmd="feroxbuster"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -20,90 +19,17 @@ _feroxbuster() {
|
|||||||
|
|
||||||
case "${cmd}" in
|
case "${cmd}" in
|
||||||
feroxbuster)
|
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 -b -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 --cookies --query --filter-size --filter-regex --filter-words --filter-lines --filter-status --filter-similar-to --scan-limit --parallel --rate-limit --time-limit "
|
opts="-h -V -u -p -P -R -a -A -x -m -H -b -Q -f -S -X -W -N -C -s -T -r -k -t -n -d -e -L -w -D -v -q -o --help --version --url --stdin --resume-from --proxy --replay-proxy --replay-codes --user-agent --random-agent --extensions --methods --data --headers --cookies --query --add-slash --dont-scan --filter-size --filter-regex --filter-words --filter-lines --filter-status --filter-similar-to --status-codes --timeout --redirects --insecure --threads --no-recursion --depth --extract-links --scan-limit --parallel --rate-limit --time-limit --wordlist --auto-tune --auto-bail --dont-filter --verbosity --silent --quiet --json --output --debug-log"
|
||||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
case "${prev}" in
|
case "${prev}" in
|
||||||
|
|
||||||
--wordlist)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-w)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--url)
|
--url)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-u)
|
-u)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--threads)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-t)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--depth)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-d)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--timeout)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-T)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--proxy)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-p)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--replay-proxy)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-P)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--replay-codes)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-R)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--status-codes)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-s)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--output)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-o)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -111,7 +37,27 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
--debug-log)
|
--proxy)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-p)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--replay-proxy)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-P)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--replay-codes)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-R)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -119,7 +65,7 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-a)
|
-a)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -127,7 +73,7 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-x)
|
-x)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -135,7 +81,7 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-m)
|
-m)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -143,15 +89,11 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
--dont-scan)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--headers)
|
--headers)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-H)
|
-H)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -159,7 +101,7 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-b)
|
-b)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -167,7 +109,11 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-Q)
|
-Q)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--dont-scan)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -175,7 +121,7 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-S)
|
-S)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -183,7 +129,7 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-X)
|
-X)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -191,7 +137,7 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-W)
|
-W)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -199,7 +145,7 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-N)
|
-N)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -207,7 +153,7 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-C)
|
-C)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -215,11 +161,43 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
--status-codes)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-s)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--timeout)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-T)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--threads)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-t)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--depth)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-d)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
--scan-limit)
|
--scan-limit)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
-L)
|
-L)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -235,6 +213,26 @@ _feroxbuster() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
--wordlist)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-w)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--output)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-o)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--debug-log)
|
||||||
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
;;
|
;;
|
||||||
@@ -242,7 +240,6 @@ _feroxbuster() {
|
|||||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
103
shell_completions/feroxbuster.elv
Normal file
103
shell_completions/feroxbuster.elv
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
use builtin;
|
||||||
|
use str;
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[feroxbuster] = {|@words|
|
||||||
|
fn spaces {|n|
|
||||||
|
builtin:repeat $n ' ' | str:join ''
|
||||||
|
}
|
||||||
|
fn cand {|text desc|
|
||||||
|
edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc
|
||||||
|
}
|
||||||
|
var command = 'feroxbuster'
|
||||||
|
for word $words[1..-1] {
|
||||||
|
if (str:has-prefix $word '-') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
set command = $command';'$word
|
||||||
|
}
|
||||||
|
var completions = [
|
||||||
|
&'feroxbuster'= {
|
||||||
|
cand -u 'The target URL (required, unless [--stdin || --resume-from] used)'
|
||||||
|
cand --url 'The target URL (required, unless [--stdin || --resume-from] used)'
|
||||||
|
cand --resume-from 'State file from which to resume a partially complete scan (ex. --resume-from ferox-1606586780.state)'
|
||||||
|
cand -p 'Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)'
|
||||||
|
cand --proxy 'Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)'
|
||||||
|
cand -P 'Send only unfiltered requests through a Replay Proxy, instead of all requests'
|
||||||
|
cand --replay-proxy 'Send only unfiltered requests through a Replay Proxy, instead of all requests'
|
||||||
|
cand -R 'Status Codes to send through a Replay Proxy when found (default: --status-codes value)'
|
||||||
|
cand --replay-codes 'Status Codes to send through a Replay Proxy when found (default: --status-codes value)'
|
||||||
|
cand -a 'Sets the User-Agent (default: feroxbuster/2.5.0)'
|
||||||
|
cand --user-agent 'Sets the User-Agent (default: feroxbuster/2.5.0)'
|
||||||
|
cand -x 'File extension(s) to search for (ex: -x php -x pdf js)'
|
||||||
|
cand --extensions 'File extension(s) to search for (ex: -x php -x pdf js)'
|
||||||
|
cand -m 'Which HTTP request method(s) should be sent (default: GET)'
|
||||||
|
cand --methods 'Which HTTP request method(s) should be sent (default: GET)'
|
||||||
|
cand --data 'Request''s Body; can read data from a file if input starts with an @ (ex: @post.bin)'
|
||||||
|
cand -H 'Specify HTTP headers to be used in each request (ex: -H Header:val -H ''stuff: things'')'
|
||||||
|
cand --headers 'Specify HTTP headers to be used in each request (ex: -H Header:val -H ''stuff: things'')'
|
||||||
|
cand -b 'Specify HTTP cookies to be used in each request (ex: -b stuff=things)'
|
||||||
|
cand --cookies 'Specify HTTP cookies to be used in each request (ex: -b stuff=things)'
|
||||||
|
cand -Q 'Request''s URL query parameters (ex: -Q token=stuff -Q secret=key)'
|
||||||
|
cand --query 'Request''s URL query parameters (ex: -Q token=stuff -Q secret=key)'
|
||||||
|
cand --dont-scan 'URL(s) or Regex Pattern(s) to exclude from recursion/scans'
|
||||||
|
cand -S 'Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)'
|
||||||
|
cand --filter-size 'Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)'
|
||||||
|
cand -X 'Filter out messages via regular expression matching on the response''s body (ex: -X ''^ignore me$'')'
|
||||||
|
cand --filter-regex 'Filter out messages via regular expression matching on the response''s body (ex: -X ''^ignore me$'')'
|
||||||
|
cand -W 'Filter out messages of a particular word count (ex: -W 312 -W 91,82)'
|
||||||
|
cand --filter-words 'Filter out messages of a particular word count (ex: -W 312 -W 91,82)'
|
||||||
|
cand -N 'Filter out messages of a particular line count (ex: -N 20 -N 31,30)'
|
||||||
|
cand --filter-lines 'Filter out messages of a particular line count (ex: -N 20 -N 31,30)'
|
||||||
|
cand -C 'Filter out status codes (deny list) (ex: -C 200 -C 401)'
|
||||||
|
cand --filter-status 'Filter out status codes (deny list) (ex: -C 200 -C 401)'
|
||||||
|
cand --filter-similar-to 'Filter out pages that are similar to the given page (ex. --filter-similar-to http://site.xyz/soft404)'
|
||||||
|
cand -s 'Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)'
|
||||||
|
cand --status-codes 'Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)'
|
||||||
|
cand -T 'Number of seconds before a client''s request times out (default: 7)'
|
||||||
|
cand --timeout 'Number of seconds before a client''s request times out (default: 7)'
|
||||||
|
cand -t 'Number of concurrent threads (default: 50)'
|
||||||
|
cand --threads 'Number of concurrent threads (default: 50)'
|
||||||
|
cand -d 'Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)'
|
||||||
|
cand --depth 'Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)'
|
||||||
|
cand -L 'Limit total number of concurrent scans (default: 0, i.e. no limit)'
|
||||||
|
cand --scan-limit 'Limit total number of concurrent scans (default: 0, i.e. no limit)'
|
||||||
|
cand --parallel 'Run parallel feroxbuster instances (one child process per url passed via stdin)'
|
||||||
|
cand --rate-limit 'Limit number of requests per second (per directory) (default: 0, i.e. no limit)'
|
||||||
|
cand --time-limit 'Limit total run time of all scans (ex: --time-limit 10m)'
|
||||||
|
cand -w 'Path to the wordlist'
|
||||||
|
cand --wordlist 'Path to the wordlist'
|
||||||
|
cand -o 'Output file to write results to (use w/ --json for JSON entries)'
|
||||||
|
cand --output 'Output file to write results to (use w/ --json for JSON entries)'
|
||||||
|
cand --debug-log 'Output file to write log entries (use w/ --json for JSON entries)'
|
||||||
|
cand -h 'Print help information'
|
||||||
|
cand --help 'Print help information'
|
||||||
|
cand -V 'Print version information'
|
||||||
|
cand --version 'Print version information'
|
||||||
|
cand --stdin 'Read url(s) from STDIN'
|
||||||
|
cand -A 'Use a random User-Agent'
|
||||||
|
cand --random-agent 'Use a random User-Agent'
|
||||||
|
cand -f 'Append / to each request''s URL'
|
||||||
|
cand --add-slash 'Append / to each request''s URL'
|
||||||
|
cand -r 'Allow client to follow redirects'
|
||||||
|
cand --redirects 'Allow client to follow redirects'
|
||||||
|
cand -k 'Disables TLS certificate validation in the client'
|
||||||
|
cand --insecure 'Disables TLS certificate validation in the client'
|
||||||
|
cand -n 'Do not scan recursively'
|
||||||
|
cand --no-recursion 'Do not scan recursively'
|
||||||
|
cand -e 'Extract links from response body (html, javascript, etc...); make new requests based on findings'
|
||||||
|
cand --extract-links 'Extract links from response body (html, javascript, etc...); make new requests based on findings'
|
||||||
|
cand --auto-tune 'Automatically lower scan rate when an excessive amount of errors are encountered'
|
||||||
|
cand --auto-bail 'Automatically stop scanning when an excessive amount of errors are encountered'
|
||||||
|
cand -D 'Don''t auto-filter wildcard responses'
|
||||||
|
cand --dont-filter 'Don''t auto-filter wildcard responses'
|
||||||
|
cand -v 'Increase verbosity level (use -vv or more for greater effect. [CAUTION] 4 -v''s is probably too much)'
|
||||||
|
cand --verbosity 'Increase verbosity level (use -vv or more for greater effect. [CAUTION] 4 -v''s is probably too much)'
|
||||||
|
cand --silent 'Only print URLs + turn off logging (good for piping a list of urls to other commands)'
|
||||||
|
cand -q 'Hide progress bars and banner (good for tmux windows w/ notifications)'
|
||||||
|
cand --quiet 'Hide progress bars and banner (good for tmux windows w/ notifications)'
|
||||||
|
cand --json 'Emit JSON logs to --output and --debug-log instead of normal text'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
$completions[$command]
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ use crate::{
|
|||||||
DEFAULT_CONFIG_NAME,
|
DEFAULT_CONFIG_NAME,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use clap::{value_t, ArgMatches};
|
use clap::ArgMatches;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::{Client, Method, StatusCode, Url};
|
use reqwest::{Client, Method, StatusCode, Url};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -22,17 +22,15 @@ use std::{
|
|||||||
|
|
||||||
/// macro helper to abstract away repetitive configuration updates
|
/// macro helper to abstract away repetitive configuration updates
|
||||||
macro_rules! update_config_if_present {
|
macro_rules! update_config_if_present {
|
||||||
($c:expr, $m:ident, $v:expr, $t:ty) => {
|
($conf_val:expr, $matches:ident, $arg_name:expr) => {
|
||||||
match value_t!($m, $v, $t) {
|
match $matches.value_of_t($arg_name) {
|
||||||
Ok(value) => *$c = value, // Update value
|
Ok(value) => *$conf_val = value, // Update value
|
||||||
Err(clap::Error {
|
Err(err) => {
|
||||||
kind: clap::ErrorKind::ArgumentNotFound,
|
if !matches!(err.kind, clap::ErrorKind::ArgumentNotFound) {
|
||||||
message: _,
|
// Do nothing if argument not found
|
||||||
info: _,
|
err.exit() // Exit with error on any other parse error
|
||||||
}) => {
|
}
|
||||||
// Do nothing if argument not found
|
|
||||||
}
|
}
|
||||||
Err(e) => e.exit(), // Exit with error on parse error
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -519,16 +517,16 @@ impl Configuration {
|
|||||||
fn parse_cli_args(args: &ArgMatches) -> Self {
|
fn parse_cli_args(args: &ArgMatches) -> Self {
|
||||||
let mut config = Configuration::default();
|
let mut config = Configuration::default();
|
||||||
|
|
||||||
update_config_if_present!(&mut config.threads, args, "threads", usize);
|
update_config_if_present!(&mut config.threads, args, "threads");
|
||||||
update_config_if_present!(&mut config.depth, args, "depth", usize);
|
update_config_if_present!(&mut config.depth, args, "depth");
|
||||||
update_config_if_present!(&mut config.scan_limit, args, "scan_limit", usize);
|
update_config_if_present!(&mut config.scan_limit, args, "scan_limit");
|
||||||
update_config_if_present!(&mut config.parallel, args, "parallel", usize);
|
update_config_if_present!(&mut config.parallel, args, "parallel");
|
||||||
update_config_if_present!(&mut config.rate_limit, args, "rate_limit", usize);
|
update_config_if_present!(&mut config.rate_limit, args, "rate_limit");
|
||||||
update_config_if_present!(&mut config.wordlist, args, "wordlist", String);
|
update_config_if_present!(&mut config.wordlist, args, "wordlist");
|
||||||
update_config_if_present!(&mut config.output, args, "output", String);
|
update_config_if_present!(&mut config.output, args, "output");
|
||||||
update_config_if_present!(&mut config.debug_log, args, "debug_log", String);
|
update_config_if_present!(&mut config.debug_log, args, "debug_log");
|
||||||
update_config_if_present!(&mut config.time_limit, args, "time_limit", String);
|
update_config_if_present!(&mut config.time_limit, args, "time_limit");
|
||||||
update_config_if_present!(&mut config.resume_from, args, "resume_from", String);
|
update_config_if_present!(&mut config.resume_from, args, "resume_from");
|
||||||
|
|
||||||
if let Some(arg) = args.values_of("status_codes") {
|
if let Some(arg) = args.values_of("status_codes") {
|
||||||
config.status_codes = arg
|
config.status_codes = arg
|
||||||
@@ -602,7 +600,7 @@ impl Configuration {
|
|||||||
// url to be scanned. With the addition of regex support, I want to move parsing
|
// url to be scanned. With the addition of regex support, I want to move parsing
|
||||||
// out of should_deny_url and into here, so it's performed once instead of thousands
|
// out of should_deny_url and into here, so it's performed once instead of thousands
|
||||||
// of times
|
// of times
|
||||||
for denier in arg.into_iter() {
|
for denier in arg {
|
||||||
// could be an absolute url or a regex, need to determine which and populate the
|
// could be an absolute url or a regex, need to determine which and populate the
|
||||||
// appropriate vector
|
// appropriate vector
|
||||||
match Url::parse(denier.trim_end_matches('/')) {
|
match Url::parse(denier.trim_end_matches('/')) {
|
||||||
@@ -727,10 +725,10 @@ impl Configuration {
|
|||||||
////
|
////
|
||||||
// organizational breakpoint; all options below alter the Client configuration
|
// organizational breakpoint; all options below alter the Client configuration
|
||||||
////
|
////
|
||||||
update_config_if_present!(&mut config.proxy, args, "proxy", String);
|
update_config_if_present!(&mut config.proxy, args, "proxy");
|
||||||
update_config_if_present!(&mut config.replay_proxy, args, "replay_proxy", String);
|
update_config_if_present!(&mut config.replay_proxy, args, "replay_proxy");
|
||||||
update_config_if_present!(&mut config.user_agent, args, "user_agent", String);
|
update_config_if_present!(&mut config.user_agent, args, "user_agent");
|
||||||
update_config_if_present!(&mut config.timeout, args, "timeout", u64);
|
update_config_if_present!(&mut config.timeout, args, "timeout");
|
||||||
|
|
||||||
if args.is_present("random_agent") {
|
if args.is_present("random_agent") {
|
||||||
config.random_agent = true;
|
config.random_agent = true;
|
||||||
|
|||||||
847
src/parser.rs
847
src/parser.rs
@@ -1,4 +1,6 @@
|
|||||||
use clap::{App, Arg, ArgGroup};
|
use clap::{
|
||||||
|
crate_authors, crate_description, crate_name, crate_version, App, Arg, ArgGroup, ValueHint,
|
||||||
|
};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::env;
|
use std::env;
|
||||||
@@ -14,423 +16,567 @@ lazy_static! {
|
|||||||
/// - 1d
|
/// - 1d
|
||||||
pub static ref TIMESPEC_REGEX: Regex =
|
pub static ref TIMESPEC_REGEX: Regex =
|
||||||
Regex::new(r"^(?i)(?P<n>\d+)(?P<m>[smdh])$").expect("Could not compile regex");
|
Regex::new(r"^(?i)(?P<n>\d+)(?P<m>[smdh])$").expect("Could not compile regex");
|
||||||
|
|
||||||
|
/// help string for user agent, your guess is as good as mine as to why this is required...
|
||||||
|
static ref DEFAULT_USER_AGENT: String = format!(
|
||||||
|
"Sets the User-Agent (default: feroxbuster/{})",
|
||||||
|
crate_version!()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create and return an instance of [clap::App](https://docs.rs/clap/latest/clap/struct.App.html), i.e. the Command Line Interface's configuration
|
/// Create and return an instance of [clap::App](https://docs.rs/clap/latest/clap/struct.App.html), i.e. the Command Line Interface's configuration
|
||||||
pub fn initialize() -> App<'static, 'static> {
|
pub fn initialize() -> App<'static> {
|
||||||
let mut app = App::new("feroxbuster")
|
let app = App::new(crate_name!())
|
||||||
.version(env!("CARGO_PKG_VERSION"))
|
.version(crate_version!())
|
||||||
.author("Ben 'epi' Risher (@epi052)")
|
.author(crate_authors!())
|
||||||
.about("A fast, simple, recursive content discovery tool written in Rust")
|
.about(crate_description!());
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// group - target selection
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
let app = app
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("wordlist")
|
Arg::new("url")
|
||||||
.short("w")
|
.short('u')
|
||||||
.long("wordlist")
|
|
||||||
.value_name("FILE")
|
|
||||||
.help("Path to the wordlist")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("url")
|
|
||||||
.short("u")
|
|
||||||
.long("url")
|
.long("url")
|
||||||
.required_unless_one(&["stdin", "resume_from"])
|
.required_unless_present_any(&["stdin", "resume_from"])
|
||||||
|
.help_heading("Target selection")
|
||||||
.value_name("URL")
|
.value_name("URL")
|
||||||
.multiple(true)
|
|
||||||
.use_delimiter(true)
|
.use_delimiter(true)
|
||||||
.help("The target URL(s) (required, unless --stdin used)"),
|
.value_hint(ValueHint::Url)
|
||||||
|
.help("The target URL (required, unless [--stdin || --resume-from] used)"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("threads")
|
Arg::new("stdin")
|
||||||
.short("t")
|
|
||||||
.long("threads")
|
|
||||||
.value_name("THREADS")
|
|
||||||
.takes_value(true)
|
|
||||||
.help("Number of concurrent threads (default: 50)"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("depth")
|
|
||||||
.short("d")
|
|
||||||
.long("depth")
|
|
||||||
.value_name("RECURSION_DEPTH")
|
|
||||||
.takes_value(true)
|
|
||||||
.help("Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("timeout")
|
|
||||||
.short("T")
|
|
||||||
.long("timeout")
|
|
||||||
.value_name("SECONDS")
|
|
||||||
.takes_value(true)
|
|
||||||
.help("Number of seconds before a request times out (default: 7)"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("verbosity")
|
|
||||||
.short("v")
|
|
||||||
.long("verbosity")
|
|
||||||
.takes_value(false)
|
|
||||||
.multiple(true)
|
|
||||||
.conflicts_with("silent")
|
|
||||||
.help("Increase verbosity level (use -vv or more for greater effect. [CAUTION] 4 -v's is probably too much)"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("proxy")
|
|
||||||
.short("p")
|
|
||||||
.long("proxy")
|
|
||||||
.takes_value(true)
|
|
||||||
.value_name("PROXY")
|
|
||||||
.help(
|
|
||||||
"Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("replay_proxy")
|
|
||||||
.short("P")
|
|
||||||
.long("replay-proxy")
|
|
||||||
.takes_value(true)
|
|
||||||
.value_name("REPLAY_PROXY")
|
|
||||||
.help(
|
|
||||||
"Send only unfiltered requests through a Replay Proxy, instead of all requests",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("replay_codes")
|
|
||||||
.short("R")
|
|
||||||
.long("replay-codes")
|
|
||||||
.value_name("REPLAY_CODE")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.use_delimiter(true)
|
|
||||||
.requires("replay_proxy")
|
|
||||||
.help(
|
|
||||||
"Status Codes to send through a Replay Proxy when found (default: --status-codes value)",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("status_codes")
|
|
||||||
.short("s")
|
|
||||||
.long("status-codes")
|
|
||||||
.value_name("STATUS_CODE")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.use_delimiter(true)
|
|
||||||
.help(
|
|
||||||
"Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("silent")
|
|
||||||
.long("silent")
|
|
||||||
.takes_value(false)
|
|
||||||
.conflicts_with("quiet")
|
|
||||||
.help("Only print URLs + turn off logging (good for piping a list of urls to other commands)")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("quiet")
|
|
||||||
.short("q")
|
|
||||||
.long("quiet")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Hide progress bars and banner (good for tmux windows w/ notifications)")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("auto_tune")
|
|
||||||
.long("auto-tune")
|
|
||||||
.takes_value(false)
|
|
||||||
.conflicts_with("auto_bail")
|
|
||||||
.help("Automatically lower scan rate when an excessive amount of errors are encountered")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("auto_bail")
|
|
||||||
.long("auto-bail")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Automatically stop scanning when an excessive amount of errors are encountered")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("json")
|
|
||||||
.long("json")
|
|
||||||
.takes_value(false)
|
|
||||||
.requires("output_files")
|
|
||||||
.help("Emit JSON logs to --output and --debug-log instead of normal text")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("dont_filter")
|
|
||||||
.short("D")
|
|
||||||
.long("dont-filter")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Don't auto-filter wildcard responses")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("output")
|
|
||||||
.short("o")
|
|
||||||
.long("output")
|
|
||||||
.value_name("FILE")
|
|
||||||
.help("Output file to write results to (use w/ --json for JSON entries)")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("resume_from")
|
|
||||||
.long("resume-from")
|
|
||||||
.value_name("STATE_FILE")
|
|
||||||
.help("State file from which to resume a partially complete scan (ex. --resume-from ferox-1606586780.state)")
|
|
||||||
.conflicts_with("url")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("debug_log")
|
|
||||||
.long("debug-log")
|
|
||||||
.value_name("FILE")
|
|
||||||
.help("Output file to write log entries (use w/ --json for JSON entries)")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("user_agent")
|
|
||||||
.short("a")
|
|
||||||
.long("user-agent")
|
|
||||||
.value_name("USER_AGENT")
|
|
||||||
.takes_value(true)
|
|
||||||
.help(
|
|
||||||
"Sets the User-Agent (default: feroxbuster/VERSION)"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("random_agent")
|
|
||||||
.short("A")
|
|
||||||
.long("random-agent")
|
|
||||||
.takes_value(false)
|
|
||||||
.help(
|
|
||||||
"Use a random User-Agent"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("redirects")
|
|
||||||
.short("r")
|
|
||||||
.long("redirects")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Follow redirects")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("insecure")
|
|
||||||
.short("k")
|
|
||||||
.long("insecure")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Disables TLS certificate validation")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("extensions")
|
|
||||||
.short("x")
|
|
||||||
.long("extensions")
|
|
||||||
.value_name("FILE_EXTENSION")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.use_delimiter(true)
|
|
||||||
.help(
|
|
||||||
"File extension(s) to search for (ex: -x php -x pdf js)",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("methods")
|
|
||||||
.short("m")
|
|
||||||
.long("methods")
|
|
||||||
.value_name("HTTP_METHODS")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.use_delimiter(true)
|
|
||||||
.help(
|
|
||||||
"HTTP request method(s) (default: GET)",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("data")
|
|
||||||
.long("data")
|
|
||||||
.value_name("DATA")
|
|
||||||
.takes_value(true)
|
|
||||||
.help(
|
|
||||||
"HTTP Body data; can read data from a file if input starts with an @ (ex: @post.bin)",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("url_denylist")
|
|
||||||
.long("dont-scan")
|
|
||||||
.value_name("URL")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.use_delimiter(true)
|
|
||||||
.help(
|
|
||||||
"URL(s) or Regex Pattern(s) to exclude from recursion/scans",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("headers")
|
|
||||||
.short("H")
|
|
||||||
.long("headers")
|
|
||||||
.value_name("HEADER")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.use_delimiter(true)
|
|
||||||
.help(
|
|
||||||
"Specify HTTP headers (ex: -H Header:val 'stuff: things')",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("cookies")
|
|
||||||
.short("b")
|
|
||||||
.long("cookies")
|
|
||||||
.value_name("COOKIE")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.use_delimiter(true)
|
|
||||||
.help(
|
|
||||||
"Specify HTTP cookies (ex: -b stuff=things)",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("queries")
|
|
||||||
.short("Q")
|
|
||||||
.long("query")
|
|
||||||
.value_name("QUERY")
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true)
|
|
||||||
.use_delimiter(true)
|
|
||||||
.help(
|
|
||||||
"Specify URL query parameters (ex: -Q token=stuff -Q secret=key)",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("no_recursion")
|
|
||||||
.short("n")
|
|
||||||
.long("no-recursion")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Do not scan recursively")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("add_slash")
|
|
||||||
.short("f")
|
|
||||||
.long("add-slash")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Append / to each request")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("stdin")
|
|
||||||
.long("stdin")
|
.long("stdin")
|
||||||
|
.help_heading("Target selection")
|
||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
.help("Read url(s) from STDIN")
|
.help("Read url(s) from STDIN")
|
||||||
.conflicts_with("url")
|
.conflicts_with("url")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("filter_size")
|
Arg::new("resume_from")
|
||||||
.short("S")
|
.long("resume-from")
|
||||||
|
.value_hint(ValueHint::FilePath)
|
||||||
|
.value_name("STATE_FILE")
|
||||||
|
.help_heading("Target selection")
|
||||||
|
.help("State file from which to resume a partially complete scan (ex. --resume-from ferox-1606586780.state)")
|
||||||
|
.conflicts_with("url")
|
||||||
|
.takes_value(true),
|
||||||
|
);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// group - proxy settings
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::new("proxy")
|
||||||
|
.short('p')
|
||||||
|
.long("proxy")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("PROXY")
|
||||||
|
.value_hint(ValueHint::Url)
|
||||||
|
.help_heading("Proxy settings")
|
||||||
|
.help(
|
||||||
|
"Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("replay_proxy")
|
||||||
|
.short('P')
|
||||||
|
.long("replay-proxy")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_hint(ValueHint::Url)
|
||||||
|
.value_name("REPLAY_PROXY")
|
||||||
|
.help_heading("Proxy settings")
|
||||||
|
.help(
|
||||||
|
"Send only unfiltered requests through a Replay Proxy, instead of all requests",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("replay_codes")
|
||||||
|
.short('R')
|
||||||
|
.long("replay-codes")
|
||||||
|
.value_name("REPLAY_CODE")
|
||||||
|
.takes_value(true)
|
||||||
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.use_delimiter(true)
|
||||||
|
.requires("replay_proxy")
|
||||||
|
.help_heading("Proxy settings")
|
||||||
|
.help(
|
||||||
|
"Status Codes to send through a Replay Proxy when found (default: --status-codes value)",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// group - request settings
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::new("user_agent")
|
||||||
|
.short('a')
|
||||||
|
.long("user-agent")
|
||||||
|
.value_name("USER_AGENT")
|
||||||
|
.takes_value(true)
|
||||||
|
.help_heading("Request settings")
|
||||||
|
.help(&**DEFAULT_USER_AGENT),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("random_agent")
|
||||||
|
.short('A')
|
||||||
|
.long("random-agent")
|
||||||
|
.takes_value(false)
|
||||||
|
.help_heading("Request settings")
|
||||||
|
.help("Use a random User-Agent"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("extensions")
|
||||||
|
.short('x')
|
||||||
|
.long("extensions")
|
||||||
|
.value_name("FILE_EXTENSION")
|
||||||
|
.takes_value(true)
|
||||||
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.use_delimiter(true)
|
||||||
|
.help_heading("Request settings")
|
||||||
|
.help(
|
||||||
|
"File extension(s) to search for (ex: -x php -x pdf js)",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("methods")
|
||||||
|
.short('m')
|
||||||
|
.long("methods")
|
||||||
|
.value_name("HTTP_METHODS")
|
||||||
|
.takes_value(true)
|
||||||
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.use_delimiter(true)
|
||||||
|
.help_heading("Request settings")
|
||||||
|
.help(
|
||||||
|
"Which HTTP request method(s) should be sent (default: GET)",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("data")
|
||||||
|
.long("data")
|
||||||
|
.value_name("DATA")
|
||||||
|
.takes_value(true)
|
||||||
|
.help_heading("Request settings")
|
||||||
|
.help(
|
||||||
|
"Request's Body; can read data from a file if input starts with an @ (ex: @post.bin)",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("headers")
|
||||||
|
.short('H')
|
||||||
|
.long("headers")
|
||||||
|
.value_name("HEADER")
|
||||||
|
.takes_value(true)
|
||||||
|
.help_heading("Request settings")
|
||||||
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.use_delimiter(true)
|
||||||
|
.help(
|
||||||
|
"Specify HTTP headers to be used in each request (ex: -H Header:val -H 'stuff: things')",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("cookies")
|
||||||
|
.short('b')
|
||||||
|
.long("cookies")
|
||||||
|
.value_name("COOKIE")
|
||||||
|
.takes_value(true)
|
||||||
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.use_delimiter(true)
|
||||||
|
.help_heading("Request settings")
|
||||||
|
.help(
|
||||||
|
"Specify HTTP cookies to be used in each request (ex: -b stuff=things)",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("queries")
|
||||||
|
.short('Q')
|
||||||
|
.long("query")
|
||||||
|
.value_name("QUERY")
|
||||||
|
.takes_value(true)
|
||||||
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.use_delimiter(true)
|
||||||
|
.help_heading("Request settings")
|
||||||
|
.help(
|
||||||
|
"Request's URL query parameters (ex: -Q token=stuff -Q secret=key)",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("add_slash")
|
||||||
|
.short('f')
|
||||||
|
.long("add-slash")
|
||||||
|
.help_heading("Request settings")
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Append / to each request's URL")
|
||||||
|
);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// group - request filters
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
let app = app.arg(
|
||||||
|
Arg::new("url_denylist")
|
||||||
|
.long("dont-scan")
|
||||||
|
.value_name("URL")
|
||||||
|
.takes_value(true)
|
||||||
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.use_delimiter(true)
|
||||||
|
.help_heading("Request filters")
|
||||||
|
.help("URL(s) or Regex Pattern(s) to exclude from recursion/scans"),
|
||||||
|
);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// group - response filters
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::new("filter_size")
|
||||||
|
.short('S')
|
||||||
.long("filter-size")
|
.long("filter-size")
|
||||||
.value_name("SIZE")
|
.value_name("SIZE")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
.use_delimiter(true)
|
.use_delimiter(true)
|
||||||
|
.help_heading("Response filters")
|
||||||
.help(
|
.help(
|
||||||
"Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)",
|
"Filter out messages of a particular size (ex: -S 5120 -S 4927,1970)",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("filter_regex")
|
Arg::new("filter_regex")
|
||||||
.short("X")
|
.short('X')
|
||||||
.long("filter-regex")
|
.long("filter-regex")
|
||||||
.value_name("REGEX")
|
.value_name("REGEX")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
.use_delimiter(true)
|
.use_delimiter(true)
|
||||||
|
.help_heading("Response filters")
|
||||||
.help(
|
.help(
|
||||||
"Filter out messages via regular expression matching on the response's body (ex: -X '^ignore me$')",
|
"Filter out messages via regular expression matching on the response's body (ex: -X '^ignore me$')",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("filter_words")
|
Arg::new("filter_words")
|
||||||
.short("W")
|
.short('W')
|
||||||
.long("filter-words")
|
.long("filter-words")
|
||||||
.value_name("WORDS")
|
.value_name("WORDS")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
.use_delimiter(true)
|
.use_delimiter(true)
|
||||||
|
.help_heading("Response filters")
|
||||||
.help(
|
.help(
|
||||||
"Filter out messages of a particular word count (ex: -W 312 -W 91,82)",
|
"Filter out messages of a particular word count (ex: -W 312 -W 91,82)",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("filter_lines")
|
Arg::new("filter_lines")
|
||||||
.short("N")
|
.short('N')
|
||||||
.long("filter-lines")
|
.long("filter-lines")
|
||||||
.value_name("LINES")
|
.value_name("LINES")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
.use_delimiter(true)
|
.use_delimiter(true)
|
||||||
|
.help_heading("Response filters")
|
||||||
.help(
|
.help(
|
||||||
"Filter out messages of a particular line count (ex: -N 20 -N 31,30)",
|
"Filter out messages of a particular line count (ex: -N 20 -N 31,30)",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("filter_status")
|
Arg::new("filter_status")
|
||||||
.short("C")
|
.short('C')
|
||||||
.long("filter-status")
|
.long("filter-status")
|
||||||
.value_name("STATUS_CODE")
|
.value_name("STATUS_CODE")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
.use_delimiter(true)
|
.use_delimiter(true)
|
||||||
|
.help_heading("Response filters")
|
||||||
.help(
|
.help(
|
||||||
"Filter out status codes (deny list) (ex: -C 200 -C 401)",
|
"Filter out status codes (deny list) (ex: -C 200 -C 401)",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("filter_similar")
|
Arg::new("filter_similar")
|
||||||
.long("filter-similar-to")
|
.long("filter-similar-to")
|
||||||
.value_name("UNWANTED_PAGE")
|
.value_name("UNWANTED_PAGE")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.value_hint(ValueHint::Url)
|
||||||
.use_delimiter(true)
|
.use_delimiter(true)
|
||||||
|
.help_heading("Response filters")
|
||||||
.help(
|
.help(
|
||||||
"Filter out pages that are similar to the given page (ex. --filter-similar-to http://site.xyz/soft404)",
|
"Filter out pages that are similar to the given page (ex. --filter-similar-to http://site.xyz/soft404)",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("extract_links")
|
Arg::new("status_codes")
|
||||||
.short("e")
|
.short('s')
|
||||||
.long("extract-links")
|
.long("status-codes")
|
||||||
.takes_value(false)
|
.value_name("STATUS_CODE")
|
||||||
.help("Extract links from response body (html, javascript, etc...); make new requests based on findings (default: false)")
|
.takes_value(true)
|
||||||
|
.multiple_values(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.use_delimiter(true)
|
||||||
|
.help_heading("Response filters")
|
||||||
|
.help(
|
||||||
|
"Status Codes to include (allow list) (default: 200 204 301 302 307 308 401 403 405)",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// group - client settings
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::new("timeout")
|
||||||
|
.short('T')
|
||||||
|
.long("timeout")
|
||||||
|
.value_name("SECONDS")
|
||||||
|
.takes_value(true)
|
||||||
|
.help_heading("Client settings")
|
||||||
|
.help("Number of seconds before a client's request times out (default: 7)"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("scan_limit")
|
Arg::new("redirects")
|
||||||
.short("L")
|
.short('r')
|
||||||
|
.long("redirects")
|
||||||
|
.takes_value(false)
|
||||||
|
.help_heading("Client settings")
|
||||||
|
.help("Allow client to follow redirects"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("insecure")
|
||||||
|
.short('k')
|
||||||
|
.long("insecure")
|
||||||
|
.takes_value(false)
|
||||||
|
.help_heading("Client settings")
|
||||||
|
.help("Disables TLS certificate validation in the client"),
|
||||||
|
);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// group - scan settings
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::new("threads")
|
||||||
|
.short('t')
|
||||||
|
.long("threads")
|
||||||
|
.value_name("THREADS")
|
||||||
|
.takes_value(true)
|
||||||
|
.help_heading("Scan settings")
|
||||||
|
.help("Number of concurrent threads (default: 50)"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("no_recursion")
|
||||||
|
.short('n')
|
||||||
|
.long("no-recursion")
|
||||||
|
.takes_value(false)
|
||||||
|
.help_heading("Scan settings")
|
||||||
|
.help("Do not scan recursively"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("depth")
|
||||||
|
.short('d')
|
||||||
|
.long("depth")
|
||||||
|
.value_name("RECURSION_DEPTH")
|
||||||
|
.takes_value(true)
|
||||||
|
.help_heading("Scan settings")
|
||||||
|
.help("Maximum recursion depth, a depth of 0 is infinite recursion (default: 4)"),
|
||||||
|
).arg(
|
||||||
|
Arg::new("extract_links")
|
||||||
|
.short('e')
|
||||||
|
.long("extract-links")
|
||||||
|
.takes_value(false)
|
||||||
|
.help_heading("Scan settings")
|
||||||
|
.help("Extract links from response body (html, javascript, etc...); make new requests based on findings")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("scan_limit")
|
||||||
|
.short('L')
|
||||||
.long("scan-limit")
|
.long("scan-limit")
|
||||||
.value_name("SCAN_LIMIT")
|
.value_name("SCAN_LIMIT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
|
.help_heading("Scan settings")
|
||||||
.help("Limit total number of concurrent scans (default: 0, i.e. no limit)")
|
.help("Limit total number of concurrent scans (default: 0, i.e. no limit)")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("parallel")
|
Arg::new("parallel")
|
||||||
.long("parallel")
|
.long("parallel")
|
||||||
.value_name("PARALLEL_SCANS")
|
.value_name("PARALLEL_SCANS")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.requires("stdin")
|
.requires("stdin")
|
||||||
|
.help_heading("Scan settings")
|
||||||
.help("Run parallel feroxbuster instances (one child process per url passed via stdin)")
|
.help("Run parallel feroxbuster instances (one child process per url passed via stdin)")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("rate_limit")
|
Arg::new("rate_limit")
|
||||||
.long("rate-limit")
|
.long("rate-limit")
|
||||||
.value_name("RATE_LIMIT")
|
.value_name("RATE_LIMIT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.conflicts_with("auto_tune")
|
.conflicts_with("auto_tune")
|
||||||
|
.help_heading("Scan settings")
|
||||||
.help("Limit number of requests per second (per directory) (default: 0, i.e. no limit)")
|
.help("Limit number of requests per second (per directory) (default: 0, i.e. no limit)")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("time_limit")
|
Arg::new("time_limit")
|
||||||
.long("time-limit")
|
.long("time-limit")
|
||||||
.value_name("TIME_SPEC")
|
.value_name("TIME_SPEC")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(valid_time_spec)
|
.validator(valid_time_spec)
|
||||||
|
.help_heading("Scan settings")
|
||||||
.help("Limit total run time of all scans (ex: --time-limit 10m)")
|
.help("Limit total run time of all scans (ex: --time-limit 10m)")
|
||||||
)
|
)
|
||||||
.group(ArgGroup::with_name("output_files")
|
.arg(
|
||||||
.args(&["debug_log", "output"])
|
Arg::new("wordlist")
|
||||||
.multiple(true)
|
.short('w')
|
||||||
|
.long("wordlist")
|
||||||
|
.value_hint(ValueHint::FilePath)
|
||||||
|
.value_name("FILE")
|
||||||
|
.help("Path to the wordlist")
|
||||||
|
.help_heading("Scan settings")
|
||||||
|
.takes_value(true),
|
||||||
|
).arg(
|
||||||
|
Arg::new("auto_tune")
|
||||||
|
.long("auto-tune")
|
||||||
|
.takes_value(false)
|
||||||
|
.conflicts_with("auto_bail")
|
||||||
|
.help_heading("Scan settings")
|
||||||
|
.help("Automatically lower scan rate when an excessive amount of errors are encountered")
|
||||||
)
|
)
|
||||||
.after_help(r#"NOTE:
|
.arg(
|
||||||
|
Arg::new("auto_bail")
|
||||||
|
.long("auto-bail")
|
||||||
|
.takes_value(false)
|
||||||
|
.help_heading("Scan settings")
|
||||||
|
.help("Automatically stop scanning when an excessive amount of errors are encountered")
|
||||||
|
).arg(
|
||||||
|
Arg::new("dont_filter")
|
||||||
|
.short('D')
|
||||||
|
.long("dont-filter")
|
||||||
|
.takes_value(false)
|
||||||
|
.help_heading("Scan settings")
|
||||||
|
.help("Don't auto-filter wildcard responses")
|
||||||
|
);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// group - output settings
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::new("verbosity")
|
||||||
|
.short('v')
|
||||||
|
.long("verbosity")
|
||||||
|
.takes_value(false)
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.conflicts_with("silent")
|
||||||
|
.help_heading("Output settings")
|
||||||
|
.help("Increase verbosity level (use -vv or more for greater effect. [CAUTION] 4 -v's is probably too much)"),
|
||||||
|
).arg(
|
||||||
|
Arg::new("silent")
|
||||||
|
.long("silent")
|
||||||
|
.takes_value(false)
|
||||||
|
.conflicts_with("quiet")
|
||||||
|
.help_heading("Output settings")
|
||||||
|
.help("Only print URLs + turn off logging (good for piping a list of urls to other commands)")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("quiet")
|
||||||
|
.short('q')
|
||||||
|
.long("quiet")
|
||||||
|
.takes_value(false)
|
||||||
|
.help_heading("Output settings")
|
||||||
|
.help("Hide progress bars and banner (good for tmux windows w/ notifications)")
|
||||||
|
)
|
||||||
|
|
||||||
|
.arg(
|
||||||
|
Arg::new("json")
|
||||||
|
.long("json")
|
||||||
|
.takes_value(false)
|
||||||
|
.requires("output_files")
|
||||||
|
.help_heading("Output settings")
|
||||||
|
.help("Emit JSON logs to --output and --debug-log instead of normal text")
|
||||||
|
).arg(
|
||||||
|
Arg::new("output")
|
||||||
|
.short('o')
|
||||||
|
.long("output")
|
||||||
|
.value_hint(ValueHint::FilePath)
|
||||||
|
.value_name("FILE")
|
||||||
|
.help_heading("Output settings")
|
||||||
|
.help("Output file to write results to (use w/ --json for JSON entries)")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("debug_log")
|
||||||
|
.long("debug-log")
|
||||||
|
.value_name("FILE")
|
||||||
|
.value_hint(ValueHint::FilePath)
|
||||||
|
.help_heading("Output settings")
|
||||||
|
.help("Output file to write log entries (use w/ --json for JSON entries)")
|
||||||
|
.takes_value(true),
|
||||||
|
);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// group - miscellaneous
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
let mut app = app
|
||||||
|
.group(
|
||||||
|
ArgGroup::new("output_files")
|
||||||
|
.args(&["debug_log", "output"])
|
||||||
|
.multiple(true),
|
||||||
|
)
|
||||||
|
.after_long_help(EPILOGUE);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// end parser
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
for arg in env::args() {
|
||||||
|
// secure-77 noticed that when an incorrect flag/option is used, the short help message is printed
|
||||||
|
// which is fine, but if you add -h|--help, it still errors out on the bad flag/option,
|
||||||
|
// never showing the full help message. This code addresses that behavior
|
||||||
|
if arg == "--help" {
|
||||||
|
app.print_long_help().unwrap();
|
||||||
|
println!(); // just a newline to mirror original --help output
|
||||||
|
process::exit(0);
|
||||||
|
} else if arg == "-h" {
|
||||||
|
// same for -h, just shorter
|
||||||
|
app.print_help().unwrap();
|
||||||
|
println!();
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validate that a string is formatted as a number followed by s, m, h, or d (10d, 30s, etc...)
|
||||||
|
fn valid_time_spec(time_spec: &str) -> Result<(), String> {
|
||||||
|
match TIMESPEC_REGEX.is_match(time_spec) {
|
||||||
|
true => Ok(()),
|
||||||
|
false => {
|
||||||
|
let msg = format!(
|
||||||
|
"Expected a non-negative, whole number followed by s, m, h, or d (case insensitive); received {}",
|
||||||
|
time_spec
|
||||||
|
);
|
||||||
|
Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const EPILOGUE: &str = r#"NOTE:
|
||||||
Options that take multiple values are very flexible. Consider the following ways of specifying
|
Options that take multiple values are very flexible. Consider the following ways of specifying
|
||||||
extensions:
|
extensions:
|
||||||
./feroxbuster -u http://127.1 -x pdf -x js,html -x php txt json,docx
|
./feroxbuster -u http://127.1 -x pdf -x js,html -x php txt json,docx
|
||||||
@@ -463,36 +609,21 @@ EXAMPLES:
|
|||||||
./feroxbuster -u http://127.1 --extract-links
|
./feroxbuster -u http://127.1 --extract-links
|
||||||
|
|
||||||
Ludicrous speed... go!
|
Ludicrous speed... go!
|
||||||
./feroxbuster -u http://127.1 -t 200
|
./feroxbuster -u http://127.1 -threads 200
|
||||||
"#);
|
|
||||||
|
Limit to a total of 60 active requests at any given time (threads * scan limit)
|
||||||
for arg in env::args() {
|
./feroxbuster -u http://127.1 --threads 30 --scan-limit 2
|
||||||
// secure-77 noticed that when an incorrect flag/option is used, the short help message is printed
|
|
||||||
// which is fine, but if you add -h|--help, it still errors out on the bad flag/option,
|
Send all 200/302 responses to a proxy (only proxy requests/responses you care about)
|
||||||
// never showing the full help message. This code addresses that behavior
|
./feroxbuster -u http://127.1 --replay-proxy http://localhost:8080 --replay-codes 200 302 --insecure
|
||||||
if arg == "--help" || arg == "-h" {
|
|
||||||
app.print_long_help().unwrap();
|
Abort or reduce scan speed to individual directory scans when too many errors have occurred
|
||||||
println!(); // just a newline to mirror original --help output
|
./feroxbuster -u http://127.1 --auto-bail
|
||||||
process::exit(0);
|
./feroxbuster -u http://127.1 --auto-tune
|
||||||
}
|
|
||||||
}
|
Examples and demonstrations of all features
|
||||||
|
https://epi052.github.io/feroxbuster-docs/docs/examples/
|
||||||
app
|
"#;
|
||||||
}
|
|
||||||
|
|
||||||
/// Validate that a string is formatted as a number followed by s, m, h, or d (10d, 30s, etc...)
|
|
||||||
fn valid_time_spec(time_spec: String) -> Result<(), String> {
|
|
||||||
match TIMESPEC_REGEX.is_match(&time_spec) {
|
|
||||||
true => Ok(()),
|
|
||||||
false => {
|
|
||||||
let msg = format!(
|
|
||||||
"Expected a non-negative, whole number followed by s, m, h, or d (case insensitive); received {}",
|
|
||||||
time_spec
|
|
||||||
);
|
|
||||||
Err(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@@ -512,29 +643,29 @@ mod tests {
|
|||||||
/// that i didn't hose up the regex. Going to consolidate them into a single test
|
/// that i didn't hose up the regex. Going to consolidate them into a single test
|
||||||
fn validate_valid_time_spec_validation() {
|
fn validate_valid_time_spec_validation() {
|
||||||
let float_rejected = "1.4m";
|
let float_rejected = "1.4m";
|
||||||
assert!(valid_time_spec(float_rejected.into()).is_err());
|
assert!(valid_time_spec(float_rejected).is_err());
|
||||||
|
|
||||||
let negative_rejected = "-1m";
|
let negative_rejected = "-1m";
|
||||||
assert!(valid_time_spec(negative_rejected.into()).is_err());
|
assert!(valid_time_spec(negative_rejected).is_err());
|
||||||
|
|
||||||
let only_number_rejected = "1";
|
let only_number_rejected = "1";
|
||||||
assert!(valid_time_spec(only_number_rejected.into()).is_err());
|
assert!(valid_time_spec(only_number_rejected).is_err());
|
||||||
|
|
||||||
let only_measurement_rejected = "m";
|
let only_measurement_rejected = "m";
|
||||||
assert!(valid_time_spec(only_measurement_rejected.into()).is_err());
|
assert!(valid_time_spec(only_measurement_rejected).is_err());
|
||||||
|
|
||||||
for accepted_measurement in &["s", "m", "h", "d", "S", "M", "H", "D"] {
|
for accepted_measurement in &["s", "m", "h", "d", "S", "M", "H", "D"] {
|
||||||
// all upper/lowercase should be good
|
// all upper/lowercase should be good
|
||||||
assert!(valid_time_spec(format!("1{}", *accepted_measurement)).is_ok());
|
assert!(valid_time_spec(&format!("1{}", *accepted_measurement)).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
let leading_space_rejected = " 14m";
|
let leading_space_rejected = " 14m";
|
||||||
assert!(valid_time_spec(leading_space_rejected.into()).is_err());
|
assert!(valid_time_spec(leading_space_rejected).is_err());
|
||||||
|
|
||||||
let trailing_space_rejected = "14m ";
|
let trailing_space_rejected = "14m ";
|
||||||
assert!(valid_time_spec(trailing_space_rejected.into()).is_err());
|
assert!(valid_time_spec(trailing_space_rejected).is_err());
|
||||||
|
|
||||||
let space_between_rejected = "1 4m";
|
let space_between_rejected = "1 4m";
|
||||||
assert!(valid_time_spec(space_between_rejected.into()).is_err());
|
assert!(valid_time_spec(space_between_rejected).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ pub(super) struct Requester {
|
|||||||
/// need a usize to determine the number of consecutive non-error calls that a requester has
|
/// need a usize to determine the number of consecutive non-error calls that a requester has
|
||||||
/// seen; this will satisfy the non-mut self constraint (due to us being behind an Arc, and
|
/// seen; this will satisfy the non-mut self constraint (due to us being behind an Arc, and
|
||||||
/// the need for a counter)
|
/// the need for a counter)
|
||||||
|
#[allow(clippy::mutex_atomic)]
|
||||||
tuning_lock: Mutex<usize>,
|
tuning_lock: Mutex<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ fn parser_incorrect_param_with_tack_tack_help() {
|
|||||||
///
|
///
|
||||||
/// For more information try --help
|
/// For more information try --help
|
||||||
///
|
///
|
||||||
/// the new behavior we expect to see is to print the long form help message, of which
|
/// the new behavior we expect to see is to print the short form help message, of which
|
||||||
/// Ludicrous speed... go! is near the bottom of that output, so we can test for that
|
/// "[CAUTION] 4 -v's is probably too much" is near the bottom of that output, so we can test for that
|
||||||
fn parser_incorrect_param_with_tack_h() {
|
fn parser_incorrect_param_with_tack_h() {
|
||||||
Command::cargo_bin("feroxbuster")
|
Command::cargo_bin("feroxbuster")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -42,5 +42,7 @@ fn parser_incorrect_param_with_tack_h() {
|
|||||||
.arg("-h")
|
.arg("-h")
|
||||||
.assert()
|
.assert()
|
||||||
.success()
|
.success()
|
||||||
.stdout(predicate::str::contains("Ludicrous speed... go!"));
|
.stdout(predicate::str::contains(
|
||||||
|
"[CAUTION] 4 -v's is probably too much",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ fn scanner_single_request_replayed_to_proxy() -> Result<(), Box<dyn std::error::
|
|||||||
.arg("--wordlist")
|
.arg("--wordlist")
|
||||||
.arg(file.as_os_str())
|
.arg(file.as_os_str())
|
||||||
.arg("--replay-proxy")
|
.arg("--replay-proxy")
|
||||||
.arg(format!("http://{}", proxy.address().to_string()))
|
.arg(format!("http://{}", proxy.address()))
|
||||||
.arg("--replay-codes")
|
.arg("--replay-codes")
|
||||||
.arg("200")
|
.arg("200")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user