diff --git a/docs/_docs/user-guide/eldritch.md b/docs/_docs/user-guide/eldritch.md
index a07122644..0afae7653 100644
--- a/docs/_docs/user-guide/eldritch.md
+++ b/docs/_docs/user-guide/eldritch.md
@@ -138,6 +138,16 @@ The agent.set_callback_interval method takes an unsigned int and changes
running agent's callback interval to the passed value. This configuration change will
not persist across agent reboots.
+### agent.set_callback_uri
+
+`agent.set_callback_uri(new_uri: str) -> None`
+
+The agent.set_callback_uri method takes an string and changes the
+running agent's callback uri to the passed value. This configuration change will
+not persist across agent reboots. NOTE: please ensure the passed URI path is correct
+for the underlying `Transport` being used, as a URI can take many forms and we make no
+assumptions on `Transport` requirements no gut checks are applied to the passed string.
+
---
## Assets
diff --git a/implants/lib/eldritch/src/agent/mod.rs b/implants/lib/eldritch/src/agent/mod.rs
index be07c49f1..6c6d9552d 100644
--- a/implants/lib/eldritch/src/agent/mod.rs
+++ b/implants/lib/eldritch/src/agent/mod.rs
@@ -1,5 +1,6 @@
mod eval_impl;
mod set_callback_interval_impl;
+mod set_callback_uri_impl;
use starlark::{
environment::MethodsBuilder,
@@ -33,4 +34,10 @@ fn methods(builder: &mut MethodsBuilder) {
set_callback_interval_impl::set_callback_interval(env, new_interval)?;
Ok(NoneType{})
}
+ #[allow(unused_variables)]
+ fn set_callback_uri(this: &AgentLibrary, starlark_eval: &mut Evaluator<'v, '_>, new_uri: String) -> anyhow::Result {
+ let env = crate::runtime::Environment::from_extra(starlark_eval.extra)?;
+ set_callback_uri_impl::set_callback_uri(env, new_uri)?;
+ Ok(NoneType{})
+ }
}
diff --git a/implants/lib/eldritch/src/agent/set_callback_uri_impl.rs b/implants/lib/eldritch/src/agent/set_callback_uri_impl.rs
new file mode 100644
index 000000000..b33dcd382
--- /dev/null
+++ b/implants/lib/eldritch/src/agent/set_callback_uri_impl.rs
@@ -0,0 +1,60 @@
+use crate::runtime::{messages::SetCallbackUriMessage, messages::SyncMessage, Environment};
+use anyhow::Result;
+
+pub fn set_callback_uri(env: &Environment, new_uri: String) -> Result<()> {
+ env.send(SyncMessage::from(SetCallbackUriMessage {
+ id: env.id(),
+ new_uri,
+ }))?;
+ Ok(())
+}
+
+#[cfg(test)]
+mod test {
+ use crate::runtime::{messages::SyncMessage, Message};
+ use pb::eldritch::Tome;
+ use std::collections::HashMap;
+
+ macro_rules! test_cases {
+ ($($name:ident: $value:expr,)*) => {
+ $(
+ #[tokio::test]
+ async fn $name() {
+ let tc: TestCase = $value;
+
+ // Run Eldritch (until finished)
+ let mut runtime = crate::start(tc.id, tc.tome).await;
+ runtime.finish().await;
+
+ // Read Messages
+ let mut found = false;
+ for msg in runtime.messages() {
+ if let Message::Sync(SyncMessage::SetCallbackUri(m)) = msg {
+ assert_eq!(tc.new_uri, m.new_uri);
+ found = true;
+ }
+ }
+ assert!(found);
+ }
+ )*
+ }
+ }
+
+ struct TestCase {
+ pub id: i64,
+ pub tome: Tome,
+ pub new_uri: String,
+ }
+
+ test_cases! {
+ change_interval: TestCase{
+ id: 123,
+ tome: Tome{
+ eldritch: String::from(r#"agent.set_callback_uri("https://127.0.0.1")"#),
+ parameters: HashMap::new(),
+ file_names: Vec::new(),
+ },
+ new_uri: String::from("https://127.0.0.1"),
+ },
+ }
+}
diff --git a/implants/lib/eldritch/src/runtime/messages/mod.rs b/implants/lib/eldritch/src/runtime/messages/mod.rs
index dd7655c2a..8317d29e1 100644
--- a/implants/lib/eldritch/src/runtime/messages/mod.rs
+++ b/implants/lib/eldritch/src/runtime/messages/mod.rs
@@ -10,6 +10,7 @@ mod report_start;
mod report_text;
mod reverse_shell_pty;
mod set_callback_interval;
+mod set_callback_uri;
pub use fetch_asset::FetchAssetMessage;
pub use pb::config::Config;
@@ -23,6 +24,7 @@ pub use report_start::ReportStartMessage;
pub use report_text::ReportTextMessage;
pub use reverse_shell_pty::ReverseShellPTYMessage;
pub use set_callback_interval::SetCallbackIntervalMessage;
+pub use set_callback_uri::SetCallbackUriMessage;
pub use transport::Transport;
use anyhow::Result;
@@ -121,6 +123,9 @@ impl AsyncDispatcher for AsyncMessage {
pub enum SyncMessage {
#[display(fmt = "SetCallbackInterval")]
SetCallbackInterval(SetCallbackIntervalMessage),
+
+ #[display(fmt = "SetCallbackUri")]
+ SetCallbackUri(SetCallbackUriMessage),
}
impl SyncDispatcher for SyncMessage {
@@ -130,6 +135,7 @@ impl SyncDispatcher for SyncMessage {
match self {
Self::SetCallbackInterval(msg) => msg.dispatch(transport, cfg),
+ Self::SetCallbackUri(msg) => msg.dispatch(transport, cfg),
}
}
}
diff --git a/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs b/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs
new file mode 100644
index 000000000..47d5165fc
--- /dev/null
+++ b/implants/lib/eldritch/src/runtime/messages/set_callback_uri.rs
@@ -0,0 +1,21 @@
+use super::{SyncDispatcher, Transport};
+use anyhow::Result;
+use pb::config::Config;
+
+/*
+ * SetCallbackUriMessage sets the callback URI in the dispatched config.
+ */
+#[cfg_attr(debug_assertions, derive(Debug, PartialEq))]
+#[derive(Clone)]
+pub struct SetCallbackUriMessage {
+ pub(crate) id: i64,
+ pub(crate) new_uri: String,
+}
+
+impl SyncDispatcher for SetCallbackUriMessage {
+ fn dispatch(self, _transport: &mut impl Transport, cfg: Config) -> Result {
+ let mut c = cfg.clone();
+ c.callback_uri = self.new_uri;
+ Ok(c)
+ }
+}
diff --git a/implants/lib/eldritch/src/runtime/mod.rs b/implants/lib/eldritch/src/runtime/mod.rs
index 5636e1298..c6d5f99ed 100644
--- a/implants/lib/eldritch/src/runtime/mod.rs
+++ b/implants/lib/eldritch/src/runtime/mod.rs
@@ -204,7 +204,7 @@ mod tests {
parameters: HashMap::new(),
file_names: Vec::new(),
},
- want_text: format!("{}\n", r#"["eval", "set_callback_interval"]"#),
+ want_text: format!("{}\n", r#"["eval", "set_callback_interval", "set_callback_uri"]"#),
want_error: None,
},
}