Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[implant] decode payload with rust #26

Merged
merged 2 commits into from
Dec 10, 2024
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
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ pub fn handle_payload(inject_id: String, api: &Client, contract_payload: &Inject
Some(args) => args,
};
for prerequisite in prerequisites.iter() {
let mut check_status = 0;
let mut check_status = 1;
let check_cmd = &prerequisite.check_command;
if check_cmd.is_some() {
if check_cmd.is_some() && !check_cmd.clone().unwrap().is_empty(){
let check_prerequisites = compute_command(check_cmd.as_ref().unwrap());
check_status = handle_execution_command(
"prerequisite check",
Expand Down
141 changes: 67 additions & 74 deletions src/process/command_exec.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::process::{Child, Command, Output, Stdio};
use std::process::{Command, Output, Stdio};

use base64::{engine::general_purpose::STANDARD, Engine as _};
use serde::Deserialize;

use crate::common::error_model::Error;
Expand All @@ -12,63 +13,36 @@ pub struct ExecutionResult {
pub exit_code: i32,
}

pub fn invoke_command(echo_cmd: Child, executor: &str) -> std::io::Result<Output> {
pub fn invoke_command(executor: &str, cmd_expression: &str, args: &[&str]) -> std::io::Result<Output> {
Command::new(executor)
.stdin(Stdio::from(echo_cmd.stdout.unwrap()))
.args(args)
.arg(cmd_expression)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?
.wait_with_output()
}

pub fn invoke_powershell_command(command: &str, executor: &str, args: &[&str]) -> std::io::Result<Output> {
// For powershell complex command, we need to encode in base64 to manage escape caracters and multi lines commands
let invoke_expression = format!("$ErrorActionPreference = 'Stop'; Invoke-Expression ([System.Text.Encoding]::UTF8.GetString([convert]::FromBase64String(\"{}\"))); exit $LASTEXITCODE", command);
Command::new(executor)
.args(args)
.arg(invoke_expression)
.stderr(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?
.wait_with_output()
pub fn decode_command(encoded_command: &str) -> String {
let decoded_bytes = STANDARD
.decode(encoded_command)
.expect("Failed to decode Base64 command");
String::from_utf8(decoded_bytes)
.expect("Decoded command is not valid UTF-8")
}

pub fn invoke_shell_command(command: &str, executor: &str) -> std::io::Result<Output> {
// For shell complex command, we need to encode in base64 to manage escape caracters and multi lines commands
let base64_command = format!("echo {} | base64 -d", command);
let base64_child = Command::new(executor)
.arg("-c")
.arg(&base64_command)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;

invoke_command(base64_child, executor)
pub fn format_powershell_command(command:String) -> String {
format!(
"$ErrorActionPreference = 'Stop'; {} ; exit $LASTEXITCODE",
command
)
}

pub fn invoke_windows_command(command: &str) -> std::io::Result<Output> {
let invoke_expression = format!("([System.Text.Encoding]::UTF8.GetString([convert]::FromBase64String(\"{}\")))", command);
let base64_child = Command::new("powershell.exe")
.arg("-Command")
.arg(&invoke_expression)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()?;

let decoded_command = String::from_utf8_lossy(&base64_child.stdout).trim().to_string();

let cmd_expression = format!(
pub fn format_windows_command(command:String) -> String {
format!(
"setlocal & {} & exit /b errorlevel",
decoded_command
);

Command::new("cmd.exe")
.arg("/C")
.arg(cmd_expression)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?
.wait_with_output()
command
)
}

pub fn manage_result(invoke_output: Output, pre_check: bool) -> Result<ExecutionResult, Error> {
Expand Down Expand Up @@ -96,39 +70,58 @@ pub fn manage_result(invoke_output: Output, pre_check: bool) -> Result<Execution
}

#[cfg(target_os = "windows")]
pub fn command_execution(command: &str, executor: &str, pre_check: bool) -> Result<ExecutionResult, Error> {
let invoke_output;
if executor == "cmd" {
invoke_output = invoke_windows_command(command);
} else if executor == "bash" || executor == "sh" {
invoke_output = invoke_shell_command(command, executor);
} else {
invoke_output = invoke_powershell_command(command,"powershell.exe", &[
"-ExecutionPolicy",
damgouj marked this conversation as resolved.
Show resolved Hide resolved
"Bypass",
"-WindowStyle",
"Hidden",
"-NonInteractive",
"-NoProfile",
"-Command"]);
pub fn get_executor( executor: &str) -> &str {
match executor {
"cmd" | "bash" | "sh" => executor,
_ => "powershell"
}
manage_result(invoke_output?, pre_check)
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn get_executor( executor: &str) -> &str {
match executor {
"bash" => executor,
"psh" => "powershell",
_ => "sh"
}
}

#[cfg(target_os = "windows")]
pub fn get_psh_arg() -> Vec<&'static str> {
Vec::from([
"-ExecutionPolicy",
"Bypass",
"-WindowStyle",
"Hidden",
"-NonInteractive",
"-NoProfile",
"-Command"])
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn get_psh_arg() -> Vec<&'static str> {
Vec::from([
"-ExecutionPolicy",
"Bypass",
"-NonInteractive",
"-NoProfile",
"-Command"])
}

pub fn command_execution(command: &str, executor: &str, pre_check: bool) -> Result<ExecutionResult, Error> {
let invoke_output;
if executor == "bash" {
invoke_output = invoke_shell_command(command, "bash");
} else if executor == "psh" {
invoke_output = invoke_powershell_command(command, "powershell", &[
"-ExecutionPolicy",
damgouj marked this conversation as resolved.
Show resolved Hide resolved
"Bypass",
"-NonInteractive",
"-NoProfile",
"-Command"]);
} else {
invoke_output = invoke_shell_command(command, "sh");
let final_executor = get_executor(executor);
let mut formatted_cmd= decode_command(command);
let mut args: Vec<&str> = vec!["-c"];

if final_executor == "cmd" {
formatted_cmd = format_windows_command(formatted_cmd);
args = vec!["/V", "/C"];

} else if final_executor == "powershell" {
formatted_cmd = format_powershell_command(formatted_cmd);
args = get_psh_arg();
}

let invoke_output = invoke_command(final_executor, &formatted_cmd, args.as_slice());
manage_result(invoke_output?, pre_check)
}