Skip to content

Commit

Permalink
new: implemented support for integer range expression
Browse files Browse the repository at this point in the history
  • Loading branch information
evilsocket committed Nov 2, 2023
1 parent e1456cd commit 5d898eb
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/creds/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const DEFAULT_PERMUTATIONS_CHARSET: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJ

lazy_static! {
static ref PERMUTATIONS_PARSER: Regex = Regex::new(r"^#(\d+)-(\d+)(:.+)?$").unwrap();
static ref RANGE_MIN_MAX_PARSER: Regex = Regex::new(r"^\[(\d+)-(\d+)\]$").unwrap();
static ref RANGE_SET_PARSER: Regex = Regex::new(r"^\[(\d+(,\s*\d+)*)?\]$").unwrap();
}

#[derive(Clone, Debug, PartialEq)]
Expand All @@ -25,6 +27,11 @@ pub(crate) enum Expression {
max: usize,
charset: String,
},
Range {
min: usize,
max: usize,
set: Vec<usize>,
},
Glob {
pattern: String,
},
Expand Down Expand Up @@ -53,6 +60,13 @@ impl fmt::Display for Expression {
)
}
Expression::Glob { pattern } => write!(f, "glob {}", pattern),
Expression::Range { min, max, set } => {
if set.is_empty() {
write!(f, "range {} -> {}", min, max)
} else {
write!(f, "range {:?}", set)
}
}
}
}
}
Expand Down Expand Up @@ -107,6 +121,35 @@ pub(crate) fn parse_expression(expr: Option<&String>) -> Expression {
}
};
}
// range expression or constant
'[' => {
return if let Some(captures) = RANGE_MIN_MAX_PARSER.captures(expr) {
// [min-max]
Expression::Range {
min: captures.get(1).unwrap().as_str().parse().unwrap(),
max: captures.get(2).unwrap().as_str().parse().unwrap(),
set: vec![],
}
} else if let Some(captures) = RANGE_SET_PARSER.captures(expr) {
// [n, n, n, ...]
Expression::Range {
min: 0,
max: 0,
set: captures
.get(1)
.unwrap()
.as_str()
.split(',')
.map(|s| s.trim().parse().unwrap())
.collect(),
}
} else {
// constant value casually starting with [
Expression::Constant {
value: expr.to_owned(),
}
};
}
// file name or constant
_ => {
let filepath = Path::new(&expr);
Expand Down Expand Up @@ -182,6 +225,17 @@ mod tests {
)
}

#[test]
fn can_parse_constant_with_bracket() {
let res = parse_expression(Some("[m_n0t_@_range]".to_owned()).as_ref());
assert_eq!(
res,
Expression::Constant {
value: "[m_n0t_@_range]".to_owned()
}
)
}

#[test]
fn can_parse_permutations_with_default_charset() {
let res = parse_expression(Some("#1-3".to_owned()).as_ref());
Expand All @@ -208,6 +262,32 @@ mod tests {
)
}

#[test]
fn can_parse_range_with_min_max() {
let res = parse_expression(Some("[1-3]".to_owned()).as_ref());
assert_eq!(
res,
Expression::Range {
min: 1,
max: 3,
set: vec![],
}
)
}

#[test]
fn can_parse_range_with_set() {
let res = parse_expression(Some("[1,3,4, 5, 6, 7, 8, 12,666]".to_owned()).as_ref());
assert_eq!(
res,
Expression::Range {
min: 0,
max: 0,
set: vec![1, 3, 4, 5, 6, 7, 8, 12, 666],
}
)
}

#[test]
fn can_parse_glob() {
let res = parse_expression(Some("@/etc/*".to_owned()).as_ref());
Expand Down
5 changes: 5 additions & 0 deletions src/creds/iterator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod empty;
mod glob;
mod permutations;
mod permutator;
mod range;
mod wordlist;

pub(crate) trait Iterator: std::iter::Iterator<Item = String> {
Expand All @@ -30,6 +31,10 @@ pub(crate) fn new(expr: Expression) -> Result<Box<dyn Iterator>, Error> {
let it = glob::Glob::new(pattern)?;
Ok(Box::new(it))
}
Expression::Range { min, max, set } => {
let it = range::Range::new(min, max, set)?;
Ok(Box::new(it))
}
}
}

Expand Down
103 changes: 103 additions & 0 deletions src/creds/iterator/range.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use crate::{creds, session::Error};

pub(crate) struct Range {
max: usize,
set: Vec<usize>,
current: usize,
elements: usize,
}

impl Range {
pub fn new(min: usize, max: usize, set: Vec<usize>) -> Result<Self, Error> {
if set.is_empty() {
if min > max {
return Err(
"left side of range expression can't be greater than the right side".to_owned(),
);
}

let elements = max - min + 1;
Ok(Self {
max,
current: min,
elements,
set: vec![],
})
} else {
let elements = set.len();
Ok(Self {
max: 0,
current: 0,
set,
elements,
})
}
}
}

impl creds::Iterator for Range {
fn search_space_size(&self) -> usize {
self.elements
}
}

impl std::iter::Iterator for Range {
type Item = String;

fn next(&mut self) -> Option<Self::Item> {
if self.set.is_empty() {
return if self.current <= self.max {
let ret = self.current;
self.current += 1;
Some(ret.to_string())
} else {
None
};
} else {
return if self.current < self.elements {
let ret = self.set[self.current];
self.current += 1;
Some(ret.to_string())
} else {
None
};
}
}
}

#[cfg(test)]
mod tests {
use crate::creds::{iterator, Expression};

#[test]
fn can_handle_min_max_range() {
let expected = vec!["1", "2", "3", "4", "5"];
let gen = iterator::new(Expression::Range {
min: 1,
max: 5,
set: vec![],
})
.unwrap();
let tot = gen.search_space_size();
let vec: Vec<String> = gen.collect();

assert_eq!(tot, expected.len());
assert_eq!(vec, expected);
}

#[test]
fn can_handle_set_range() {
let expected = vec!["1", "666", "2", "234", "5", "19"];
let gen = iterator::new(Expression::Range {
min: 0,
max: 0,
set: vec![1, 666, 2, 234, 5, 19],
})
.unwrap();
let tot = gen.search_space_size();
let vec: Vec<String> = gen.collect();

assert_eq!(tot, expected.len());
assert_eq!(vec, expected);
}
}

0 comments on commit 5d898eb

Please sign in to comment.