Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 8 additions & 59 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 44 additions & 21 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,56 @@ version = "0.1.0"
edition = "2024"

[dependencies]
anyhow = "1.0.100"
chrono = "0.4.43"
clap = { version = "4.5.54", features = ["derive"] }
colored = "3.1.1"
csv = "1.4.0"
dashmap = "6.1.0"
eframe = "0.33.3"
egui = "0.33.3"
indicatif = "0.18.3"
# --- [ Error Handling & Logging ] ---
anyhow = "1.0.100" # Flexible error handling for applications
log = "0.4.29" # Standard logging facade
simple_logger = "5.1.0" # Simple logger for terminal output

# --- [ Networking Core ] ---
# Low-level packet construction and raw socket access
pnet = { version = "0.35.0", features = ["std"] }
pnet_packet = "0.35.0" # Specialized packet parsing/manipulation
surge-ping = "0.8.4" # High-level ICMP (Ping) implementation for host discovery
# Subnet and IP range calculations (CIDR math)
ipnet = "2.11.0"
ipnetwork = "0.21.1"
log = "0.4.29"
network-interface = "2.0.5"
pnet = { version = "0.35.0", features = ["std"] }
pnet_packet = "0.35.0"
network-interface = "2.0.5" # Helper to find local adapters/interfaces for source IP selection

# --- [ Asynchronous Runtime ] ---
# The heart of the concurrent scanner
tokio = { version = "1.49.0", features = ["full", "io-util"] }
tokio-util = { version = "0.7.18", features = ["full"] }


# --- [ Data Structures & Parallelism ] ---
# Concurrent Hashmap for sharing 'pending scans' across threads
dashmap = "6.1.0"
# Thread-safe random numbers (e.g., for TCP Sequence Numbers)
rand = "0.9.2"
regex = "1.12.2"

# --- [ GUI Framework (egui) ] ---
# Immediate mode GUI for the dashboard
egui = "0.33.3"
eframe = "0.33.3" # The framework to run egui on OS windows
rfd = "0.17.2" # Native file dialogs (Save/Open results)

# --- [ CLI & UI Helpers ] ---
clap = { version = "4.5.54", features = ["derive"] } # CLI Argument parsing
indicatif = "0.18.3" # Progress bars for long network scans
colored = "3.1.1" # Terminal colors (RED/GREEN status)


# --- [ Web & Data Handling ] ---
# For Banner Grabbing or checking web server headers
reqwest = { version = "0.13.1", features = ["native-tls"] }
rfd = "0.17.2"
# Serialization/Deserialization for config and output
serde = { version = "1.0.228", features = ["derive"] }
serde-xml-rs = "0.8.2"
serde_json = "1.0.149"
simple_logger = "5.1.0"
surge-ping = "0.8.4"
tokio = { version = "1.49.0", features = ["full", "io-util"] }
tokio-util = { version = "0.7.18", features = ["full"] }
serde-xml-rs = "0.8.2" # Parsing Nmap-style XML output
csv = "1.4.0" # Exporting scan results to Excel-friendly format
regex = "1.12.2" # Parsing text signatures/banners


[dev-dependencies]
# Mocking HTTP responses for testing the web-scanner parts
wiremock = "0.6.5"

18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ pentest-kit --headers https://example.com -o audit.json
* **Network Isolation** : Ensure your testing environment is firewalled from the public internet.
* **DNS** : If testing local VMs, ensure your `/etc/hosts` file is configured correctly for target resolution.

**Verified Test Targets:**
* **Localhost** : Tested against a multi-threaded Python 3 HTTP server on port 8080.
* **Container** : Audited a local OWASP Juice Shop Docker container to verify HeaderGrapper and DirFinder accuracy.
* **VM** : Conducted ping sweeps across a Host-Only subnet (192.168.56.0/24) to verify HostMapper.

## Legal & Ethical Warning

[!IMPORTANT] FOR AUTHORIZED EDUCATIONAL USE ONLY.
Expand All @@ -136,6 +141,9 @@ The use of this software for scanning targets without prior mutual consent is il
* **Target Unreachable:** Verify the target VM's IP address and ensure your network settings (NAT/Bridged) allow communication.
* **Zero Results in DirFinder:** Ensure your wordlist path is correct and that the target doesn't have a WAF (Web Application Firewall) blocking rapid requests.
* **OpenSSL Errors:** Ensure `libssl-dev` (Linux) or `openssl` (macOS) is installed on your development machine.
* **Non-Root Users** : If the -sS (SYN scan) flag is used without sudo or the cap_net_raw capability, the tool will exit with an error as it cannot open raw sockets.
* **Network Interface Access** : On Linux, the tool may fail to list interfaces if the user does not have read access to /sys/class/net/.


### Known Limitations

Expand All @@ -147,6 +155,8 @@ The use of this software for scanning targets without prior mutual consent is il

## Output Format Explanations

* **Storage Location** : By default, all output files are saved in the current working directory from which the command was executed. You may provide an absolute path (e.g., -o /home/user/reports/scan.json) to save elsewhere.

The toolkit uses a smart-detection system based on file extensions:

* **JSON (`.json`):** Full data dump including nested maps of all retrieved HTTP headers. Best for post-processing with other tools.
Expand All @@ -163,3 +173,11 @@ Pentest-Kit is a high-performance reconnaissance tool designed to provide rapid
1. **Speed:** Utilizing Rust's `Tokio` runtime for non-blocking I/O.
2. **Security Auditing:** Identifying misconfigured headers and sensitive file exposures (like `.env` or `.git`).
3. **Versatility:** Offering multiple scanning modes (SYN, Connect, Dir-Brute) in a single binary.


## HELP: Running without Sudo
To run SYN scans without being root every time, grant the binary specific capabilities:

```bash
sudo setcap cap_net_raw,cap_net_admin=eip ./target/debug/pentest-kit
```
14 changes: 14 additions & 0 deletions result1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"port": 22,
"state": "OPEN"
},
{
"port": 80,
"state": "CLOSED"
},
{
"port": 443,
"state": "CLOSED"
}
]
1 change: 1 addition & 0 deletions result2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[200] http://example.com//
5 changes: 5 additions & 0 deletions result3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
10.1.8.6 - LIVE (144.962µs)
10.1.8.3 - LIVE (208.354µs)
10.1.8.12 - LIVE (151.156µs)
10.1.8.5 - LIVE (165.044µs)
10.1.8.7 - LIVE (463.297µs)
17 changes: 17 additions & 0 deletions result4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--- HEADER ANALYSIS REPORT ---
URL : http://example.com
Status : 200 OK
Server : cloudflare
Headers:
cf-cache-status: HIT,
server: cloudflare,
age: 6331,
last-modified: Fri, 30 Jan 2026 23:42:19 GMT,
date: Sun, 01 Feb 2026 16:49:24 GMT,
cf-ray: 9c72f1212e6e4893-LIS,
allow: GET, HEAD,
accept-ranges: bytes,
content-type: text/html,
connection: keep-alive,
Score : 0/100
Missing: Content-Security-Policy, Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy
21 changes: 21 additions & 0 deletions src/bin/pentestkit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use pentest_kit::utils::preluad::*;

/// The entry point for the PentestKit application.
///
/// We use `#[tokio::main]` to initialize the multi-threaded async runtime,
/// which allows all downstream tools to perform non-blocking network I/O.
#[tokio::main]
async fn main() -> Result<()> {
let mut cli = Cli::parse();
if cli.threads == 0 {
warn!("ignore number of threads");
cli.threads = 50;
}
logger(&cli);
if !cli.gui {
start_commands(&cli).await?;
} else {
start_gui()?;
}
Ok(())
}
58 changes: 57 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use anyhow::Ok;
use clap::Parser;
use ipnet::Ipv4Net;
use crate::utils::preluad::*;

use crate::hostmapper::localnet::get_localnet;
use crate::{hostmapper::localnet::get_localnet, tinyscanner};

#[derive(Parser, Default)]
#[command(
Expand Down Expand Up @@ -175,3 +176,58 @@ impl TryFrom<&Cli> for Mode {
}
}
}





/// The command dispatcher.
/// Maps the CLI arguments to the specific tool logic (TinyScanner, DirFinder, etc.).
pub async fn start_commands(cli: &Cli) -> Result<()> {
let mode = Mode::try_from(cli)?;
match mode {
Mode::TinyScanner {
ref target,
ref ports,
verify,
} => {
println!("Running TinyScanner on {target} ports {ports}");
tinyscanner::run(
target,
ports,
cli.threads,
&cli.output,
&cli.scan_mode,
verify,
None,
)
.await?;
exit(0)
}
Mode::DirFinder { url, wordlist } => {
println!("DirFinder → {url} with wordlist {wordlist}");
dirfinder::run(
&url,
&wordlist,
cli.threads,
&cli.output,
&cli.extensions,
None,
)
.await?;
}
Mode::HostMapper { subnet } => {
println!("HostMapper on subnet {subnet}");
hostmapper::run(subnet, cli.threads, &cli.output, None).await?;
}
Mode::HeaderGrabber { url } => {
println!("HeaderGrabber on {url}");
headergrabber::run(&url, &cli.output, None).await?;
}
}

if let Some(out) = &cli.output {
println!("→ Results will be saved to: {out}");
}
Ok(())
}
Loading
Loading