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
32 changes: 31 additions & 1 deletion docs/_docs/admin-guide/tavern.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,12 @@ By default Tavern only supports gRPC connections directly to the server. To enab

### Available Redirectors

Realm includes three built-in redirector implementations:
Realm includes four built-in redirector implementations:

- **`grpc`** - Direct gRPC passthrough redirector
- **`http1`** - HTTP/1.1 to gRPC redirector
- **`dns`** - DNS to gRPC redirector
- **`icmp`** - ICMP Echo to gRPC redirector

### Basic Usage

Expand Down Expand Up @@ -166,6 +167,35 @@ tavern redirector --transport dns --listen "0.0.0.0:53?domain=c2.example.com&dom

See the [DNS Transport Configuration](/user-guide/imix#dns-transport-configuration) section in the Imix user guide for more details on agent-side configuration.

### ICMP Redirector

The ICMP redirector tunnels C2 traffic through ICMP Echo Request/Reply packets.

```bash
# Start ICMP redirector, listening on all interfaces
tavern redirector --transport icmp --listen 0.0.0.0 http://localhost:8000
```

**Host Configuration Requirements:**

Before starting the ICMP redirector, the Linux kernel's automatic ICMP echo reply must be disabled. Without this, the kernel responds to incoming ICMP echo requests by mirroring the payload back to the sender before the user-space redirector can act. Agents receive this kernel reply first and parse their own request payload as a response, breaking the protocol.

```bash
echo 1 | sudo tee /proc/sys/net/ipv4/icmp_echo_ignore_all
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the terraform to include support for ICMP.

Probably need to copy the DNS pattern but will need a separate VM per redirector otherwise they'll have the same IP.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didnt plan on supporting public infra icmp. Ill look into it tho

```

The redirector will refuse to start if this is not set. To make the setting persistent across reboots:

```bash
echo "net.ipv4.icmp_echo_ignore_all = 1" | sudo tee -a /etc/sysctl.conf
sysctl -p
```

**Other requirements:**

- Must run as root (raw ICMP sockets require `CAP_NET_RAW`)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RAW?!?!!
If we do not raw can we support windows and non root beacons?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for the tavern redirector, not the beacons.

- Not supported on Windows hosts

### gRPC Redirector

The gRPC redirector provides a passthrough for gRPC traffic, useful for deploying multiple Tavern endpoints or load balancing.
Expand Down
8 changes: 7 additions & 1 deletion docs/_docs/dev-guide/imix.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ Realm currently includes three transport implementations:
- **`grpc`** - Default gRPC transport
- **`http1`** - HTTP/1.1 transport
- **`dns`** - DNS-based covert channel transport
- **`icmp`** - ICMP-based covert channel transport

_grpc & http1 both support doh and http proxy set through the extra argument_

Expand Down Expand Up @@ -259,6 +260,8 @@ pub enum ActiveTransport {
Http(http::HTTP),
#[cfg(feature = "dns")]
Dns(dns::DNS),
#[cfg(feature = "icmp")]
Icmp(icmp::ICMP),
#[cfg(feature = "mock")]
Mock(mock::MockTransport),
Empty,
Expand All @@ -278,6 +281,7 @@ grpc = ["pb/grpc"]
doh = ["dep:hickory-resolver"]
http1 = ["pb/http1"]
dns = ["dep:base32", "dep:rand", "dep:hickory-resolver", "dep:url"]
icmp = ["dep:rand", "dep:libc"]
custom = ["dep:your-custom-dependency"] # <-- Add your feature here
mock = ["dep:mockall"]

Expand All @@ -299,11 +303,12 @@ Add a proxy for your feature to `realm/implants/imix/Cargo.toml`

```toml
[features]
default = ["install", "grpc", "http1", "dns", "doh", "custom"]
default = ["install", "grpc", "http1", "dns", "doh", "custom", "icmp"]
grpc = ["transport/grpc"]
http1 = ["transport/http1"]
dns = ["transport/dns"]
doh = ["transport/doh"]
icmp = ["transport/icmp"]
custom = ["transport/custom"]
```

Expand All @@ -317,6 +322,7 @@ For your agent to communicate, you'll need to implement a corresponding redirect
- `tavern/internal/redirectors/grpc/` - gRPC redirector
- `tavern/internal/redirectors/http1/` - HTTP/1.1 redirector
- `tavern/internal/redirectors/dns/` - DNS redirector
- `tavern/internal/redirectors/icmp/` - ICMP redirector

Your redirector must implement the `Redirector` interface and register itself in the redirector registry. See `tavern/internal/redirectors/redirector.go` for the interface definition.

Expand Down
16 changes: 13 additions & 3 deletions docs/_docs/user-guide/imix.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ For more complex setups, such as configuring multiple transports or specifying d
```yaml
transports:
- URI: <string>
type: <grpc|http1|dns>
type: <grpc|http1|dns|icmp>
interval: <integer> # optional, seconds
extra: <json_string> # required (use "" if none)
server_pubkey: <string> # optional - defaults to checking the first transport URI status page.
Expand Down Expand Up @@ -167,7 +167,7 @@ cargo build --release --bin imix --target=x86_64-unknown-linux-musl

## Transport configuration

Imix supports pluggable transports making it easy to adapt to your environment. Out of the box it supports `grpc` (default), `http1` and `dns`. Each transport has a corresponding redirector subcommand in tavern. In order to use a non grpc transport a redirector that can speak to your transport is required.
Imix supports pluggable transports making it easy to adapt to your environment. Out of the box it supports `grpc` (default), `http1`, `dns`, and `icmp`. Each transport has a corresponding redirector subcommand in tavern. In order to use a non grpc transport a redirector that can speak to your transport is required.

### global configuration options
- `uri`: specifies the upstream server or redirector the agent should connect to eg. `https://example.com` custom ports can be specified as `https://example.com:8443`
Expand Down Expand Up @@ -199,7 +199,7 @@ This transport doesn't support eldritch functions that require bi-directional st

### dns

The DNS transport enables covert C2 communication by tunneling traffic through DNS queries and responses. This transport supports multiple DNS record types (TXT, A, AAAA).
The DNS transport enables covert C2 communication by tunneling `ConvPacket` traffic through DNS queries and responses. This transport supports multiple DNS record types (TXT, A, AAAA).

This transport doesn't support eldritch functions that require bi-directional streaming like reverse shell, or SOCKS5 proxying.

Expand Down Expand Up @@ -242,6 +242,16 @@ transports:
- **Connection Persistence**: The TCP connection is maintained and reused across multiple C2 cycles. If the connection drops, a new upstream connection must be initiated.
- **Not Suitable for Wide-Area Networks**: This transport is designed for local or trusted network chaining. For remote communication, use standard grpc, http1, or dns transports.

### icmp

The ICMP transport tunnels `ConvPacket` traffic through ICMP Echo Request/Reply packets. Raw protobuf bytes are carried directly in the echo payload, allowing up to 1400 byte chunks per packet.

This transport doesn't support eldritch functions that require bi-directional streaming like reverse shell, or SOCKS5 proxying.

*Note*: The URI must be the IPv4 address of the ICMP redirector, e.g. `icmp://192.168.1.1`. The redirector host must have kernel ICMP echo replies disabled - see the [ICMP Redirector](/admin-guide/tavern#icmp-redirector) section in the Tavern admin guide for setup instructions.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No support for FQDN?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also didnt plan on supporting this either


**Extra Keys Supported:** None

## Logging

At runtime, you may use the `IMIX_LOG` environment variable to control log levels and verbosity. See [these docs](https://docs.rs/pretty_env_logger/latest/pretty_env_logger/) for more information. **When building a release version of imix, logging is disabled** and is not included in the released binary.
Expand Down
3 changes: 2 additions & 1 deletion implants/imix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ edition = "2024"
crate-type = ["cdylib"]

[features]
default = ["install", "grpc", "http1", "dns", "doh", "tcp-bind"]
default = ["install", "grpc", "http1", "dns", "doh", "icmp", "tcp-bind"]
grpc = ["transport/grpc"]
http1 = ["transport/http1"]
dns = ["transport/dns"]
doh = ["transport/doh"]
icmp = ["transport/icmp"]
tcp-bind = ["transport/tcp-bind"]
win_service = []
install = []
Expand Down
11 changes: 6 additions & 5 deletions implants/lib/pb/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ struct TransportConfig {
uri: String,
#[serde(rename = "type")]
transport_type: String,
#[serde(default)]
extra: String,
#[serde(default)]
interval: Option<u64>,
Expand Down Expand Up @@ -87,7 +88,7 @@ fn parse_yaml_config() -> Result<Option<YamlConfigResult>, Box<dyn std::error::E
for transport in &config.transports {
// Validate transport type
let transport_type_lower = transport.transport_type.to_lowercase();
if !["grpc", "http1", "dns"].contains(&transport_type_lower.as_str()) {
if !["grpc", "http1", "dns", "icmp"].contains(&transport_type_lower.as_str()) {
return Err(format!(
"Invalid transport type '{}'. Must be one of: GRPC, http1, DNS",
transport.transport_type
Expand Down Expand Up @@ -391,23 +392,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(_) => println!("generated c2 protos"),
};

// Build DNS Protos (no encryption codec - used for transport layer only)
// Build Conv Protos (no encryption codec - shared conversation protocol)
match tonic_prost_build::configure()
.out_dir("./src/generated")
.build_server(false)
.build_client(false)
.compile_protos(
&["dns.proto"],
&["conv.proto"],
&[
"../../../tavern/internal/c2/proto/",
"../../../tavern/portals/proto/",
],
) {
Err(err) => {
println!("WARNING: Failed to compile dns protos: {}", err);
println!("WARNING: Failed to compile conv protos: {}", err);
panic!("{}", err);
}
Ok(_) => println!("generated dns protos"),
Ok(_) => println!("generated conv protos"),
};

Ok(())
Expand Down
1 change: 1 addition & 0 deletions implants/lib/pb/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ pub const RUN_ONCE: bool = run_once!();
fn get_transport_type(uri: &str) -> crate::c2::transport::Type {
match uri.split(":").next().unwrap_or("unspecified") {
"dns" => crate::c2::transport::Type::TransportDns,
"icmp" => crate::c2::transport::Type::TransportIcmp,
"http1" => crate::c2::transport::Type::TransportHttp1,
"https1" => crate::c2::transport::Type::TransportHttp1,
"https" => crate::c2::transport::Type::TransportGrpc,
Expand Down
3 changes: 3 additions & 0 deletions implants/lib/pb/src/generated/c2.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions implants/lib/pb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pub mod eldritch {
pub mod c2 {
include!("generated/c2.rs");
}
pub mod dns {
include!("generated/dns.rs");
pub mod conv {
include!("generated/conv.rs");
}
pub mod portal {
include!("generated/portal.rs");
Expand Down
8 changes: 8 additions & 0 deletions implants/lib/transport/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ grpc = ["pb/grpc"]
doh = ["dep:hickory-resolver"]
http1 = ["pb/http1"]
dns = ["dep:base32", "dep:rand", "dep:hickory-resolver", "dep:url"]
icmp = ["dep:rand", "dep:libc"]
mock = ["dep:mockall"]
tcp-bind = ["tokio-stream/net"]

Expand Down Expand Up @@ -45,6 +46,13 @@ hickory-resolver = { version = "0.24", features = ["dns-over-https-rustls", "web
base32 = { workspace = true, optional = true }
rand = { workspace = true, optional = true }
url = { workspace = true, optional = true }
libc = { workspace = true, optional = true }

# [feature = mock]
mockall = { workspace = true, optional = true }

[target.'cfg(target_os = "windows")'.dependencies]
windows-sys = { workspace = true, features = [
"Win32_Foundation",
"Win32_NetworkManagement_IpHelper",
] }
Loading
Loading