Skip to content

Commit

Permalink
Merge branch 'main' into 150-feature-imix-platform-information
Browse files Browse the repository at this point in the history
  • Loading branch information
hulto authored Mar 23, 2023
2 parents b04d5fe + 9c63e50 commit a7ef7e4
Show file tree
Hide file tree
Showing 20 changed files with 272 additions and 54 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ build/**
# Credentials
.creds/**
implants/imix/imix-test-config.json

implants/golem/embed_files_golem_prod/*
4 changes: 2 additions & 2 deletions docs/_docs/user-guide/golem.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ You can leverage the power of Eldritch with minimal exposure in the system proce
```bash
git clone [email protected]:KCarretto/realm.git
cd realm/implants/golem
cargo run
cargo run -- -i
# - or -
../target/debug/golem working_dir/tomes/hello_world.tome
../target/debug/golem ../../tests/golem_cli_test/tomes/hello_world.tome
```
1 change: 1 addition & 0 deletions implants/eldritch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ tera = "1.17.1"
gazebo = "0.8.1"
nix = "0.26.1"
eval = "0.4.3"
rust-embed="6.6.0"

[dependencies.windows-sys]
version = "0.45.0"
Expand Down
70 changes: 70 additions & 0 deletions implants/eldritch/src/assets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
mod copy_impl;
mod list_impl;

use derive_more::Display;

use starlark::environment::{Methods, MethodsBuilder, MethodsStatic};
use starlark::values::none::NoneType;
use starlark::values::{StarlarkValue, Value, UnpackValue, ValueLike, ProvidesStaticType};
use starlark::{starlark_type, starlark_simple_value, starlark_module};

use serde::{Serialize,Serializer};
use rust_embed::RustEmbed;

#[cfg(debug_assertions)]
#[derive(RustEmbed)]
#[folder = "../../tests/embedded_files_test"]
pub struct Asset;

#[cfg(not(debug_assertions))]
#[derive(RustEmbed)]
#[folder = "../../implants/golem/embed_files_golem_prod"]
pub struct Asset;


#[derive(Copy, Clone, Debug, PartialEq, Display, ProvidesStaticType)]
#[display(fmt = "AssetsLibrary")]
pub struct AssetsLibrary();
starlark_simple_value!(AssetsLibrary);

impl<'v> StarlarkValue<'v> for AssetsLibrary {
starlark_type!("assets_library");

fn get_methods() -> Option<&'static Methods> {
static RES: MethodsStatic = MethodsStatic::new();
RES.methods(methods)
}
}

impl Serialize for AssetsLibrary {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_none()
}
}

impl<'v> UnpackValue<'v> for AssetsLibrary {
fn expected() -> String {
AssetsLibrary::get_type_value_static().as_str().to_owned()
}

fn unpack_value(value: Value<'v>) -> Option<Self> {
Some(*value.downcast_ref::<AssetsLibrary>().unwrap())
}
}

// This is where all of the "assets.X" impl methods are bound
#[starlark_module]
fn methods(builder: &mut MethodsBuilder) {
fn copy(this: AssetsLibrary, src: String, dest: String) -> anyhow::Result<NoneType> {
if false { println!("Ignore unused this var. _this isn't allowed by starlark. {:?}", this); }
copy_impl::copy(src, dest)?;
Ok(NoneType{})
}
fn list(this: AssetsLibrary) -> anyhow::Result<Vec<String>> {
if false { println!("Ignore unused this var. _this isn't allowed by starlark. {:?}", this); }
list_impl::list()
}
}
41 changes: 41 additions & 0 deletions implants/eldritch/src/assets/copy_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use std::fs;
use anyhow::Result;

pub fn copy(src: String, dst: String) -> Result<()> {
let src_file = match super::Asset::get(src.as_str()) {
Some(local_src_file) => local_src_file.data,
None => return Err(anyhow::anyhow!("Embedded file {src} not found.")),
};

match fs::write(dst, src_file) {
Ok(_) => Ok(()),
Err(local_err) => Err(local_err.into()),
}
}


#[cfg(test)]
mod tests {
use super::*;
use std::io::prelude::*;
use tempfile::NamedTempFile;

#[test]
fn test_embedded_copy() -> anyhow::Result<()>{

// Create files
let mut tmp_file_dst = NamedTempFile::new()?;
let path_dst = String::from(tmp_file_dst.path().to_str().unwrap());

// Run our code
copy("exec_script/hello_word.sh".to_string(), path_dst)?;

// Read
let mut contents = String::new();
tmp_file_dst.read_to_string(&mut contents)?;
// Compare
assert!(contents.contains("hello from an embedded shell script"));

Ok(())
}
}
25 changes: 25 additions & 0 deletions implants/eldritch/src/assets/list_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use anyhow::Result;

pub fn list() -> Result<Vec<String>> {
let mut res: Vec<String> = Vec::new();
for file_path in super::Asset::iter() {
res.push(file_path.to_string());
}

Ok(res)
}


#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_assets_list() -> anyhow::Result<()>{
let res_all_embedded_files = list()?;

assert_eq!(res_all_embedded_files, ["exec_script/hello_word.sh", "exec_script/main.eld", "print/main.eld"]);

Ok(())
}
}
24 changes: 8 additions & 16 deletions implants/eldritch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod file;
pub mod process;
pub mod sys;
pub mod pivot;
pub mod assets;

use serde_json::Map;
use starlark::collections::SmallMap;
Expand All @@ -15,13 +16,17 @@ use starlark::values::{Value, AllocValue};
use file::FileLibrary;
use process::ProcessLibrary;
use sys::SysLibrary;
use assets::AssetsLibrary;
use pivot::PivotLibrary;

pub fn get_eldritch() -> anyhow::Result<Globals> {
#[starlark_module]
fn eldritch(builder: &mut GlobalsBuilder) {
const file: FileLibrary = FileLibrary();
const process: ProcessLibrary = ProcessLibrary();
const sys: SysLibrary = SysLibrary();
const pivot: PivotLibrary = PivotLibrary();
const assets: AssetsLibrary = AssetsLibrary();
}

let globals = GlobalsBuilder::extended().with(eldritch).build();
Expand Down Expand Up @@ -114,35 +119,22 @@ mod tests {
use std::thread;

use super::*;
use starlark::environment::{GlobalsBuilder};
use starlark::{starlark_module};
use starlark::assert::Assert;
use tempfile::NamedTempFile;

use super::file::FileLibrary;
use super::process::ProcessLibrary;
use super::sys::SysLibrary;
use super::pivot::PivotLibrary;

// just checks dir...
#[test]
fn test_library_bindings() {
#[starlark_module]
fn globals(builder: &mut GlobalsBuilder) {
const file: FileLibrary = FileLibrary();
const process: ProcessLibrary = ProcessLibrary();
const sys: SysLibrary = SysLibrary();
const pivot: PivotLibrary = PivotLibrary();
}

let globals = get_eldritch().unwrap();
let mut a = Assert::new();
a.globals_add(globals);
a.globals(globals);
a.all_true(
r#"
dir(file) == ["append", "compress", "copy", "download", "exists", "hash", "is_dir", "is_file", "mkdir", "read", "remove", "rename", "replace", "replace_all", "template", "timestomp", "write"]
dir(process) == ["kill", "list", "name"]
dir(sys) == ["dll_inject", "exec", "is_linux", "is_macos", "is_windows", "shell"]
dir(pivot) == ["arp_scan", "bind_proxy", "ncat", "port_forward", "port_scan", "smb_exec", "ssh_exec", "ssh_password_spray"]
dir(assets) == ["copy","list"]
"#,
);
}
Expand Down
1 change: 1 addition & 0 deletions implants/golem/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ gazebo.version = "0.8.1"
itertools = "0.10"
thiserror = "1.0.30"
lsp-types = "0.93.0"
rust-embed = { version = "6.6.0" }

[dev-dependencies]
assert_cmd = "2.0.6"
Expand Down
118 changes: 91 additions & 27 deletions implants/golem/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ extern crate golem;
extern crate eldritch;

use clap::{Command, Arg};
use rust_embed::RustEmbed;
use std::fs;
use std::process;
use std::thread;
Expand All @@ -10,13 +11,65 @@ use eldritch::{eldritch_run};

mod inter;

#[cfg(debug_assertions)]
#[derive(RustEmbed)]
#[folder = "../../tests/embedded_files_test"]
pub struct Asset;

#[cfg(not(debug_assertions))]
#[derive(RustEmbed)]
#[folder = "../../implants/golem/embed_files_golem_prod"]
pub struct Asset;


async fn execute_tomes_in_parallel(tome_name_and_content: Vec<(String, String)>) -> anyhow::Result<(i32, Vec<String>)> {
// Queue async tasks
let mut all_tome_futures: Vec<(String, _)> = vec![];
for tome_data in tome_name_and_content {
let tmp_row = (
tome_data.0.clone().to_string(),
thread::spawn(|| { eldritch_run(tome_data.0, tome_data.1, None) })
);
all_tome_futures.push(tmp_row)
}

let mut error_code = 0;
let mut result: Vec<String> = Vec::new();
for tome_task in all_tome_futures {
let tome_name: String = tome_task.0;
// Join our
let tome_result_thread_join = match tome_task.1.join() {
Ok(local_thread_join_res) => local_thread_join_res,
Err(_) => {
error_code = 1;
Err(anyhow::anyhow!("An error occured waiting for the tome thread to complete while executing {tome_name}."))
},
};

match tome_result_thread_join {
Ok(local_tome_result) => result.push(local_tome_result),
Err(task_error) => {
error_code = 1;
eprintln!("[TASK ERROR] {tome_name}: {task_error}");
}
}
}
Ok((error_code, result))
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let matches = Command::new("golem")
.arg(Arg::with_name("INPUT")
.help("Set the tomes to run")
.multiple_occurrences(true)
.required(false)
)
.arg(Arg::with_name("interactive")
.help("Run the interactive REPL")
.short('i')
.multiple_occurrences(false)
.required(false)
).get_matches();

if matches.contains_id("INPUT") {
Expand All @@ -25,44 +78,55 @@ async fn main() -> anyhow::Result<()> {
.unwrap()
.unwrap();


// Queue async tasks
let mut all_tome_futures: Vec<(String, _)> = vec![];
let mut tome_files_and_content: Vec< (String, String) > = Vec::new();
for tome in tome_files {
let tome_path = tome.to_string().clone();
let tome_contents = fs::read_to_string(tome_path.clone())?;
let tmp_row = (tome.to_string(), thread::spawn(|| { eldritch_run(tome_path, tome_contents, None) }));
all_tome_futures.push(tmp_row)
tome_files_and_content.push( (tome_path, tome_contents) )
}


let mut error_code = 0;
let mut result: Vec<String> = Vec::new();
for tome_task in all_tome_futures {
let tome_name: String = tome_task.0;
// Join our
let tome_result_thread_join = match tome_task.1.join() {
Ok(local_thread_join_res) => local_thread_join_res,
Err(_) => {
error_code = 1;
Err(anyhow::anyhow!("An error occured waiting for the tome thread to complete while executing {tome_name}."))
},
let (error_code, result) = execute_tomes_in_parallel(tome_files_and_content).await?;
if result.len() > 0 {
println!("{:?}", result);
}
process::exit(error_code);
} else if matches.contains_id("interactive") {
inter::interactive_main()?;
} else {
let mut tome_files_and_content: Vec< (String, String) > = Vec::new();
for embedded_file_path in Asset::iter() {
let filename = match embedded_file_path.split(r#"/"#).last() {
Some(local_filename) => local_filename,
None => "",
};

match tome_result_thread_join {
Ok(local_tome_result) => result.push(local_tome_result),
Err(task_error) => {
error_code = 1;
eprintln!("[TASK ERROR] {tome_name}: {task_error}");
}
println!("{}", embedded_file_path);
if filename == "main.eld" {
let tome_path = embedded_file_path.to_string().clone();
let tome_contents_extraction_result = match Asset::get(embedded_file_path.as_ref()) {
Some(local_tome_content) => String::from_utf8(local_tome_content.data.to_vec()),
None => {
eprint!("Failed to extract eldritch script as string");
Ok("".to_string())
},
};

let tome_contents = match tome_contents_extraction_result {
Ok(local_tome_contents) => local_tome_contents,
Err(utf8_error) => {
eprint!("Failed to extract eldritch script as string {utf8_error}");
"".to_string()
},
};
tome_files_and_content.push( (tome_path, tome_contents) )
}
}

}
let (error_code, result) = execute_tomes_in_parallel(tome_files_and_content).await?;
if result.len() > 0 {
println!("{:?}", result);
}
process::exit(error_code);
} else {
inter::interactive_main()?;
}

Ok(())
}
Loading

0 comments on commit a7ef7e4

Please sign in to comment.