Skip to content

Commit

Permalink
[implant] decode payload with rust (#1604)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarineLeM authored Dec 10, 2024
1 parent be94374 commit 404ad50
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 76 deletions.
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",
"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",
"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)
}

0 comments on commit 404ad50

Please sign in to comment.