Compare commits

...
24 Commits
Author SHA1 Message Date
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 5d69339cc7 cargo fmt 2020-07-31 11:33:08 +01:00
Brandon d8fd12694c fixed tests 2020-07-31 11:32:02 +01:00
Brandon 7d4084d06c added ipv6 support to nmap command 2020-07-31 11:21:58 +01:00
Brandon 365be75689 Merge branch 'ipv6-support' of github.com:brandonskerritt/RustScan into ipv6-support 2020-07-31 02:11:28 +01:00
Brandon 5ea316c5db ipv6 is now implemented. Just need to do a final cleanup 2020-07-31 02:11:09 +01:00
Brandon b363529045 ipv6 is now implemented. Just need to do a final cleanup 2020-07-31 01:30:35 +01:00
Brandon ed378f7fc8 Either this doesnt work or my internet is broken 2020-07-31 01:17:38 +01:00
Brandon aa3c591016 added logging module 2020-07-30 23:44:48 +01:00
Brandon ef893fdcb8 Update README.md 2020-07-30 12:49:22 +01:00
Brandon b78a8ad0af edited contributing.md 2020-07-30 12:39:54 +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 6d72037974 Code finally compiles 2020-07-30 02:17:17 +01:00
Brandon 66486b2467 scanner.rs now works 2020-07-30 01:46:38 +01:00
Brandon 4b085d97f2 added ipv6 testing 2020-07-29 18:11:57 +01:00
Brandon 3951c25dff end of dya 2020-07-29 01:50:36 +01:00
Brandon 071c437206 sending to smackhack 2020-07-29 00:45:47 +01:00
Brandon 7d351f2025 socketaddr is now ipv4 and ipv6 2020-07-28 23:12:08 +01:00
Brandon 8ce14c5690 Added arguments in structopts for ipv6 2020-07-28 02:23:07 +01:00
Brandon 6cf71a1529 switching branches real quick 2020-07-28 01:07:57 +01:00
10 changed files with 326 additions and 65 deletions

No files matched your search

+1 -1
View File
@@ -1,2 +1,2 @@
todo:
keyword: "TODO"
keyword: "// TODO"
Generated
+85 -1
View File
@@ -1,5 +1,14 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
@@ -162,6 +171,19 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "event-listener"
version = "2.2.1"
@@ -302,6 +324,15 @@ dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
[[package]]
name = "js-sys"
version = "0.3.42"
@@ -448,6 +479,12 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.7"
@@ -463,6 +500,24 @@ version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "regex"
version = "1.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
[[package]]
name = "rlimit"
version = "0.3.0"
@@ -475,11 +530,13 @@ dependencies = [
[[package]]
name = "rustscan"
version = "1.3.0"
version = "1.4.0"
dependencies = [
"async-std",
"colored",
"env_logger",
"futures",
"log",
"rlimit",
"shell-words",
"structopt",
@@ -588,6 +645,15 @@ dependencies = [
"syn",
]
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@@ -597,6 +663,15 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"lazy_static",
]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
@@ -734,6 +809,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
+3 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "rustscan"
version = "1.3.0"
version = "1.4.0"
authors = ["Bee <[email protected]>"]
edition = "2018"
description = "Faster Nmap Scanning with Rust"
@@ -20,6 +20,8 @@ async-std = "1.6.2"
futures = "0.3"
rlimit = "0.3.0"
shell-words = "1.0.0"
log = "0.4.0"
env_logger = "0.7.1"
[package.metadata.deb]
depends = "$auto, nmap"
+2 -1
View File
@@ -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?
+29 -4
View File
@@ -1,6 +1,31 @@
This is my first Rust project! As such, I expect there are many, many bugs involved or things that can be sped up.
Howdy Space Cow-Person 🤠🌌
If you're looking to get involved, we make use of Good First Issues / Help Wanted tags. Click this link to see all the issues we could use help with!
[https://github.com/brandonskerritt/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22](https://github.com/brandonskerritt/RustScan/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
RustScan is always looking for contributors. Whether that's spelling mistakes or major changes, your help is **wanted** and welcomed here.
Please leave issues / pull requests, I'd love to learn more about this amazing language :)
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** with no chance to get unbanned. No warnings either. 🤗
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
## Rewarding you
I cannot pay you :-( But, I can place your GitHub profile on the README under `#Contributors` as a thank you! :)
+72
View File
@@ -0,0 +1,72 @@
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
@@ -0,0 +1 @@
nyaaa~~
-1
View File
@@ -18,4 +18,3 @@ RUN echo "objcopy = { path = \"arm-linux-gnueabihf-objcopy\" }" >> /root/.cargo/
COPY ./entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
1
+60 -17
View File
@@ -8,9 +8,12 @@ use futures::executor::block_on;
use rlimit::Resource;
use rlimit::{getrlimit, setrlimit};
use std::process::{exit, Command};
use std::time::Duration;
use std::{net::IpAddr, time::Duration};
use structopt::StructOpt;
#[macro_use]
extern crate log;
#[derive(StructOpt, Debug)]
#[structopt(name = "rustscan", setting = structopt::clap::AppSettings::TrailingVarArg)]
/// Fast Port Scanner built in Rust.
@@ -39,6 +42,10 @@ struct Opts {
#[structopt(short, long)]
ulimit: Option<u64>,
/// IPv6 mode.
#[structopt(short, long)]
ipv6: bool,
/// The Nmap arguments to run.
/// To use the argument -A, end RustScan's args with '-- -A'.
/// Example: 'rustscan -T 1500 127.0.0.1 -- -A -sC'.
@@ -48,8 +55,14 @@ struct Opts {
}
/// Faster Nmap scanning with Rust
/// If you're looking for the actual scanning, check out the module Scanner.
fn main() {
// logger
env_logger::init();
info!("Starting up");
let mut opts = Opts::from_args();
info!("Mains() `opts` arguments are {:?}", opts);
let user_nmap_options = if opts.command.is_empty() {
"-A -vvv".to_string()
@@ -62,8 +75,11 @@ fn main() {
}
// 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);
@@ -84,8 +100,6 @@ fn main() {
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());
}
// TODO this is a joke please fix
// if the OS supports high file limits like 8000
// but the user selected a batch size higher than this
// reduce to a lower number
@@ -95,13 +109,13 @@ fn main() {
if x > 8000 {
opts.batch_size = 3000
} else {
opts.batch_size = x - 100u64;
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 && (opts.ulimit.is_none()) {
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 {}.",
@@ -110,15 +124,19 @@ fn main() {
);
}
}
// the user has asked to automatically up the ulimit
let addr = match opts.ip.parse::<IpAddr>() {
Ok(res) => res,
Err(_) => panic!("Could not parse IP Address"),
};
// 65535 + 1 because of 0 indexing
let scanner = Scanner::new(
&opts.ip,
addr,
1,
65536,
opts.batch_size,
Duration::from_millis(opts.timeout),
65535,
opts.batch_size.into(),
Duration::from_millis(opts.timeout.into()),
opts.quiet,
);
let scan_result = block_on(scanner.run());
@@ -132,7 +150,7 @@ fn main() {
// if no ports are found, suggest running with less
if nmap_str_ports.is_empty() {
panic!("{} Looks like I didn't find any open ports. This is usually caused by a high batch size.
\n*I used {} threads, consider lowering to {} with {} or a comfortable number lfor your system.
\n*I used {} batch size, consider lowering to {} with {} or a comfortable number for your system.
\n Alternatively, increase the timeout if your ping is high. Rustscan -T 2000 for 2000 second timeout.", "ERROR".red(),
opts.batch_size,
(opts.batch_size / 2).to_string().green(),
@@ -153,10 +171,18 @@ fn main() {
exit(1);
}
let nmap_args = format!(
"{} {} {} {} {} {}",
&user_nmap_options, "-vvv", "-Pn", "-p", &ports_str, opts.ip
);
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
)
};
if !opts.quiet {
println!("The Nmap command to be run is {}", &nmap_args);
}
@@ -171,7 +197,9 @@ fn main() {
child.wait().expect("failed to wait on nmap process");
}
/// Prints the opening title of RustScan
fn print_opening() {
info!("Printing opening");
let s = "
_____ _ _____
| __ \\ | | / ____|
@@ -187,12 +215,27 @@ fn print_opening() {
mod tests {
use super::Scanner;
use async_std::task::block_on;
use std::time::Duration;
use std::{net::IpAddr, time::Duration};
#[test]
fn does_it_run() {
// Makes sure te program still runs and doesn't panic
let scanner = Scanner::new("127.0.0.1", 1, 65536, 1000, Duration::from_millis(10), true);
let addr = match "127.0.0.1".parse::<IpAddr>() {
Ok(res) => res,
Err(_) => panic!("Could not parse IP Address"),
};
let scanner = Scanner::new(addr, 1, 65535, 1000, Duration::from_millis(10), true);
let scan_result = block_on(scanner.run());
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
assert_eq!(1, 1);
}
fn does_it_run_ivp6() {
// Makes sure te program still runs and doesn't panic
let addr = match "::1".parse::<IpAddr>() {
Ok(res) => res,
Err(_) => panic!("Could not parse IP Address"),
};
let scanner = Scanner::new(addr, 1, 65535, 1000, Duration::from_millis(10), true);
let scan_result = block_on(scanner.run());
// if the scan fails, it wouldn't be able to assert_eq! as it panicked!
assert_eq!(1, 1);
+73 -39
View File
@@ -6,13 +6,20 @@ use futures::stream::FuturesUnordered;
use std::time::Duration;
use std::{
io::ErrorKind,
net::{Shutdown, SocketAddr},
net::{IpAddr, Shutdown, SocketAddr},
};
/// The class for the scanner
/// Host is data type IpAddr and is the host address
/// start & end is where the port scan starts and ends
/// 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: String,
start: u64,
end: u64,
host: IpAddr,
start: u16,
end: u16,
batch_size: u64,
timeout: Duration,
quiet: bool,
@@ -20,9 +27,9 @@ pub struct Scanner {
impl Scanner {
pub fn new(
host: &str,
start: u64,
end: u64,
host: IpAddr,
start: u16,
end: u16,
batch_size: u64,
timeout: Duration,
quiet: bool,
@@ -37,9 +44,14 @@ impl Scanner {
}
}
pub async fn run(&self) -> Vec<u64> {
let ports: Vec<u64> = (self.start..self.end).collect();
let mut open_ports: std::vec::Vec<u64> = Vec::new();
/// Runs scan_range with chunk sizes
/// If you want to run RustScan normally, this is the entry point used
/// Returns all open ports as Vec<u16>
pub async fn run(&self) -> Vec<u16> {
let ports: Vec<u16> = (self.start..self.end).collect();
let mut open_ports: std::vec::Vec<u16> = Vec::new();
// TODO change this to port size
// to fix bug when we introduce custom port ranges
for range in ports.chunks(self.batch_size as usize) {
let mut ports = self.scan_range(range).await;
@@ -49,14 +61,15 @@ impl Scanner {
open_ports
}
async fn scan_range(&self, range: &[u64]) -> Vec<u64> {
/// Given a range of ports, scan them all.
/// Returns a vector of open ports.
async fn scan_range(&self, range: &[u16]) -> Vec<u16> {
let mut ftrs = FuturesUnordered::new();
for port in range {
ftrs.push(self.scan_port(port));
ftrs.push(self.scan_port(*port));
}
let mut open_ports: Vec<u64> = Vec::new();
let mut open_ports: Vec<u16> = Vec::new();
while let Some(result) = ftrs.next().await {
match result {
Ok(port) => open_ports.push(port),
@@ -67,39 +80,60 @@ impl Scanner {
open_ports
}
async fn scan_port(&self, port: &u64) -> io::Result<u64> {
let addr = format!("{}:{}", self.host, port);
match addr.parse() {
Ok(sock_addr) => match self.connect(sock_addr).await {
Ok(stream_result) => {
match stream_result.shutdown(Shutdown::Both) {
_ => {}
}
if !self.quiet {
println!("Open {}", port.to_string().purple());
}
Ok(*port)
/// Given a port, scan it.
/// Turns the address into a SocketAddr
/// Deals with the <result> type
/// If it experiences error ErrorKind::Other then too many files are open and it Panics!
/// ese any other error, it returns the error in Result as a string
/// 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);
// println!("{:?}", addr);
match self.connect(addr).await {
Ok(x) => {
// match stream_result.shutdown(Shutdown::Both)
info!("Shutting down stream");
match x.shutdown(Shutdown::Both) {
_ => {}
}
Err(e) => match e.kind() {
ErrorKind::Other => {
eprintln!("{:?}", e); // in case we get too many open files
panic!("Too many open files. Please reduce batch size. The default is 5000. Try -b 2500.");
}
_ => Err(io::Error::new(io::ErrorKind::Other, e.to_string())),
},
},
Err(e) => {
eprintln!("Unable to convert to socket address {:?}", e);
panic!("Unable to convert to socket address");
if !self.quiet {
println!("Open {}", port.to_string().purple());
}
// if connection successful
// shut down stream
// return port
Ok(port)
}
Err(e) => match e.kind() {
ErrorKind::Other => {
panic!("Too many open files. Please reduce batch size. The default is 5000. Try -b 2500.");
}
_ => Err(io::Error::new(io::ErrorKind::Other, e.to_string())),
},
}
}
/// 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
/// ```
async fn connect(&self, addr: SocketAddr) -> io::Result<TcpStream> {
let stream =
io::timeout(self.timeout, async move { TcpStream::connect(addr).await }).await?;
info!("Returning okay from connect");
Ok(stream)
}
}