Skip to content

Commit d09bfeb

Browse files
authored
Merge pull request #242 from bergabman/scripts
Scripting Engine Implementation
2 parents 03877d3 + 4614e6b commit d09bfeb

File tree

11 files changed

+578
-74
lines changed

11 files changed

+578
-74
lines changed

Cargo.lock

Lines changed: 57 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ serde_derive = "1.0.116"
3636
cidr-utils = "0.5.0"
3737
itertools = "0.9.0"
3838
trust-dns-resolver = { version = "0.19.5", features = ["dns-over-rustls"] }
39+
anyhow = "1.0.33"
40+
subprocess = "0.2.6"
41+
text_placeholder = { version = "0.4", features = ["struct_context"] }
3942

4043
[dev-dependencies]
4144
wait-timeout = "0.2"

fixtures/test_rustscan_scripts.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Test/Example ScriptConfig file
2+
3+
# Tags to filter on scripts. Only scripts containing all these tags will run.
4+
tags = ["core_approved", "example"]
5+
6+
# If it's present then only those scripts will run which has a tag ports = "80". Not yet implemented.
7+
#
8+
# ex.:
9+
# ports = [80]
10+
# ports = [80,81,8080]
11+
ports = [80]
12+
13+
# Only this developer(s) scripts to run. Not yet implemented.
14+
developer = ["example"]

fixtures/test_script.pl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/perl
2+
#tags = ["core_approved", "example",]
3+
#developer = [ "example", "https://example.org" ]
4+
#ports_separator = ","
5+
#call_format = "perl {{script}} {{ip}} {{port}}"
6+
7+
# Sriptfile parser stops at the first blank line with parsing.
8+
# This script will run itself as an argument with the system installed perl interpreter, ports will be concatenated with "," .
9+
# Unused field: trigger_port = "80"
10+
# get total arg passed to this script
11+
my $total = $#ARGV + 1;
12+
my $counter = 1;
13+
14+
# get script name
15+
my $scriptname = $0;
16+
17+
print "Total args passed to $scriptname : $total\n";
18+
19+
# Use loop to print all args stored in an array called @ARGV
20+
foreach my $a(@ARGV) {
21+
print "Arg # $counter : $a\n";
22+
$counter++;
23+
}

fixtures/test_script.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/python3
2+
#tags = ["core_approved", "example",]
3+
#developer = [ "example", "https://example.org" ]
4+
#trigger_port = "80"
5+
#call_format = "python3 {{script}} {{ip}} {{port}}"
6+
7+
# Sriptfile parser stops at the first blank line with parsing.
8+
# This script will run itself as an argument with the system installed python interpreter, only scanning port 80.
9+
# Unused filed: ports_separator = ","
10+
11+
import sys
12+
13+
print('Python script ran with arguments', str(sys.argv))

fixtures/test_script.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
#tags = ["core_approved", "example",]
3+
#developer = [ "example", "https://example.org" ]
4+
#ports_separator = ","
5+
#call_format = "bash {{script}} {{ip}} {{port}}"
6+
7+
# Sriptfile parser stops at the first blank line with parsing.
8+
# This script will run itself as an argument with the system installed bash interpreter, scanning all ports concatenated with "," .
9+
# Unused filed: trigger_port = "80"
10+
11+
# print all arguments passed to the script
12+
echo $@

fixtures/test_script.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!intentional_blank_line
2+
#tags = ["core_approved", "example"]
3+
#developer = [ "example", "https://example.org" ]
4+
#ports_separator = ","
5+
#call_format = "nmap -vvv -p {{port}} {{ip}}"
6+
7+
# Sriptfile parser stops at the first blank line with parsing.
8+
# This script will run the system installed nmap, ports will be concatenated with "," .
9+
# Unused field: trigger_port = "80"

src/input.rs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use serde_derive::Deserialize;
22
use std::collections::HashMap;
33
use std::fs;
4-
54
use structopt::{clap::arg_enum, StructOpt};
65

76
const LOWEST_PORT_NUMBER: u16 = 1;
@@ -18,6 +17,19 @@ arg_enum! {
1817
}
1918
}
2019

20+
arg_enum! {
21+
/// Represents the scripts variant.
22+
/// - none will avoid running any script, only portscan results will be shown.
23+
/// - default will run the default embedded nmap script, that's part of RustScan since the beginning.
24+
/// - custom will read the ScriptConfig file and the available scripts in the predefined folders
25+
#[derive(Deserialize, Debug, StructOpt, Clone, PartialEq, Copy)]
26+
pub enum ScriptsRequired {
27+
None,
28+
Default,
29+
Custom,
30+
}
31+
}
32+
2133
/// Represents the range of ports to be scanned.
2234
#[derive(Deserialize, Debug, Clone, PartialEq)]
2335
pub struct PortRange {
@@ -49,7 +61,7 @@ fn parse_range(input: &str) -> Result<PortRange, String> {
4961
}
5062
}
5163

52-
#[derive(StructOpt, Debug)]
64+
#[derive(StructOpt, Debug, Clone)]
5365
#[structopt(name = "rustscan", setting = structopt::clap::AppSettings::TrailingVarArg)]
5466
/// Fast Port Scanner built in Rust.
5567
/// WARNING Do not use this program against sensitive infrastructure since the
@@ -81,10 +93,6 @@ pub struct Opts {
8193
#[structopt(long)]
8294
pub accessible: bool,
8395

84-
/// Turns off Nmap.
85-
#[structopt(long)]
86-
pub no_nmap: bool,
87-
8896
/// The batch size for port scanning, it increases or slows the speed of
8997
/// scanning. Depends on the open file limit of your OS. If you do 65535
9098
/// it will do every port at the same time. Although, your OS may not
@@ -111,17 +119,21 @@ pub struct Opts {
111119
#[structopt(long, possible_values = &ScanOrder::variants(), case_insensitive = true, default_value = "serial")]
112120
pub scan_order: ScanOrder,
113121

114-
/// The Nmap arguments to run.
122+
/// Level of scripting required for the run.
123+
#[structopt(long, possible_values = &ScriptsRequired::variants(), case_insensitive = true, default_value = "default")]
124+
pub scripts: ScriptsRequired,
125+
126+
/// Use the top 1000 ports.
127+
#[structopt(long)]
128+
pub top: bool,
129+
130+
/// The Script arguments to run.
115131
/// To use the argument -A, end RustScan's args with '-- -A'.
116132
/// Example: 'rustscan -T 1500 127.0.0.1 -- -A -sC'.
117133
/// This command adds -Pn -vvv -p $PORTS automatically to nmap.
118134
/// For things like --script '(safe and vuln)' enclose it in quotations marks \"'(safe and vuln)'\"")
119135
#[structopt(last = true)]
120136
pub command: Vec<String>,
121-
122-
/// Use the top 1000 ports.
123-
#[structopt(long)]
124-
pub top: bool,
125137
}
126138

127139
#[cfg(not(tarpaulin_include))]
@@ -160,7 +172,8 @@ impl Opts {
160172
}
161173

162174
merge_required!(
163-
addresses, greppable, accessible, batch_size, timeout, tries, scan_order, command
175+
addresses, greppable, accessible, batch_size, timeout, tries, scan_order, scripts,
176+
command
164177
);
165178
}
166179

@@ -204,10 +217,10 @@ pub struct Config {
204217
batch_size: Option<u16>,
205218
timeout: Option<u32>,
206219
tries: Option<u8>,
207-
no_nmap: Option<bool>,
208220
ulimit: Option<rlimit::RawRlim>,
209221
scan_order: Option<ScanOrder>,
210222
command: Option<Vec<String>>,
223+
scripts: Option<ScriptsRequired>,
211224
}
212225

213226
#[cfg(not(tarpaulin_include))]
@@ -251,7 +264,7 @@ impl Config {
251264

252265
#[cfg(test)]
253266
mod tests {
254-
use super::{Config, Opts, PortRange, ScanOrder};
267+
use super::{Config, Opts, PortRange, ScanOrder, ScriptsRequired};
255268
impl Config {
256269
fn default() -> Self {
257270
Self {
@@ -263,10 +276,10 @@ mod tests {
263276
timeout: Some(1_000),
264277
tries: Some(1),
265278
ulimit: None,
266-
no_nmap: Some(false),
267279
command: Some(vec!["-A".to_owned()]),
268280
accessible: Some(true),
269281
scan_order: Some(ScanOrder::Random),
282+
scripts: None,
270283
}
271284
}
272285
}
@@ -284,10 +297,10 @@ mod tests {
284297
ulimit: None,
285298
command: vec![],
286299
accessible: false,
287-
no_nmap: false,
288300
scan_order: ScanOrder::Serial,
289301
no_config: true,
290302
top: false,
303+
scripts: ScriptsRequired::Default,
291304
}
292305
}
293306
}
@@ -320,6 +333,7 @@ mod tests {
320333
assert_eq!(opts.command, config.command.unwrap());
321334
assert_eq!(opts.accessible, config.accessible.unwrap());
322335
assert_eq!(opts.scan_order, config.scan_order.unwrap());
336+
assert_eq!(opts.scripts, ScriptsRequired::Default)
323337
}
324338

325339
#[test]

0 commit comments

Comments
 (0)