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)]