diff --git a/docs/_docs/dev-guide/eldritch.md b/docs/_docs/dev-guide/eldritch.md index c29e4b4ad..c8921dce4 100644 --- a/docs/_docs/dev-guide/eldritch.md +++ b/docs/_docs/dev-guide/eldritch.md @@ -40,6 +40,7 @@ Currently Eldritch has eight libraries your function can be bound to: * `file`: Is used for any on disk file processing. * `pivot`: Is used to migrate to identify, and migrate between systems. The pivot library is also responsible for facilitating connectivity within an environment. * `process`: Is used to manage running processes on a system. +* `regex`: Is used to preform regex operations on strings. * `report`: Is used to report structured data to the caller of the eldritch environment (e.g. to the c2). * `sys`: Is used to check system specific configurations and start new processes. * `time`: Is used for obtaining and formatting time or adding delays into code. diff --git a/docs/_docs/user-guide/eldritch.md b/docs/_docs/user-guide/eldritch.md index 48d0b7c29..11f685df7 100644 --- a/docs/_docs/user-guide/eldritch.md +++ b/docs/_docs/user-guide/eldritch.md @@ -357,7 +357,8 @@ The file.remove method deletes a file or directory (and it's contents) sp ### file.replace `file.replace(path: str, pattern: str, value: str) -> None` -The file.replace method is very cool, and will be even cooler when Nick documents it. + +Unimplemented. ### file.replace_all @@ -378,7 +379,7 @@ The `args` dictionary currently supports values of: `int`, `str`, and `List`. `file.timestomp(src: str, dst: str) -> None` -The file.timestomp method is very cool, and will be even cooler when Nick documents it. +Unimplemented. ### file.write @@ -389,7 +390,7 @@ If a file or directory already exists at this path, the method will fail. ### file.find -`file.find(path: str, name: Option, file_type: Option, permissions: Option, modified_time: Option, create_time: Option) -> Vec` +`file.find(path: str, name: Option, file_type: Option, permissions: Option, modified_time: Option, create_time: Option) -> List` The file.find method finds all files matching the used parameters. Returns file path for all matching items. @@ -613,7 +614,7 @@ The process.name method returns the name of the process from it's given p ### process.netstat -`process.netstat() -> Vec` +`process.netstat() -> List` The process.netstat method returns all information on TCP, UDP, and Unix sockets on the system. Will also return PID and Process Name of attached process, if one exists. @@ -636,6 +637,36 @@ The process.netstat method returns all information on TCP, UDP, and Unix --- +## Regex + +The regex library is designed to enable basic regex operations on strings. + +### regex.match_all + +`regex.match_all(haystack: str, pattern: str) -> List` + +Unimplemented. + +### regex.match + +`regex.match(haystack: str, pattern: str) -> str` + +Unimplemented. + +### regex.replace_all + +`regex.replace_all(haystack: str, pattern: str, value: string) -> None` + +Unimplemented. + +### regex.replace + +`regex.replace(haystack: str, pattern: str, value: string) -> None` + +Unimplemented. + +--- + ## Report The report library is designed to enable reporting structured data to Tavern. It's API is still in the active development phase, so **future versions of Eldritch may break tomes that rely on this API**. diff --git a/implants/lib/eldritch/src/lib.rs b/implants/lib/eldritch/src/lib.rs index a1181246e..122e9380f 100644 --- a/implants/lib/eldritch/src/lib.rs +++ b/implants/lib/eldritch/src/lib.rs @@ -3,6 +3,7 @@ pub mod crypto; pub mod file; pub mod pivot; pub mod process; +pub mod regex; mod report; pub mod runtime; pub mod sys; diff --git a/implants/lib/eldritch/src/regex/match_all_impl.rs b/implants/lib/eldritch/src/regex/match_all_impl.rs new file mode 100644 index 000000000..a544c17ae --- /dev/null +++ b/implants/lib/eldritch/src/regex/match_all_impl.rs @@ -0,0 +1,10 @@ +use anyhow::Result; + +pub fn match_all(_haystack: String, _pattern: String) -> Result> { + unimplemented!("Method unimplemented") +} + +#[cfg(test)] +mod tests { + // TODO: Write Tests After Implementing the Function! +} diff --git a/implants/lib/eldritch/src/regex/match_impl.rs b/implants/lib/eldritch/src/regex/match_impl.rs new file mode 100644 index 000000000..547107b8b --- /dev/null +++ b/implants/lib/eldritch/src/regex/match_impl.rs @@ -0,0 +1,10 @@ +use anyhow::Result; + +pub fn r#match(_haystack: String, _pattern: String) -> Result { + unimplemented!("Method unimplemented") +} + +#[cfg(test)] +mod tests { + // TODO: Write Tests After Implementing the Function! +} diff --git a/implants/lib/eldritch/src/regex/mod.rs b/implants/lib/eldritch/src/regex/mod.rs new file mode 100644 index 000000000..f9e622f06 --- /dev/null +++ b/implants/lib/eldritch/src/regex/mod.rs @@ -0,0 +1,46 @@ +mod match_all_impl; +mod match_impl; +mod replace_all_impl; +mod replace_impl; + +use starlark::{ + environment::MethodsBuilder, + starlark_module, + values::{none::NoneType, starlark_value}, +}; + +/* + * Define our library for this module. + */ +crate::eldritch_lib!(RegexLibrary, "regex_library"); + +/* + * Below, we define starlark wrappers for all of our library methods. + * The functions must be defined here to be present on our library. + */ +#[starlark_module] +#[rustfmt::skip] +#[allow(clippy::needless_lifetimes, clippy::type_complexity, clippy::too_many_arguments)] +fn methods(builder: &mut MethodsBuilder) { + #[allow(unused_variables)] + fn replace_all<'v>(this: &RegexLibrary, haystack: String, pattern: String, text: String) -> anyhow::Result { + replace_all_impl::replace_all(haystack, pattern, text)?; + Ok(NoneType{}) + } + + #[allow(unused_variables)] + fn replace<'v>(this: &RegexLibrary, haystack: String, pattern: String, text: String) -> anyhow::Result { + replace_impl::replace(haystack, pattern, text)?; + Ok(NoneType{}) + } + + #[allow(unused_variables)] + fn match_all<'v>(this: &RegexLibrary, haystack: String, pattern: String) -> anyhow::Result> { + match_all_impl::match_all(haystack, pattern) + } + + #[allow(unused_variables)] + fn r#match<'v>(this: &RegexLibrary, haystack: String, pattern: String) -> anyhow::Result { + match_impl::r#match(haystack, pattern) + } +} diff --git a/implants/lib/eldritch/src/regex/replace_all_impl.rs b/implants/lib/eldritch/src/regex/replace_all_impl.rs new file mode 100644 index 000000000..4e724ee4e --- /dev/null +++ b/implants/lib/eldritch/src/regex/replace_all_impl.rs @@ -0,0 +1,10 @@ +use anyhow::Result; + +pub fn replace_all(_haystack: String, _pattern: String, _value: String) -> Result<()> { + unimplemented!("Method unimplemented") +} + +#[cfg(test)] +mod tests { + // TODO: Write Tests After Implementing the Function! +} diff --git a/implants/lib/eldritch/src/regex/replace_impl.rs b/implants/lib/eldritch/src/regex/replace_impl.rs new file mode 100644 index 000000000..e01ef66cf --- /dev/null +++ b/implants/lib/eldritch/src/regex/replace_impl.rs @@ -0,0 +1,10 @@ +use anyhow::Result; + +pub fn replace(_haystack: String, _pattern: String, _value: String) -> Result<()> { + unimplemented!("Method unimplemented") +} + +#[cfg(test)] +mod tests { + // TODO: Write Tests After Implementing the Function! +} diff --git a/implants/lib/eldritch/src/runtime/eval.rs b/implants/lib/eldritch/src/runtime/eval.rs index d53087522..f9cb4a750 100644 --- a/implants/lib/eldritch/src/runtime/eval.rs +++ b/implants/lib/eldritch/src/runtime/eval.rs @@ -5,6 +5,7 @@ use crate::{ file::FileLibrary, pivot::PivotLibrary, process::ProcessLibrary, + regex::RegexLibrary, report::ReportLibrary, runtime::{ messages::{reduce, Message, ReportErrorMessage, ReportFinishMessage, ReportStartMessage}, @@ -157,6 +158,7 @@ impl Runtime { const crypto: CryptoLibrary = CryptoLibrary; const time: TimeLibrary = TimeLibrary; const report: ReportLibrary = ReportLibrary; + const regex: RegexLibrary = RegexLibrary; } GlobalsBuilder::extended_by(&[ diff --git a/implants/lib/eldritch/src/runtime/mod.rs b/implants/lib/eldritch/src/runtime/mod.rs index d470c8949..221866dbd 100644 --- a/implants/lib/eldritch/src/runtime/mod.rs +++ b/implants/lib/eldritch/src/runtime/mod.rs @@ -161,6 +161,16 @@ mod tests { want_text: String::from(r#"["file", "process_list", "ssh_key", "user_password"]"#), want_error: None, }, + regex_bindings: TestCase { + id: 123, + tome: Tome { + eldritch: String::from("print(dir(regex))"), + parameters: HashMap::new(), + file_names: Vec::new(), + }, + want_text: String::from(r#"["match", "match_all", "replace", "replace_all"]"#), + want_error: None, + }, } #[tokio::test(flavor = "multi_thread", worker_threads = 128)]