From 227e6a2b0ad0983c0e81105bd569fdb83ed31fb2 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 29 Nov 2025 20:25:06 +0000 Subject: [PATCH 1/3] Docs updates --- .../{download_test.tome => download_test.eldritch} | 0 .../{eldritch_test.tome => eldritch_test.eldritch} | 0 .../{hello_world.tome => hello_world.eldritch} | 0 .../{syntax_fail.tome => syntax_fail.eldritch} | 0 docs/_docs/user-guide/getting-started.md | 8 +++++++- docs/_docs/user-guide/golem.md | 9 ++++++--- docs/_docs/user-guide/imix.md | 3 +++ implants/golem/tests/cli.rs | 10 +++++----- 8 files changed, 21 insertions(+), 9 deletions(-) rename bin/golem_cli_test/{download_test.tome => download_test.eldritch} (100%) rename bin/golem_cli_test/{eldritch_test.tome => eldritch_test.eldritch} (100%) rename bin/golem_cli_test/{hello_world.tome => hello_world.eldritch} (100%) rename bin/golem_cli_test/{syntax_fail.tome => syntax_fail.eldritch} (100%) diff --git a/bin/golem_cli_test/download_test.tome b/bin/golem_cli_test/download_test.eldritch similarity index 100% rename from bin/golem_cli_test/download_test.tome rename to bin/golem_cli_test/download_test.eldritch diff --git a/bin/golem_cli_test/eldritch_test.tome b/bin/golem_cli_test/eldritch_test.eldritch similarity index 100% rename from bin/golem_cli_test/eldritch_test.tome rename to bin/golem_cli_test/eldritch_test.eldritch diff --git a/bin/golem_cli_test/hello_world.tome b/bin/golem_cli_test/hello_world.eldritch similarity index 100% rename from bin/golem_cli_test/hello_world.tome rename to bin/golem_cli_test/hello_world.eldritch diff --git a/bin/golem_cli_test/syntax_fail.tome b/bin/golem_cli_test/syntax_fail.eldritch similarity index 100% rename from bin/golem_cli_test/syntax_fail.tome rename to bin/golem_cli_test/syntax_fail.eldritch diff --git a/docs/_docs/user-guide/getting-started.md b/docs/_docs/user-guide/getting-started.md index 22b93b17a..eaa1cbd77 100644 --- a/docs/_docs/user-guide/getting-started.md +++ b/docs/_docs/user-guide/getting-started.md @@ -16,6 +16,7 @@ git clone https://github.com/spellshift/realm && cd ./realm go run ./tavern # Start Agent +export IMIX_SERVER_PUBKEY="$(curl http://localhost:8000/status | jq -r '.Pubkey')" cd implants/imix && cargo run ``` @@ -51,7 +52,12 @@ The warnings you see here indicate that there are settings recommended for produ ```bash # Assumes you have already cloned the repository and are in the 'realm' directory -cd ./implants/imix && cargo run +cd ./implants/imix + +# Set the server pubkey this assumes you've already started a local tavern instance +export IMIX_SERVER_PUBKEY="$(curl http://localhost:8000/status | jq -r '.Pubkey')" + +cargo run ``` ![starting-imix](/assets/img/user-guide/getting-started/starting-imix.png) diff --git a/docs/_docs/user-guide/golem.md b/docs/_docs/user-guide/golem.md index 7f9a55d4e..a2a6bf65f 100644 --- a/docs/_docs/user-guide/golem.md +++ b/docs/_docs/user-guide/golem.md @@ -18,10 +18,13 @@ You can leverage the power of Eldritch with minimal exposure in the system proce ```bash git clone git@github.com:spellshift/realm.git cd realm/implants/golem + +# Launch and interactive REPL cargo run -- -i -# - or - + +# Or run a tome on disk cargo build --release && \ - ../target/debug/golem ../../tests/golem_cli_test/tomes/hello_world.tome + ../target/release/golem ../../bin/golem_cli_test/hello_world.eldritch ``` ## Creating and testing tomes @@ -31,7 +34,7 @@ Golem operates in three different modes: - Interactive `-i` - With embedded tomes _no args_ -- On a specific tome `/path/to/tome/eldritch.main` +- On a specific tome `/path/to/tome/main.eldritch` In this guide we'll leverage the last one. diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index b261645e2..22b30853d 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -13,6 +13,9 @@ Imix is an offensive security implant designed for stealthy communication and ad Imix has compile-time configuration, that may be specified using environment variables during `cargo build`. +**We strongly recommend building agents inside the provided devcontainer `.devcontainer`** +Building in the dev container limits variables that might cause issues and is the most tested way to compile. + | Env Var | Description | Default | Required | | ------- | ----------- | ------- | -------- | | IMIX_CALLBACK_URI | URI for initial callbacks (must specify a scheme, e.g. `http://`) | `http://127.0.0.1:8000` | No | diff --git a/implants/golem/tests/cli.rs b/implants/golem/tests/cli.rs index 095e2583a..4a15f9363 100644 --- a/implants/golem/tests/cli.rs +++ b/implants/golem/tests/cli.rs @@ -10,7 +10,7 @@ const GOLEM_CLI_TEST_DIR: &str = "../../bin/golem_cli_test/"; #[test] fn test_golem_main_file_not_found() -> anyhow::Result<()> { let mut cmd = Command::new(cargo_bin!("golem")); - cmd.arg("nonexistentdir/run.tome"); + cmd.arg("nonexistentdir/run.eldritch"); #[cfg(target_os = "linux")] cmd.assert() .failure() @@ -27,7 +27,7 @@ fn test_golem_main_file_not_found() -> anyhow::Result<()> { fn test_golem_main_syntax_fail() -> anyhow::Result<()> { let mut cmd = Command::new(cargo_bin!("golem")); - cmd.arg(format!("{GOLEM_CLI_TEST_DIR}syntax_fail.tome")); + cmd.arg(format!("{GOLEM_CLI_TEST_DIR}syntax_fail.eldritch")); cmd.assert().failure().stderr(predicate::str::contains( r#"Parse error: unexpected string literal"#.to_string(), )); @@ -39,7 +39,7 @@ fn test_golem_main_syntax_fail() -> anyhow::Result<()> { fn test_golem_main_basic_non_interactive() -> anyhow::Result<()> { let mut cmd = Command::new(cargo_bin!("golem")); - cmd.arg(format!("{GOLEM_CLI_TEST_DIR}hello_world.tome")); + cmd.arg(format!("{GOLEM_CLI_TEST_DIR}hello_world.eldritch")); cmd.assert() .success() .stdout(predicate::str::contains(r#"HELLO"#)); @@ -51,7 +51,7 @@ fn test_golem_main_basic_non_interactive() -> anyhow::Result<()> { fn test_golem_main_basic_eldritch_non_interactive() -> anyhow::Result<()> { let mut cmd = Command::new(cargo_bin!("golem")); - cmd.arg(format!("{GOLEM_CLI_TEST_DIR}eldritch_test.tome")); + cmd.arg(format!("{GOLEM_CLI_TEST_DIR}eldritch_test.eldritch")); cmd.assert() .success() .stdout(predicate::str::contains(r#"["append", "compress""#)); @@ -63,7 +63,7 @@ fn test_golem_main_basic_eldritch_non_interactive() -> anyhow::Result<()> { fn test_golem_main_basic_async() -> anyhow::Result<()> { let mut cmd = Command::new(cargo_bin!("golem")); - cmd.arg(format!("{GOLEM_CLI_TEST_DIR}download_test.tome")); + cmd.arg(format!("{GOLEM_CLI_TEST_DIR}download_test.eldritch")); cmd.assert() .success() .stdout(predicate::str::contains(r#"OKAY!"#)); From 37d1aef47ba6c4a7a8edca1e2ede2f0625a13a9c Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 29 Nov 2025 21:31:36 +0000 Subject: [PATCH 2/3] Update transport docs --- docs/_docs/dev-guide/imix.md | 33 +++++++++------------------------ docs/_docs/dev-guide/tavern.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/docs/_docs/dev-guide/imix.md b/docs/_docs/dev-guide/imix.md index 65fed4035..ae766e0b1 100644 --- a/docs/_docs/dev-guide/imix.md +++ b/docs/_docs/dev-guide/imix.md @@ -169,7 +169,7 @@ impl Transport for DNS { NOTE: Be Aware that currently `reverse_shell` uses tokio's sender/reciever while the rest of the methods rely on mpsc's. This is an artifact of some implementation details under the hood of Imix. Some day we may wish to move completely over to tokio's but currenlty it would just result in performance loss/less maintainable code. -After you implement all the functions/write in a decent error message for operators to understad why the function call failed then you need to import the Transport to the broader lib scope. To do this open up `realm/implants/lib/transport/src/lib.rs` and add in your new Transport like so: +After you implement all the functions/write in a decent error message for operators to understand why the function call failed then you need to import the Transport to the broader lib scope. To do this open up `realm/implants/lib/transport/src/lib.rs` and add in your new Transport like so: ```rust // more stuff above @@ -177,7 +177,7 @@ After you implement all the functions/write in a decent error message for operat #[cfg(feature = "dns")] mod dns; #[cfg(feature = "dns")] -pub use dns::DNS; +pub use dns::DNS as ActiveTransport; // more stuff below ``` @@ -196,32 +196,17 @@ mock = ["dep:mockall"] # more stuff below ``` -And that's it! Well, unless you want to _use_ the new transport. In which case you need to swap out the chosen transport being compiled for Imix in it's Cargo.toml (`/workspaces/realm/implants/lib/transport/Cargo.toml`) like so - +Then make sure the feature flag is populated down from the imix crate `realm/implants/imix/Cargo.toml` ```toml # more stuff above -[dependencies] -eldritch = { workspace = true, features = ["imix"] } -pb = { workspace = true } -transport = { workspace = true, features = ["dns"] } # <-- see here -host_unique = { workspace = true } +[features] +default = ["transport/grpc"] +http1 = ["transport/http1"] +dns = ["transport/dns"] +transport-grpc-doh = ["transport/grpc-doh"] # more stuff below ``` -Then just swap which Transport gets intialized on Imix's `run` function in run.rs (`/workspaces/realm/implants/imix/src/run.rs`) accordingly, - -```rust -// more stuff above - -async fn run(cfg: Config) -> anyhow::Result<()> { - let mut agent = Agent::new(cfg, DNS::init())?; // <-- changed this (also imported it) - agent.callback_loop().await?; - Ok(()) -} - -// more stuff below -``` - -And that's all that is needed for Imix to use a new Transport! Now all there is to do is setup some sort of tavern proxy for your new protocol and test! +And that's all that is needed for Imix to use a new Transport! Now all there is to do is setup the Tarver redirector see the [tavern dev docs here](/dev-guide/tavern#transport-development) diff --git a/docs/_docs/dev-guide/tavern.md b/docs/_docs/dev-guide/tavern.md index c5b6ae8e6..6d08d78a7 100644 --- a/docs/_docs/dev-guide/tavern.md +++ b/docs/_docs/dev-guide/tavern.md @@ -152,6 +152,38 @@ If you wish to develop an agent using a different transport method (e.g. DNS), y 3. Report available output from [Task](/user-guide/terminology#task) execution 4. Sleep for an interval and repeat +## Transport Development + +The tavern transport recieves traffic from an agent over one of the defined protocols (GRPC, HTTP1, DNS) and translates / relays it to the upstream tavern server using grpc. + +Add your redirector implementation to: `tavern/internal/redirectors/dns/dns.go` + +It should inculed the following: +```go +package grpc + +// Register the redirector in the global redirector map. +func init() { + redirectors.Register("dns", &Redirect{}) +} + +// Redirector is a gRPC redirector. +type Redirect struct{} + +// Redirect implements the redirectors.Redirector interface. +func (r *Redirect) Redirect(ctx context.Context, listenOn string, upstream *grpc.ClientConn) error { + // Setup a connection to the upstream server using `upstream.NewStream()` + // Use the `grpc.CallContentSubtype("raw")` option to create a grpc client that operates on raw bytes. + // It's important that the grpc client use raw bytes since transports are unable to read the encrypted + // messages sent by the agent. + + // Setup a server listener that reads requests from the transport + + // It may help to split requests by unary, server streaming, client streaming, and bi-directional streaming. +} +``` + + ## Custom oauth2 backend If you can't use the default google oauth2 backend Realm has a flexible implementation that allows you to implement your own backends. From 6fccc635ce8f4dcdaae45e3c6a2df3da7074421f Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 10 Dec 2025 23:30:59 +0000 Subject: [PATCH 3/3] remove manual pubkey set --- docs/_docs/user-guide/getting-started.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/_docs/user-guide/getting-started.md b/docs/_docs/user-guide/getting-started.md index eaa1cbd77..08add4451 100644 --- a/docs/_docs/user-guide/getting-started.md +++ b/docs/_docs/user-guide/getting-started.md @@ -16,7 +16,6 @@ git clone https://github.com/spellshift/realm && cd ./realm go run ./tavern # Start Agent -export IMIX_SERVER_PUBKEY="$(curl http://localhost:8000/status | jq -r '.Pubkey')" cd implants/imix && cargo run ``` @@ -54,9 +53,6 @@ The warnings you see here indicate that there are settings recommended for produ # Assumes you have already cloned the repository and are in the 'realm' directory cd ./implants/imix -# Set the server pubkey this assumes you've already started a local tavern instance -export IMIX_SERVER_PUBKEY="$(curl http://localhost:8000/status | jq -r '.Pubkey')" - cargo run ```