diff --git a/docs/_docs/user-guide/eldritch.md b/docs/_docs/user-guide/eldritch.md index 08b348c96..82990ccb8 100644 --- a/docs/_docs/user-guide/eldritch.md +++ b/docs/_docs/user-guide/eldritch.md @@ -552,37 +552,32 @@ The pivot.smb_exec method is being proposed to allow users a way to move ### pivot.ssh_copy -`pivot.ssh_copy(target: str, port: int, src: str, dst: str, username: str, password: Optional, key: Optional, key_password: Optional, timeout: Optional) -> None` +`pivot.ssh_copy(target: str, port: int, src: str, dst: str, username: str, password: Optional, key: Optional, key_password: Optional, timeout: Optional) -> str` -The pivot.ssh_copy method copies a local file to a remote system. If no password or key is specified the function will error out with: -`Failed to run handle_ssh_exec: Failed to authenticate to host` +The pivot.ssh_copy method copies a local file to a remote system. +ssh_copy will return `"Sucess"` if successful and `"Failed to run handle_ssh_copy: ..."` on failure. If the connection is successful but the copy writes a file error will be returned. - -ssh_copy will first delete the remote file and then write to its location. +ssh_copy will overwrite the remote file if it exists. The file directory the `dst` file exists in must exist in order for ssh_copy to work. + ### pivot.ssh_exec `pivot.ssh_exec(target: str, port: int, command: str, username: str, password: Optional, key: Optional, key_password: Optional, timeout: Optional) -> List` -The pivot.ssh_exec method executes a command string on the remote host using the default shell. If no password or key is specified the function will error out with: -`Failed to run handle_ssh_exec: Failed to authenticate to host` -If the connection is successful but the command fails no output will be returned but the status code will be set. -Not returning stderr is a limitation of the way we're performing execution. Since it's not using the SSH shell directive we're limited on the return output we can capture. +The pivot.ssh_exec method executes a command string on the remote host using the default shell. +Stdout returns the string result from the command output. +Stderr will return any errors from the SSH connection but not the command being executed. +Status will be equal to the code returned by the command being run and -1 in the event that the ssh connection raises an error. ```json { "stdout": "uid=1000(kali) gid=1000(kali) groups=1000(kali),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),118(bluetooth),128(lpadmin),132(scanner),143(docker)\n", + "stderr":"", "status": 0 } ``` -### pivot.ssh_password_spray - -`pivot.ssh_password_spray(targets: List, port: int, credentials: List, keys: List, command: str, shell_path: str) -> List` - -The pivot.ssh_password_spray method is being proposed to allow users a way to test found credentials against neighboring targets. It will iterate over the targets list and try each credential set. Credentials will be a formatted list of usernames and passwords Eg. "username:password". The function will return a formatted list of "target:username:password". command and shell_path is intended to give more flexibility but may be adding complexity. - --- ## Process diff --git a/implants/lib/eldritch/src/pivot/mod.rs b/implants/lib/eldritch/src/pivot/mod.rs index 6cf790ff5..eb8457bcc 100644 --- a/implants/lib/eldritch/src/pivot/mod.rs +++ b/implants/lib/eldritch/src/pivot/mod.rs @@ -7,7 +7,6 @@ mod reverse_shell_pty_impl; mod smb_exec_impl; mod ssh_copy_impl; mod ssh_exec_impl; -mod ssh_password_spray_impl; use anyhow::Result; use async_trait::async_trait; @@ -48,14 +47,8 @@ fn methods(builder: &mut MethodsBuilder) { } #[allow(unused_variables)] - fn ssh_copy<'v>(this: &PivotLibrary, target: String, port: i32, src: String, dst: String, username: String, password: Option, key: Option, key_password: Option, timeout: Option) -> anyhow::Result { - ssh_copy_impl::ssh_copy(target, port, src, dst, username, password, key, key_password, timeout)?; - Ok(NoneType{}) - } - - #[allow(unused_variables)] - fn ssh_password_spray(this: &PivotLibrary, targets: UnpackList, port: i32, credentials: UnpackList, keys: UnpackList, command: String, shell_path: String) -> anyhow::Result { - ssh_password_spray_impl::ssh_password_spray(targets.items, port, credentials.items, keys.items, command, shell_path) + fn ssh_copy<'v>(this: &PivotLibrary, target: String, port: i32, src: String, dst: String, username: String, password: Option, key: Option, key_password: Option, timeout: Option) -> anyhow::Result { + ssh_copy_impl::ssh_copy(target, port, src, dst, username, password, key, key_password, timeout) } #[allow(unused_variables)] diff --git a/implants/lib/eldritch/src/pivot/ssh_copy_impl.rs b/implants/lib/eldritch/src/pivot/ssh_copy_impl.rs index e426295dd..3d0250212 100644 --- a/implants/lib/eldritch/src/pivot/ssh_copy_impl.rs +++ b/implants/lib/eldritch/src/pivot/ssh_copy_impl.rs @@ -42,7 +42,7 @@ pub fn ssh_copy( key: Option, key_password: Option, timeout: Option, -) -> Result<()> { +) -> Result { let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build()?; @@ -63,14 +63,11 @@ pub fn ssh_copy( )) { Ok(local_res) => local_res, Err(local_err) => { - return Err(anyhow::anyhow!( - "Failed to run handle_ssh_exec: {}", - local_err.to_string() - )) + return Ok(format!("Failed to run handle_ssh_copy: {}", local_err)); } }; - Ok(()) + Ok("Sucess".to_string()) } #[cfg(test)] diff --git a/implants/lib/eldritch/src/pivot/ssh_exec_impl.rs b/implants/lib/eldritch/src/pivot/ssh_exec_impl.rs index b00d6549c..3ac3f4ad7 100644 --- a/implants/lib/eldritch/src/pivot/ssh_exec_impl.rs +++ b/implants/lib/eldritch/src/pivot/ssh_exec_impl.rs @@ -63,7 +63,7 @@ pub fn ssh_exec( let key_password_ref = key_password.as_deref(); let local_port: u16 = port.try_into()?; - let cmd_res = match runtime.block_on(handle_ssh_exec( + let (out, status, err) = match runtime.block_on(handle_ssh_exec( target, local_port, command, @@ -73,19 +73,15 @@ pub fn ssh_exec( key_password_ref, timeout, )) { - Ok(local_res) => local_res, - Err(local_err) => { - return Err(anyhow::anyhow!( - "Failed to run handle_ssh_exec: {}", - local_err.to_string() - )) - } + Ok(local_res) => (local_res.stdout, local_res.status, String::from("")), + Err(local_err) => (String::from(""), -1, local_err.to_string()), }; let res = SmallMap::new(); let mut dict_res = Dict::new(res); - insert_dict_kv!(dict_res, starlark_heap, "stdout", &cmd_res.stdout, String); - insert_dict_kv!(dict_res, starlark_heap, "status", cmd_res.status, i32); + insert_dict_kv!(dict_res, starlark_heap, "stdout", &out, String); + insert_dict_kv!(dict_res, starlark_heap, "stderr", &err, String); + insert_dict_kv!(dict_res, starlark_heap, "status", status, i32); Ok(dict_res) } diff --git a/implants/lib/eldritch/src/pivot/ssh_password_spray_impl.rs b/implants/lib/eldritch/src/pivot/ssh_password_spray_impl.rs deleted file mode 100644 index c0ad7a2dc..000000000 --- a/implants/lib/eldritch/src/pivot/ssh_password_spray_impl.rs +++ /dev/null @@ -1,12 +0,0 @@ -use anyhow::Result; - -pub fn ssh_password_spray( - _targets: Vec, - _port: i32, - _credentials: Vec, - _keys: Vec, - _command: String, - _shell_path: String, -) -> Result { - unimplemented!("Method unimplemented") -} diff --git a/implants/lib/eldritch/src/runtime/mod.rs b/implants/lib/eldritch/src/runtime/mod.rs index 99792a2be..483024cf7 100644 --- a/implants/lib/eldritch/src/runtime/mod.rs +++ b/implants/lib/eldritch/src/runtime/mod.rs @@ -119,7 +119,7 @@ mod tests { parameters: HashMap::new(), file_names: Vec::new(), }, - want_text: format!("{}\n", r#"["arp_scan", "bind_proxy", "ncat", "port_forward", "port_scan", "reverse_shell_pty", "smb_exec", "ssh_copy", "ssh_exec", "ssh_password_spray"]"#), + want_text: format!("{}\n", r#"["arp_scan", "bind_proxy", "ncat", "port_forward", "port_scan", "reverse_shell_pty", "smb_exec", "ssh_copy", "ssh_exec"]"#), want_error: None, }, assets_bindings: TestCase {