Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 9 additions & 24 deletions docs/_docs/dev-guide/imix.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,15 @@ 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

#[cfg(feature = "dns")]
mod dns;
#[cfg(feature = "dns")]
pub use dns::DNS;
pub use dns::DNS as ActiveTransport;

// more stuff below
```
Expand All @@ -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)
32 changes: 32 additions & 0 deletions docs/_docs/dev-guide/tavern.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion docs/_docs/user-guide/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ 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

cargo run
```

![starting-imix](/assets/img/user-guide/getting-started/starting-imix.png)
Expand Down
9 changes: 6 additions & 3 deletions docs/_docs/user-guide/golem.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.

Expand Down
3 changes: 3 additions & 0 deletions docs/_docs/user-guide/imix.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
10 changes: 5 additions & 5 deletions implants/golem/tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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(),
));
Expand All @@ -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"#));
Expand All @@ -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""#));
Expand All @@ -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!"#));
Expand Down
Loading