Compare commits

..
26 Commits
Author SHA1 Message Date
Brandon b52a990ad0 Merge pull request #95 from RustScan/bee-scheduled-markdown-action
Scheduled markdown action 404 links
2020-08-01 22:47:37 +01:00
Brandon c8404781dc Merge branch 'master' into bee-scheduled-markdown-action 2020-08-01 22:45:29 +01:00
Brandon 6ab43bf213 Merge pull request #96 from bernardoamc/ba-reduce-unsig-int
Refactor ulimit and batch_size logic consider the OS architecture
2020-08-01 21:15:39 +01:00
Brandon da3629cc7b Merge branch 'master' into bee-scheduled-markdown-action 2020-08-01 21:08:11 +01:00
Bernardo de Araujo af344becbc Refactor ulimit and batch_size logic consider the OS architecture
RustScan should be able to run on systems with either 32 or 64 bits. In
order to achieve that we should rely on the `rlimit` library to get the
proper unsigned int type from the system.
2020-08-01 15:45:31 -04:00
Brandon 85b7f9fe7a Merge pull request #94 from RustScan/bee-readme-community-additions
Updated readme
2020-08-01 19:34:00 +01:00
Brandon 9d1d064e71 fixed typo 2020-08-01 19:30:33 +01:00
Brandon 343563818f checking to see if CI works 2020-08-01 17:40:59 +01:00
Brandon bc77814d59 checking to see if CI works 2020-08-01 17:37:49 +01:00
Brandon 42b72ea114 added daily 404 link checking 2020-08-01 17:31:46 +01:00
Brandon d73c66482e Updated readme 2020-08-01 17:07:50 +01:00
Brandon 82e3128641 Update README.md 2020-08-01 13:21:53 +01:00
Brandon 679d1a787d Merge pull request #92 from RustScan/dependabot/cargo/colored-2.0.0
Bump colored from 1.9.3 to 2.0.0
2020-08-01 11:42:04 +01:00
dependabot-preview[bot] 813b6753c8 Bump colored from 1.9.3 to 2.0.0
Bumps [colored](https://github.com/mackwic/colored) from 1.9.3 to 2.0.0.
- [Release notes](https://github.com/mackwic/colored/releases)
- [Changelog](https://github.com/mackwic/colored/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mackwic/colored/compare/v1.9.3...v2.0.0)

Signed-off-by: dependabot-preview[bot] <[email protected]>
2020-08-01 10:35:53 +00:00
Brandon 51df49836b Merge pull request #91 from bernardoamc/ba-refactor-ip-parsing
Fail early when the specified IP format is not valid
2020-08-01 11:18:53 +01:00
Bernardo de Araujo 2df98016c9 Fail early when the specified IP format is not valid
We can let structopt parse the supplied IP for us and fail early when
that IP address is invalid. We can also let IpAddr let us know when an
IP is an ipv4 or ipv6 without relying on the user to supply this
information to us.
2020-08-01 00:15:19 -04:00
Brandon deb8bb3216 rust fmt 2020-07-31 16:23:28 +01:00
Brandon 6ce8fe1afd trying to fix docs.rs 2020-07-31 14:23:38 +01:00
Brandon 8aa9a44949 updating lock file 2020-07-31 13:34:33 +01:00
Brandon 416602dd02 added ipv6 to readme 2020-07-31 13:34:04 +01:00
Brandon a2e7125e03 updated cargo.toml 2020-07-31 13:33:24 +01:00
Brandon 10acad243c Merge pull request #87 from RustScan/ipv6-support
Ipv6 support
2020-07-31 13:02:56 +01:00
Brandon ef893fdcb8 Update README.md 2020-07-30 12:49:22 +01:00
Brandon 7ad7e34abc Updated comments -> issues bot 2020-07-30 12:24:36 +01:00
Brandon e41393b4ad Update Dockerfile 2020-07-30 11:22:45 +01:00
Brandon 4785b75f9f 1.3 release 2020-07-29 12:02:01 +01:00
10 changed files with 182 additions and 193 deletions

No files matched your search

+1 -1
View File
@@ -1,2 +1,2 @@
todo:
keyword: "TODO"
keyword: "// TODO"
+8 -1
View File
@@ -45,4 +45,11 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
args: --all -- --check
links:
name: markdown-link-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: gaurav-nelson/github-action-markdown-link-check@v1
@@ -0,0 +1,18 @@
name: Check Markdown links
on:
push:
branches:
- master
schedule:
# Run everyday at 9:00 AM (See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html#tag_20_25_07)
- cron: "0 9 * * *"
jobs:
markdown-link-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: gaurav-nelson/github-action-markdown-link-check@v1
with:
use-quiet-mode: 'yes'
Generated
+3 -3
View File
@@ -142,9 +142,9 @@ dependencies = [
[[package]]
name = "colored"
version = "1.9.3"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
@@ -530,7 +530,7 @@ dependencies = [
[[package]]
name = "rustscan"
version = "1.2.0"
version = "1.4.1"
dependencies = [
"async-std",
"colored",
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "rustscan"
version = "1.2.0"
version = "1.4.1"
authors = ["Bee <[email protected]>"]
edition = "2018"
description = "Faster Nmap Scanning with Rust"
@@ -14,7 +14,7 @@ readme="README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
colored = "1.9.3"
colored = "2.0.0"
structopt = "0.3.15"
async-std = "1.6.2"
futures = "0.3"
+49 -19
View File
@@ -1,6 +1,6 @@
<p align="center">
➡️
<a href="https://discord.gg/r38pna">Discord</a> |
<a href="https://discord.gg/GFrQsGy">Discord</a> |
<a href="https://github.com/RustScan/RustScan#-full-installation-guide">Installation Guide</a> |
<a href="https://github.com/RustScan/RustScan#-usage">Usage Guide</a>
⬅️
@@ -17,7 +17,7 @@
<img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/rustscan/rustscan/total?label=GitHub%20Downloads">
<img alt="Crates.io" src="https://img.shields.io/crates/d/rustscan?label=Cargo%20Downloads">
<img alt="Discord" src="https://img.shields.io/discord/736614461313515576">
<img alt="Actions" src="https://github.com/RustScan/RustScan/workflows/Continuous%20integration/badge.svg">
<img alt="Actions" src="https://github.com/RustScan/RustScan/workflows/Continuous%20integration/badge.svg?branch=master">
</p>
<hr>
@@ -62,6 +62,7 @@ RustScans **only** job is to reduce the friction between finding open ports and
* Saves you time by automatically piping it into Nmap. No more manual copying and pasting!
* Does one thing and does it well. **Only** purpose is to improve Nmap, not replace it!
* Let's you choose what Nmap commands to run, or uses the default.
* IPv6 Support
# 🔭 Why RustScan?
Why spend time running fast scans and manually copying the ports, or waiting for a 20 minute scan to finish when you can just do all 65k ports in less than a minute?
@@ -78,21 +79,18 @@ Why spend time running fast scans and manually copying the ports, or waiting for
| Actually useful | ❌ | ✅ | ❌ |
| Realises it's not useful, and pipes the only useful data into the only useful port scanner | ✅ | ❌ | ❌ |
## ‼️ Important Links
## 🙋 FAQ
> I think this would be a great port scanner on its own without Nmap!
| Installation Guide | Documentation | Discord |
| ------------------ | ------------- | ------- |
| 📖 [Installation Guide](https://github.com/RustScan/RustScan#-full-installation-guide) | 📚 [Documentation](https://github.com/RustScan/RustScan/issues/89) | 🦜 [Discord](https://discord.gg/GFrQsGy)
No. If you want a fast port scanner, use Masscan.
> I have this great idea for a script to get information on ports / hosts
## 🙋 Table of Contents
* 📖 [Installation Guide](https://github.com/RustScan/RustScan#-full-installation-guide)
* 🦜 [Discord](https://discord.gg/GFrQsGy)
* 🤸 [Usage](https://github.com/RustScan/RustScan#-usage)
* 🎪 [Contributing](https://github.com/RustScan/RustScan#-contributing)
Great. Contribute it to Nmap! :D
> Not everyone has nmap installed....
If you're a pentester, then yes, you have Nmap installed.
> I want to contribute!
Great! I'd love some help with this. Read the [contributing.md file](contributing.md) file for more information!
# 📖 Full Installation Guide
**You need Nmap**. If you have Kali Linux or Parrot OS installed, you already have Nmap. If not, [follow the nmap install guide](https://nmap.org/download.html).
@@ -277,13 +275,45 @@ To increase accuracy, the easiest way is to increase the timeout. The default is
Decreasing accuracy gives some speed bonus, but my testing found that batch size dramatically changed the speed whereas timeout did, but not so much.
# 🎪 Contributing
# 🎪 Community
Howdy Space Cow-Person 🤠🌌
RustScan is always looking for contributors. Whether that's spelling mistakes or major changes, your help is **wanted** and welcomed here.
Before contributing, read our [code of conduct](https://github.com/RustScan/RustScan/blob/master/CODE_OF_CONDUCT.md).
TL;DR if you abuse members of our community you will be **perma-banned** 🤗
RustScan has 2 major labels for GitHub issues you should look at:
* Good First issue
These are issues for newcomers to open source!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
* Help wanted
These are issues that aren't really for newcomers, but we could still do wiht help!
[https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22](https://github.com/RustScan/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22help+wanted%22)
If you want to, solve the issue or comment on the issue for help.
The flow for contributing to open source software is:
* Fork the repo
* Make changes
* Pull request to the repo
And then comment on the issue that you've done.
RustScan also has some `// TODO`'s in the codebase, which are meant more for the core team but we wouldn't say no to help with these issues.
If you have any feature suggestions or bugs, leave a GitHub issue. We welcome any and all support :D
We communicate over Discord. [Click here](https://discord.gg/GFrQsGy) to join our Discord community!
## Rewarding you
I cannot pay you :-( But, I can place your GitHub profile on the README under `#Contributors` as a thank you! :)
Please read the [contributing.md file](contributing.md)
# 💻 Other Hacking Projects By This Author
## 🧮 Ciphey
Ciphey is an automated decryption tool using artifical intelligence & natural language processing.
[Check it out here!](https://github.com/ciphey/ciphey)
## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-)
-72
View File
@@ -1,72 +0,0 @@
Rust room
# what is rust?
* speed
* saftey
* cargo (pip but for rust)
* Links to the rust book (the documentation for rust is literally an ebook)
# Toolings
# Introduction
* if statements
* functions
* variables
* loops
Some basic questions like "how would u make variable x, how would u make a function named x" and so on
# Expressions
* rust return statements (they're super weird)
* What is an expression?
# Results object
If something can fail in Rust, you **HAVE** to deal with the exception.
FOr example
```python3
# python
f = open("file.txt", 'r')
```
But in Rust, you **cannot** open a file unless you write an exception for if that file does not exist.
In Rust, everything that can fail returns a <return> object. This means that you're never going to encounter an unexpected "file not found" or similar, because everything is accounted for.
# Borrow checker
Variables not in scope are killed. In Python, I think you can do:
```
if y = 6:
x = 3
else:
x = 9
```
But in Rust, the borrow checker will kill X the second the if is over. You cannot create variables inside a scope and use them out fo the scope.
You can however, do this
```
let x = if y == 6 {3} else {9}
```
This is a security feature, the borrow checker stops you from doing silly things with variables -- everything is either in scope or it's killed off.
# Multi-threading
* Rayon
* Turning a for loop into multi-threaded with one word (into_iter -> into_para_iter)
# Async
* Basic async 101
* Making a web server with async rust and how rust ensures saftey with async
# Packaging
* Packaging your rust app
* Okay not security related but it's really cool it's just 1 command `rust publish`
## TODO
* Rust has an official discord (like, the one the Rust team uses to organise their codebase and create new features). I can ask them for their fave blueteam features of Rust :)
* Ask if I'm allowed to include a link to the official discord of Rust. They only have like 2 help channels, the rest of the channels are for organising new features / work on the language itself. It's really cool to be able to see the language evole in Discord, rather than whatever C++ or Python uses (mailing lists I think)
-1
View File
@@ -1 +0,0 @@
nyaaa~~
+94 -86
View File
@@ -11,6 +11,11 @@ use std::process::{exit, Command};
use std::{net::IpAddr, time::Duration};
use structopt::StructOpt;
// Average value for Ubuntu
const DEFAULT_FILE_DESCRIPTORS_LIMIT: rlimit::rlim = 8000;
// Safest batch size based on experimentation
const AVERAGE_BATCH_SIZE: rlimit::rlim = 3000;
#[macro_use]
extern crate log;
@@ -21,7 +26,8 @@ extern crate log;
/// specified server may not be able to handle this many socket connections at once.
struct Opts {
/// The IP address to scan
ip: String,
#[structopt(parse(try_from_str))]
ip: IpAddr,
///Quiet mode. Only output the ports. No Nmap. Useful for grep or outputting to a file.
#[structopt(short, long)]
@@ -32,19 +38,15 @@ struct Opts {
/// it will do every port at the same time. Although, your OS may not
/// support this.
#[structopt(short, long, default_value = "4500")]
batch_size: u64,
batch_size: u32,
/// The timeout in milliseconds before a port is assumed to be closed.
#[structopt(short, long, default_value = "1500")]
timeout: u64,
timeout: u32,
/// Automatically ups the ULIMIT with the value you provided.
#[structopt(short, long)]
ulimit: Option<u64>,
/// IPv6 mode.
#[structopt(short, long)]
ipv6: bool,
ulimit: Option<rlimit::rlim>,
/// The Nmap arguments to run.
/// To use the argument -A, end RustScan's args with '-- -A'.
@@ -61,81 +63,22 @@ fn main() {
env_logger::init();
info!("Starting up");
let mut opts = Opts::from_args();
let opts = Opts::from_args();
info!("Mains() `opts` arguments are {:?}", opts);
let user_nmap_options = if opts.command.is_empty() {
"-A -vvv".to_string()
} else {
opts.command.join(" ")
};
if !opts.quiet {
print_opening();
}
// Updates ulimit when the argument is set
// Automatically ups the ulimit
if opts.ulimit.is_some() {
let limit = opts.ulimit.unwrap();
info!("Automatically upping ulimit");
if !opts.quiet {
println!("Automatically upping ulimit to {}", limit);
}
match setrlimit(Resource::NOFILE, limit, limit) {
Ok(_) => {}
Err(_) => println!("ERROR. Failed to set Ulimit."),
}
}
let (x, _) = getrlimit(Resource::NOFILE).unwrap();
// if maximum limit is lower than batch size
// automatically re-adjust the batch size
if x < opts.batch_size {
if !opts.quiet {
println!("{}", "WARNING: Your file description limit is lower than selected batch size. Please considering upping this (how to is on the README). NOTE: this may be dangerous and may cause harm to sensitive servers. Automatically reducing Batch Size to match your limit, this process isn't harmful but reduces speed.".red());
}
// if the OS supports high file limits like 8000
// but the user selected a batch size higher than this
// reduce to a lower number
// basically, ubuntu is 8000
// but i can only get it to work on < 5k in testing
// 5k is default, so 3000 seems safe
if x > 8000 {
opts.batch_size = 3000
} else {
opts.batch_size = x - 100u64
}
}
// else if the ulimit is higher than batch size
// tell the user they can increase batch size
// if the user set ulimit arg they probably know what they are doing so don't print this
else if x + 2 > opts.batch_size.into() && (opts.ulimit.is_none()) {
if !opts.quiet {
println!(
"Your file description limit is higher than the batch size. You can potentially increase the speed by increasing the batch size, but this may cause harm to sensitive servers. Your limit is {}, try batch size {}.",
x,
x - 1u64
);
}
}
let addr = match opts.ip.parse::<IpAddr>() {
Ok(res) => res,
Err(_) => panic!("Could not parse IP Address"),
};
let ulimit: rlimit::rlim = adjust_ulimit_size(&opts);
let batch_size: u32 = infer_batch_size(&opts, ulimit);
// 65535 + 1 because of 0 indexing
let scanner = Scanner::new(
addr,
opts.ip,
1,
65535,
opts.batch_size.into(),
batch_size,
Duration::from_millis(opts.timeout.into()),
opts.quiet,
);
@@ -171,22 +114,14 @@ fn main() {
exit(1);
}
let nmap_args = if !opts.ipv6 {
format!(
"{} {} {} {} {} {}",
&user_nmap_options, "-vvv", "-Pn", "-p", &ports_str, opts.ip
)
} else {
format!(
"{} {} {} {} {} {} {}",
&user_nmap_options, "-vvv", "-Pn", "-6", "-p", &ports_str, opts.ip
)
};
let addr = opts.ip.to_string();
let user_nmap_args =
shell_words::split(&opts.command.join(" ")).expect("failed to parse nmap arguments");
let nmap_args = build_nmap_arguments(&addr, &ports_str, &user_nmap_args, opts.ip.is_ipv6());
if !opts.quiet {
println!("The Nmap command to be run is {}", &nmap_args);
println!("The Nmap command to be run is {}", &nmap_args.join(" "));
}
let nmap_args = shell_words::split(&nmap_args).expect("failed to parse nmap arguments");
// Runs the nmap command and spawns it as a process.
let mut child = Command::new("nmap")
@@ -211,6 +146,79 @@ fn print_opening() {
println!("{}\n", s.green());
}
fn build_nmap_arguments<'a>(
addr: &'a str,
ports: &'a str,
user_args: &'a Vec<String>,
is_ipv6: bool,
) -> Vec<&'a str> {
let mut arguments: Vec<&str> = user_args.iter().map(AsRef::as_ref).collect();
arguments.push("-A");
arguments.push("-vvv");
if is_ipv6 {
arguments.push("-6");
}
arguments.push("-p");
arguments.push(ports);
arguments.push(addr);
arguments
}
fn adjust_ulimit_size(opts: &Opts) -> rlimit::rlim {
if opts.ulimit.is_some() {
let limit: rlimit::rlim = opts.ulimit.unwrap();
match setrlimit(Resource::NOFILE, limit, limit) {
Ok(_) => {
if !opts.quiet {
println!("\nAutomatically increasing ulimit value to {}.\n", limit);
}
}
Err(_) => println!("{}", "ERROR. Failed to set ulimit value.".red()),
}
}
let (rlim, _) = getrlimit(Resource::NOFILE).unwrap();
rlim
}
fn infer_batch_size(opts: &Opts, ulimit: rlimit::rlim) -> u32 {
let mut batch_size: rlimit::rlim = opts.batch_size.into();
// Adjust the batch size when the ulimit value is lower than the desired batch size
if ulimit < batch_size {
if !opts.quiet {
println!("{}", "WARNING: Your file description limit is lower than the provided batch size. Please considering upping this (instructions in our README). NOTE: this may be dangerous and may cause harm to sensitive servers. Automatically reducing the batch Size to match your system's limit, this process isn't harmful but reduces speed.".red());
}
// When the OS supports high file limits like 8000, but the user
// selected a batch size higher than this we should reduce it to
// a lower number.
if ulimit > DEFAULT_FILE_DESCRIPTORS_LIMIT {
batch_size = AVERAGE_BATCH_SIZE
} else {
batch_size = ulimit - 100
}
}
// When the ulimit is higher than the batch size let the user know that the
// batch size can be increased unless they specified the ulimit themselves.
else if ulimit + 2 > batch_size && (opts.ulimit.is_none()) {
if !opts.quiet {
println!(
"Your file descriptor limit is higher than the batch size. You can potentially increase the speed by increasing the batch size, but this may cause harm to sensitive servers. Your limit is {}, try batch size {}.",
ulimit,
ulimit - 1
);
}
}
batch_size as u32
}
#[cfg(test)]
mod tests {
use super::Scanner;
@@ -229,7 +237,7 @@ mod tests {
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
assert_eq!(1, 1);
}
fn does_it_run_ivp6() {
fn does_it_run_ipv6() {
// Makes sure te program still runs and doesn't panic
let addr = match "::1".parse::<IpAddr>() {
Ok(res) => res,
+7 -8
View File
@@ -15,12 +15,11 @@ use std::{
/// batch_size is how many ports at a time should be scanned
/// Timeout is the time RustScan should wait before declaring a port closed. As datatype Duration.
/// Quiet is whether or not RustScan should print things, or wait until the end to print only open ports.
/// ipv6 is whether or not this scan is an ipv6 scan.
pub struct Scanner {
host: IpAddr,
start: u16,
end: u16,
batch_size: u64,
batch_size: u32,
timeout: Duration,
quiet: bool,
}
@@ -30,7 +29,7 @@ impl Scanner {
host: IpAddr,
start: u16,
end: u16,
batch_size: u64,
batch_size: u32,
timeout: Duration,
quiet: bool,
) -> Self {
@@ -88,9 +87,9 @@ impl Scanner {
/// If no errors occur, it returns the port number in Result to signify the port is open.
/// This function mainly deals with the logic of Results handling.
/// # Example
/// ```rust
///
/// self.scan_port(10:u16)
/// ```
///
/// Note: `self` must contain `self.host`.
async fn scan_port(&self, port: u16) -> io::Result<u16> {
let addr = SocketAddr::new(self.host, port);
@@ -121,15 +120,15 @@ impl Scanner {
/// Performs the connection to the socket with timeout
/// # Example
/// ```rust
///
/// let port: u16 = 80
/// // Host is an IpAddr type
/// let host = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
/// let addr = SocketAddr::new(host, port)
/// self.connect(addr)
/// // returns Result which is either Ok(stream) for port is open, or Er for port is closed.
/// // Timesout after self.timeouts seconds
/// ```
/// // Timeout occurs after self.timeout seconds
///
async fn connect(&self, addr: SocketAddr) -> io::Result<TcpStream> {
let stream =
io::timeout(self.timeout, async move { TcpStream::connect(addr).await }).await?;