From d51457667396f6bfc6d738adaf2bee3e0b8e42cb Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 8 Sep 2024 13:48:08 +0200 Subject: [PATCH 01/22] =?UTF-8?q?docs:=20=F0=9F=93=9A=20Remove=20old=20doc?= =?UTF-8?q?umentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Artefacts.md | 178 ---------------------------------------------- docs/cli_help.md | 109 ---------------------------- 2 files changed, 287 deletions(-) delete mode 100644 docs/Artefacts.md delete mode 100644 docs/cli_help.md diff --git a/docs/Artefacts.md b/docs/Artefacts.md deleted file mode 100644 index 75aa07c..0000000 --- a/docs/Artefacts.md +++ /dev/null @@ -1,178 +0,0 @@ - - -# Artefact list - -- [Sysmon V15 Artefact](#sysmon-v15-artefact) - - [Process creation (1)](#process-creation-1) - - [process changed a file creation time (2)](#process-changed-a-file-creation-time-2) - - [Network connection (3)](#network-connection-3) - - [Sysmon service state changed (4)](#sysmon-service-state-changed-4) - - [Process terminated (5)](#process-terminated-5) - - [Driver loaded (6)](#driver-loaded-6) - - [Image loaded (7)](#image-loaded-7) - - [CreateRemoteThread (8)](#createremotethread-8) - - [RawAccessRead (9)](#rawaccessread-9) - - [ProcessAccess (10)](#processaccess-10) - - [FileCreate (11)](#filecreate-11) - - [RegistryEvent (12,13,14)](#registryevent-121314) - - [FileCreateStreamHash (15)](#filecreatestreamhash-15) - - [ServiceConfigurationChange (16)](#serviceconfigurationchange-16) - - [PipeEvent (17,18)](#pipeevent-1718) - - [WmiEvent (19,20,21)](#wmievent-192021) - - [DNSEvent (22)](#dnsevent-22) - - [FileDelete (23)](#filedelete-23) - - [ClipboardChange (24)](#clipboardchange-24) - - [ProcessTampering (25)](#processtampering-25) - - [FileDeleteDetected (26)](#filedeletedetected-26) - - [FileBlockExecutable (27)](#fileblockexecutable-27) - - [FileBlockShredding (28)](#fileblockshredding-28) - - [FileExecutableDetected (29)](#fileexecutabledetected-29) - - [Error (255)](#error-255) -- [Windows builtin Channel](#windows-builtin-channel) - -# Sysmon V15 Artefact - -- ✔ Wag can create artefact -- ✖ Wag will not create artefact - -❓ Need to be check - -| EventID | Description | Cover by wag | -| ------- | ----------------------------------------------------- | ------------ | -| 1 | Process creation | ✖ | -| 2 | process changed a file creation time | ❓ | -| 3 | Network connection | ✖ | -| 4 | Sysmon service state changed | ✖ | -| 5 | Process terminated | ✖ | -| 6 | Driver loaded | ✔ | -| 7 | Image loaded | ❓ | -| 8 | CreateRemoteThread | ❓ | -| 9 | RawAccessRead | ❓ | -| 10 | ProcessAccess | ❓ | -| 11 | FileCreate | ✔ | -| 12 | RegistryEvent (Object create and delete) | ✖ | -| 13 | RegistryEvent (Value Set) | ✖ | -| 14 | RegistryEvent (Key and Value Rename) | ✖ | -| 15 | FileCreateStreamHash | ✔ | -| 16 | ServiceConfigurationChange | ✖ | -| 17 | PipeEvent (Pipe Created) | ✔ | -| 18 | PipeEvent (Pipe Connected) | ❓ | -| 19 | WmiEvent (WmiEventFilter activity detected) | ❓ | -| 20 | WmiEvent (WmiEventConsumer activity detected) | ❓ | -| 21 | WmiEvent (WmiEventConsumerToFilter activity detected) | ❓ | -| 22 | DNSEvent (DNS query) | ✖ | -| 23 | FileDelete (File Delete archived) | ❓ | -| 24 | ClipboardChange (New content in the clipboard) | ❓ | -| 25 | ProcessTampering (Process image change) | ❓ | -| 26 | FileDeleteDetected (File Delete logged) | ❓ | -| 27 | FileBlockExecutable | ❓ | -| 28 | FileBlockShredding | ❓ | -| 29 | FileExecutableDetected | ❓ | -| 255 | Error | ✖ | - -## Process creation (1) - -Cover by other tools like Atomic RedTeam - -## process changed a file creation time (2) - -Need to see its usefulness - -## Network connection (3) - -Cover by other tools like Atomic RedTeam - -## Sysmon service state changed (4) - -Need to see its usefulness - -## Process terminated (5) - -Cover by other tools like Atomic RedTeam - -## Driver loaded (6) - -Done by the option X - -## Image loaded (7) - -Need to see its usefulness - -## CreateRemoteThread (8) - -Need to see its usefulness - -## RawAccessRead (9) - -Need to see its usefulness - -## ProcessAccess (10) - -Need to see its usefulness - -## FileCreate (11) - -Done by the option X - -## RegistryEvent (12,13,14) - -Cover by other tools like Atomic RedTeam - -## FileCreateStreamHash (15) - -Done but get a bug when in Sysmon to validate - -## ServiceConfigurationChange (16) - -Need to see its usefulness - -## PipeEvent (17,18) - -Only Pipe Created , no Pipe Connected - -## WmiEvent (19,20,21) - -Need to see its usefulness - -## DNSEvent (22) - -Cover by other tools like Atomic RedTeam - -## FileDelete (23) - -Need to see its usefulness - -## ClipboardChange (24) - -Need to see its usefulness - -## ProcessTampering (25) - -Need to see its usefulness - -## FileDeleteDetected (26) - -Need to see its usefulness - -## FileBlockExecutable (27) - -Need to see its usefulness - -## FileBlockShredding (28) - -Need to see its usefulness - -## FileExecutableDetected (29) - -Need to see its usefulness - -## Error (255) - -Need to see its usefulness - -# Windows builtin Channel - -- code_integrity when use driver option diff --git a/docs/cli_help.md b/docs/cli_help.md deleted file mode 100644 index 07bcb0c..0000000 --- a/docs/cli_help.md +++ /dev/null @@ -1,109 +0,0 @@ - - -# Ads - -`wag ads -f fullpath -a ads -d data` - -- fullpath: regex of the full path -- ads: name of the stream -- data: base64 of the data to write - -| Type | ads | data | -| -------------- | --------------- | -------------------------------------------------------------------------------------------- | -| ZoneTransfer 0 | Zone.Identifier | W1pvbmVUcmFuc2Zlcl0NClpvbmVJZD0wDQpSZWZlcnJlclVybD1jOlx3aW5kb3dzXHdhZy56aXANCg== | -| ZoneTransfer 1 | Zone.Identifier | W1pvbmVUcmFuc2Zlcl0NClpvbmVJZD0xDQpSZWZlcnJlclVybD0vL3N2cl9BRC93YWcuemlwDQo= | -| ZoneTransfer 2 | Zone.Identifier | W1pvbmVUcmFuc2Zlcl0NClpvbmVJZD0yDQpSZWZlcnJlclVybD1odHRwOi8vbXlzaXRlLm9yZy93YWcuemlwDQo= | -| ZoneTransfer 3 | Zone.Identifier | W1pvbmVUcmFuc2Zlcl0NClpvbmVJZD0zDQpSZWZlcnJlclVybD1odHRwczovL3NvbWVzaXRlLmNvbS93YWcuemlwDQo= | -| ZoneTransfer 4 | Zone.Identifier | W1pvbmVUcmFuc2Zlcl0NClpvbmVJZD00DQpSZWZlcnJlclVybD1odHRwOi8vbWFsd2FyZS5iYWQvd2FnLnppcA0K | -| Sysmon | sysmon | SSBhbSB0aGUgYmVzdCB0byBoaWRlIGZyb20gc3lzbW9u | - -# File - -## magicbytes - -| Type | Hex | -| ---- | ------------------------------------ | -| Exe | TVo= | -| Zip | UEsDBA== | -| Vmdk | S0RN | -| Iso | Q0QwMDE= | -| Txt | QSBzaW1wbGUgdGV4dCBmaWxl | -| Ps1 | d3JpdGUtaG9zdCAiV0FHIHdhcyBIZXJlIgo= | - -## well known File - -`wag file-create -f fullpath -m Magicbyte_Hex ` - -- fullpath: regex of the full path -- Magicbyte_Hex: base64 of the magicbytes to write -- admin: can use `--admin` to check if run as administrator - -| Type | Admin | Magicbyte | fullpath | -| -------------- | ----- | --------- | ------------------------------------------------------- | -| NPPSpy | true | Exe | `C:/Windows/System32/NPPSpy\.dll` | -| SafetyKatz | false | Zip | _SystemRoot_ + `Temp\\debug\.bin` | -| SmallSieve_txt | false | Txt | _LocalAppData_ + `MicrosoftWindowsOutlookDataPlus\.txt` | -| SmallSieve_exe | false | Exe | _AppData_ + `OutlookMicrosift\\index\.exe` | -| SNAKE_jpsetup | false | Exe | _TEMP_ + `jpsetup\.exe` | -| SNAKE_jpinst | false | Exe | _TEMP_ + `jpinst\\.exe` | -| SNAKE_Comadmin | true | Exe | `C:\\Windows\\System32\\Com\\Comadmin\.dat` | -| COLDSTEEL_exe | false | Exe | `C:\\users\\public\\Documents\\dllhost\.exe` | -| COLDSTEEL_dll | false | Exe | _APPDATA_ + `newdev\.dll` | -| temp_ps1_12 | false | Ps1 | _SystemRoot_ + `temp\[0-9a-f]{12}\.ps1` | - -Remark: You need to convert the environment variable into a correct regular expression. - -# Named pipe - -`wag name-pipe -n name` - -- name: named pipe name as a regex - -| Type | name | -| ------------------ | -------------------------------------------------- | -| CSExec | `\\csexecsvc` | -| psexec | `\\psexec` | -| psexec | `\\PAExec` | -| psexec | `\\remcom` | -| psexec | `\\csexec` | -| psexec | `\\PSEXESVC` | -| Cobal_strike | `\\wkssvc_?[0-9a-f]{2}` | -| Cobal_strike | `\\ntsvcs[0-9a-f]{2}` | -| Cobal_strike | `\\DserNamePipe[0-9a-f]{2}` | -| Cobal_strike | `\\SearchTextHarvester[0-9a-f]{2}` | -| Cobal_strike | `\\windows\\.update\\.manager[0-9a-f]{2,3}` | -| Cobal_strike | `\\ntsvcs_[0-9a-f]{2}` | -| Cobal_strike | `\\scerpc_?[0-9a-f]{2}` | -| Cobal_strike | `\\PGMessagePipe[0-9a-f]{2}` | -| Cobal_strike | `\\MsFteWds[0-9a-f]{2}` | -| Cobal_strike | `\\f4c3[0-9a-f]{2}` | -| Cobal_strike | `\\fullduplex_[0-9a-f]{2}` | -| Cobal_strike | `\\msrpc_[0-9a-f]{4}` | -| Cobal_strike | `\\win\\msrpc_[0-9a-f]{2}` | -| Cobal_strike | `\\f53f[0-9a-f]{2}` | -| Cobal_strike | `\\rpc_[0-9a-f]{2}` | -| Cobal_strike | `\\spoolss_[0-9a-f]{2}` | -| Cobal_strike | `\\Winsock2\\CatalogChangeListener-[0-9a-f]{3}-0,` | -| DiagTrackEoP | `thisispipe` | -| EfsPotato | `\\pipe\\srvsvc` | -| Credential_Dumping | `\\cachedump` | -| Credential_Dumping | `\\lsadump` | -| Credential_Dumping | `\\wceservicepipe` | -| Koh | `\\imposecost` | -| Koh | `\\imposingcost` | -| PowerShell | `\\PSHost` | -| ADFS | `\\MICROSOFT##WID\\tsql\\query` | - -# Mutex - -`wag mutex -n name` - -- name: mutex name as a regex - -| Type | name | -| ---------- | ------------------ | -| avoslocker | `Cheic0WaZie6zeiy` | From d1cd621691368ba2b2a3bd20941fa147b36bd992 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 8 Sep 2024 13:52:31 +0200 Subject: [PATCH 02/22] =?UTF-8?q?refactor:=20=F0=9F=94=A8=20Change=20help?= =?UTF-8?q?=20of=20the=20spoofing=20action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/processes/spoofing.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/actions/processes/spoofing.rs b/src/actions/processes/spoofing.rs index fab6f85..23f2055 100644 --- a/src/actions/processes/spoofing.rs +++ b/src/actions/processes/spoofing.rs @@ -40,18 +40,13 @@ use windows::{ #[derive(Debug, Parser)] pub struct Spoofing { - #[clap( - short = 'e', - long, - required = true, - help = "Full path to the executable eg: c:\\temp..." - )] + #[clap(short = 'e', long, required = true, help = "Path to the executable")] executable: String, #[clap( short = 'p', long, required = true, - help = "Full path to the parent executable eg: c:\\temp..." + help = "Name of the parent executable" )] parent_executable: String, } From d2ce3fd404d6b678bb85ff9c70a43bbe23990ecb Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 8 Sep 2024 15:51:17 +0200 Subject: [PATCH 03/22] =?UTF-8?q?refactor:=20=F0=9F=94=A8=20Move=20get=20p?= =?UTF-8?q?id=20function=20to=20the=20windows=20folder=20because=20it's=20?= =?UTF-8?q?a=20general=20thing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/processes/spoofing.rs | 67 ++----------------------------- src/windows.rs | 1 + src/windows/processes.rs | 64 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 63 deletions(-) create mode 100644 src/windows/processes.rs diff --git a/src/actions/processes/spoofing.rs b/src/actions/processes/spoofing.rs index 23f2055..bac5798 100644 --- a/src/actions/processes/spoofing.rs +++ b/src/actions/processes/spoofing.rs @@ -6,27 +6,15 @@ // // Last update 20240224 -use crate::actions::Runnable; +use crate::{actions::Runnable, windows::processes::get_pid}; use clap::Parser; use core::ffi::c_void; -use std::{ - error::Error, - ffi::OsString, - fmt::{Display, Formatter, Result as FormatterResult}, - mem::size_of, - os::windows::ffi::OsStringExt, - thread, - time::Duration, -}; +use std::{error::Error, mem::size_of, thread, time::Duration}; use windows::{ - core::{Owned, PSTR}, + core::PSTR, Win32::{ Foundation::{CloseHandle, HANDLE}, System::{ - Diagnostics::ToolHelp::{ - CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W, - TH32CS_SNAPPROCESS, - }, Memory::{GetProcessHeap, HeapAlloc, HEAP_FLAGS}, Threading::{ CreateProcessA, InitializeProcThreadAttributeList, OpenProcess, TerminateProcess, @@ -51,50 +39,6 @@ pub struct Spoofing { parent_executable: String, } -#[derive(Debug)] -struct ProcessNotFound; - -impl Error for ProcessNotFound {} - -impl Display for ProcessNotFound { - fn fmt(&self, formatter: &mut Formatter) -> FormatterResult { - write!(formatter, "Process not found") - } -} - -fn get_pid_from_name(name: &str) -> Result> { - let snapshot: Owned = - unsafe { Owned::new(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)?) }; - let mut process_entry: PROCESSENTRY32W = PROCESSENTRY32W { - dwSize: size_of::() as u32, - ..Default::default() - }; - - unsafe { - Process32FirstW(*snapshot, &mut process_entry)?; - } - - loop { - if OsString::from_wide( - process_entry - .szExeFile - .into_iter() - .take_while(|&byte| byte != 0) - .collect::>() - .as_slice(), - ) == name - { - return Ok(process_entry.th32ProcessID); - } - - if unsafe { Process32NextW(*snapshot, &mut process_entry) }.is_err() { - break; - } - } - - Err(Box::new(ProcessNotFound)) -} - fn create_ppid(name: &String, new_ppid: u32) -> bool { println!("Use the PPID {}", new_ppid); println!("Open the Parent Process"); @@ -170,10 +114,7 @@ impl Runnable for Spoofing { /* Version 20240209 */ fn run(&self) -> Result> { println!("PPID spoofing"); - let result: bool = create_ppid( - &self.executable, - get_pid_from_name(&self.parent_executable)?, - ); + let result: bool = create_ppid(&self.executable, get_pid(&self.parent_executable)?); Ok(!result as i32) } diff --git a/src/windows.rs b/src/windows.rs index 3ac4988..3a99ec0 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -2,4 +2,5 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +pub mod processes; pub mod users; diff --git a/src/windows/processes.rs b/src/windows/processes.rs new file mode 100644 index 0000000..1c76284 --- /dev/null +++ b/src/windows/processes.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2023 The WAG development team +// +// SPDX-License-Identifier: GPL-3.0-or-later + +use std::{ + error::Error, + ffi::OsString, + fmt::{Display, Formatter, Result as FormatterResult}, + os::windows::ffi::OsStringExt, +}; +use windows::{ + core::Owned, + Win32::{ + Foundation::HANDLE, + System::Diagnostics::ToolHelp::{ + CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W, + TH32CS_SNAPPROCESS, + }, + }, +}; + +#[derive(Debug)] +pub struct ProcessNotFound; + +impl Error for ProcessNotFound {} + +impl Display for ProcessNotFound { + fn fmt(&self, formatter: &mut Formatter) -> FormatterResult { + write!(formatter, "ProcessNotFound") + } +} + +pub fn get_pid(name: &str) -> Result> { + let snapshot: Owned = + unsafe { Owned::new(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)?) }; + let mut process_entry: PROCESSENTRY32W = PROCESSENTRY32W { + dwSize: size_of::() as u32, + ..Default::default() + }; + + unsafe { + Process32FirstW(*snapshot, &mut process_entry)?; + } + + loop { + if OsString::from_wide( + process_entry + .szExeFile + .into_iter() + .take_while(|&byte| byte != 0) + .collect::>() + .as_slice(), + ) == name + { + return Ok(process_entry.th32ProcessID); + } + + if unsafe { Process32NextW(*snapshot, &mut process_entry) }.is_err() { + break; + } + } + + Err(Box::new(ProcessNotFound)) +} From 21f325392f0229a4736226441ed8b638f8eb3aac Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 15 Sep 2024 21:56:50 +0200 Subject: [PATCH 04/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Rewrite=20spoofing=20?= =?UTF-8?q?and=20don't=20close=20the=20process=20that=20was=20created?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/processes/spoofing.rs | 128 +++++++++++++----------------- 1 file changed, 56 insertions(+), 72 deletions(-) diff --git a/src/actions/processes/spoofing.rs b/src/actions/processes/spoofing.rs index bac5798..1d14721 100644 --- a/src/actions/processes/spoofing.rs +++ b/src/actions/processes/spoofing.rs @@ -2,26 +2,18 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -// PPID Spoofing -// -// Last update 20240224 - use crate::{actions::Runnable, windows::processes::get_pid}; use clap::Parser; -use core::ffi::c_void; -use std::{error::Error, mem::size_of, thread, time::Duration}; +use std::{error::Error, ffi::OsString, iter::once, mem::size_of, os::windows::ffi::OsStrExt}; use windows::{ - core::PSTR, + core::{Owned, PCWSTR, PWSTR}, Win32::{ - Foundation::{CloseHandle, HANDLE}, - System::{ - Memory::{GetProcessHeap, HeapAlloc, HEAP_FLAGS}, - Threading::{ - CreateProcessA, InitializeProcThreadAttributeList, OpenProcess, TerminateProcess, - UpdateProcThreadAttribute, WaitForSingleObject, LPPROC_THREAD_ATTRIBUTE_LIST, - PROCESS_ACCESS_RIGHTS, PROCESS_CREATION_FLAGS, PROCESS_INFORMATION, - PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, STARTF_USESHOWWINDOW, STARTUPINFOEXA, - }, + Foundation::HANDLE, + System::Threading::{ + CreateProcessW, InitializeProcThreadAttributeList, OpenProcess, + UpdateProcThreadAttribute, EXTENDED_STARTUPINFO_PRESENT, LPPROC_THREAD_ATTRIBUTE_LIST, + PROCESS_INFORMATION, PROCESS_SET_INFORMATION, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + STARTUPINFOEXW, STARTUPINFOW, }, }, }; @@ -39,83 +31,75 @@ pub struct Spoofing { parent_executable: String, } -fn create_ppid(name: &String, new_ppid: u32) -> bool { - println!("Use the PPID {}", new_ppid); - println!("Open the Parent Process"); - let mut parent_process_handle: HANDLE = - unsafe { OpenProcess(PROCESS_ACCESS_RIGHTS(0x02000000), false, new_ppid).unwrap() }; +fn spoof(executable: &str, parent_pid: u32) -> Result<(), Box> { + let mut required_size: usize = 0; - let mut pi: PROCESS_INFORMATION = PROCESS_INFORMATION::default(); - let mut sinfo: STARTUPINFOEXA = STARTUPINFOEXA::default(); - let mut cb_attribute_list_size: usize = size_of::(); - sinfo.StartupInfo.cb = cb_attribute_list_size as u32; - sinfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; + unsafe { + let _ = InitializeProcThreadAttributeList( + LPPROC_THREAD_ATTRIBUTE_LIST::default(), + 1, + 0, + &mut required_size, + ); + }; - println!("allocate memory for PROC_THREAD_ATTRIBUTE_LIST"); - sinfo.lpAttributeList = LPPROC_THREAD_ATTRIBUTE_LIST(unsafe { - HeapAlloc( - GetProcessHeap().unwrap(), - HEAP_FLAGS(0), - cb_attribute_list_size, - ) - }); + let mut attributes: Box<[u8]> = vec![0; required_size].into_boxed_slice(); + let startup_informations: STARTUPINFOEXW = STARTUPINFOEXW { + StartupInfo: STARTUPINFOW { + cb: size_of::() as u32, + ..Default::default() + }, + lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST(attributes.as_mut_ptr() as *mut _), + }; - println!("InitializeProcThreadAttributeList"); unsafe { - InitializeProcThreadAttributeList(sinfo.lpAttributeList, 1, 0, &mut cb_attribute_list_size) - .unwrap() - }; + InitializeProcThreadAttributeList( + startup_informations.lpAttributeList, + 1, + 0, + &mut required_size, + )?; - println!("UpdateProcThreadAttribute"); - let _ = unsafe { UpdateProcThreadAttribute( - sinfo.lpAttributeList, + startup_informations.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as usize, - Some(&mut parent_process_handle as *mut _ as *mut c_void), + Some( + &mut *Owned::new(OpenProcess(PROCESS_SET_INFORMATION, false, parent_pid)?) as *mut _ + as *mut _, + ), size_of::(), None, None, - ) - }; + )?; - println!("CreateProcessA"); - let process_name = format!("{}\0", name); - let new_process = unsafe { - CreateProcessA( - None, - PSTR::from_raw(process_name.to_owned().as_mut_ptr()), + CreateProcessW( + PCWSTR::null(), + PWSTR( + OsString::from(executable) + .encode_wide() + .chain(once(0)) + .collect::>() + .as_mut_ptr(), + ), None, None, false, - PROCESS_CREATION_FLAGS(0x00080000), + EXTENDED_STARTUPINFO_PRESENT, None, - None, - &sinfo.StartupInfo, - &mut pi, - ) + PCWSTR::null(), + &startup_informations.StartupInfo, + &mut PROCESS_INFORMATION::default(), + )? }; - match new_process { - Ok(_) => { - println!("New process is created with pid {:}", pi.dwProcessId); - let wait_duration: Duration = Duration::from_millis(2000); - thread::sleep(wait_duration); - let _ = unsafe { TerminateProcess(pi.hProcess, 0) }; - let _ = unsafe { WaitForSingleObject(pi.hProcess, 5000) }; - let _ = unsafe { CloseHandle(pi.hProcess) }; - let _ = unsafe { CloseHandle(pi.hThread) }; - true - } - Err(_) => false, - } + + Ok(()) } impl Runnable for Spoofing { - /* Version 20240209 */ fn run(&self) -> Result> { - println!("PPID spoofing"); - let result: bool = create_ppid(&self.executable, get_pid(&self.parent_executable)?); + spoof(&self.executable, get_pid(&self.parent_executable)?)?; - Ok(!result as i32) + Ok(0) } } From 2084ceb6b7635171cabcd293323d8b271cf8d9b1 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 15 Sep 2024 22:06:49 +0200 Subject: [PATCH 05/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Fix=20the=20message?= =?UTF-8?q?=20shown=20for=20ProcessNotFound?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/windows/processes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows/processes.rs b/src/windows/processes.rs index 1c76284..ed28add 100644 --- a/src/windows/processes.rs +++ b/src/windows/processes.rs @@ -26,7 +26,7 @@ impl Error for ProcessNotFound {} impl Display for ProcessNotFound { fn fmt(&self, formatter: &mut Formatter) -> FormatterResult { - write!(formatter, "ProcessNotFound") + write!(formatter, "Process not found") } } From 94e2e842b822f4e2cda5449ba18af2a0f811f766 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 15 Sep 2024 22:16:33 +0200 Subject: [PATCH 06/22] =?UTF-8?q?refactor:=20=F0=9F=94=A8=20Use=20HSTRING?= =?UTF-8?q?=20instead=20of=20OsString?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use HSTRING when possible instead of OsString. HSTRING sometimes use OsString internally. If we have no other choice, we will use OsString and after that normal rust string --- src/windows/processes.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/windows/processes.rs b/src/windows/processes.rs index ed28add..9371c47 100644 --- a/src/windows/processes.rs +++ b/src/windows/processes.rs @@ -4,12 +4,10 @@ use std::{ error::Error, - ffi::OsString, fmt::{Display, Formatter, Result as FormatterResult}, - os::windows::ffi::OsStringExt, }; use windows::{ - core::Owned, + core::{Owned, HSTRING}, Win32::{ Foundation::HANDLE, System::Diagnostics::ToolHelp::{ @@ -43,14 +41,14 @@ pub fn get_pid(name: &str) -> Result> { } loop { - if OsString::from_wide( + if HSTRING::from_wide( process_entry .szExeFile .into_iter() .take_while(|&byte| byte != 0) .collect::>() .as_slice(), - ) == name + )? == name { return Ok(process_entry.th32ProcessID); } From eb903ab1d5200a202f613e5db0d18acccf157acf Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 15 Sep 2024 23:11:23 +0200 Subject: [PATCH 07/22] =?UTF-8?q?refactor:=20=F0=9F=94=A8=20Use=20None=20i?= =?UTF-8?q?nstead=20of=20an=20empty=20PCWSTR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use None when Param is asked and if we don't want to use this parameter. It will be converted automatically --- src/actions/processes/spoofing.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/actions/processes/spoofing.rs b/src/actions/processes/spoofing.rs index 1d14721..1c8a3ad 100644 --- a/src/actions/processes/spoofing.rs +++ b/src/actions/processes/spoofing.rs @@ -6,7 +6,7 @@ use crate::{actions::Runnable, windows::processes::get_pid}; use clap::Parser; use std::{error::Error, ffi::OsString, iter::once, mem::size_of, os::windows::ffi::OsStrExt}; use windows::{ - core::{Owned, PCWSTR, PWSTR}, + core::{Owned, PWSTR}, Win32::{ Foundation::HANDLE, System::Threading::{ @@ -74,7 +74,7 @@ fn spoof(executable: &str, parent_pid: u32) -> Result<(), Box> { )?; CreateProcessW( - PCWSTR::null(), + None, PWSTR( OsString::from(executable) .encode_wide() @@ -87,7 +87,7 @@ fn spoof(executable: &str, parent_pid: u32) -> Result<(), Box> { false, EXTENDED_STARTUPINFO_PRESENT, None, - PCWSTR::null(), + None, &startup_informations.StartupInfo, &mut PROCESS_INFORMATION::default(), )? From 2697d8670cb139d5cc89599c760c2a0f45e92dea Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Mon, 16 Sep 2024 15:05:14 +0200 Subject: [PATCH 08/22] =?UTF-8?q?refactor:=20=F0=9F=94=A8=20Return=20Resul?= =?UTF-8?q?t=20directly=20and=20remove=20all=20exit=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because Result implements Terminaison trait, the cli will return the right exit code --- src/actions.rs | 4 ++-- src/actions/ads.rs | 2 +- src/actions/ads/create.rs | 6 +++--- src/actions/drivers.rs | 2 +- src/actions/drivers/create.rs | 6 +++--- src/actions/files.rs | 2 +- src/actions/files/create.rs | 6 +++--- src/actions/mutexes.rs | 2 +- src/actions/mutexes/create.rs | 4 ++-- src/actions/pipes.rs | 2 +- src/actions/pipes/create.rs | 4 ++-- src/actions/processes.rs | 2 +- src/actions/processes/spoofing.rs | 6 ++---- src/main.rs | 16 +++++----------- 14 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/actions.rs b/src/actions.rs index ebc5141..0e7f704 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -33,11 +33,11 @@ pub enum Commands { } pub trait Runnable { - fn run(&self) -> Result>; + fn run(&self) -> Result<(), Box>; } impl Runnable for Actions { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { match &self.command { Commands::AlternateDataStreams(alternate_data_streams) => { alternate_data_streams as &dyn Runnable diff --git a/src/actions/ads.rs b/src/actions/ads.rs index 004c48f..57bd700 100644 --- a/src/actions/ads.rs +++ b/src/actions/ads.rs @@ -20,7 +20,7 @@ pub enum Commands { } impl Runnable for AlternateDataStreams { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { match &self.command { Commands::Create(create) => create as &dyn Runnable, } diff --git a/src/actions/ads/create.rs b/src/actions/ads/create.rs index bf29a46..072ca1f 100644 --- a/src/actions/ads/create.rs +++ b/src/actions/ads/create.rs @@ -64,7 +64,7 @@ fn create_ads(fullpath: String, adsname: String, hex_data: Vec) -> bool { impl Runnable for Create { /* Version 20230908 */ - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { println!("Alternate Data Stream"); if !self.filename.is_empty() { @@ -77,9 +77,9 @@ impl Runnable for Create { let payload: Vec = general_purpose::STANDARD.decode(self.data.as_str())?; let ret_ads: bool = create_ads(fullname, barrow_ads, payload); - return Ok(!ret_ads as i32); + return Ok(()); } - Ok(1) + Ok(()) } } diff --git a/src/actions/drivers.rs b/src/actions/drivers.rs index 03344c5..0c17673 100644 --- a/src/actions/drivers.rs +++ b/src/actions/drivers.rs @@ -20,7 +20,7 @@ pub enum Commands { } impl Runnable for Drivers { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { match &self.command { Commands::Create(create) => create as &dyn Runnable, } diff --git a/src/actions/drivers/create.rs b/src/actions/drivers/create.rs index 566d299..80a85bb 100644 --- a/src/actions/drivers/create.rs +++ b/src/actions/drivers/create.rs @@ -114,18 +114,18 @@ fn create_driver_service(name: &str, details: &str, path: &str) -> bool { impl Runnable for Create { /* Version 20230908 */ - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { println!("Bring Your Own Vulnerable Driver"); if !is_administrator()? { println!("Need to have Administrator right to create the service"); - return Ok(1); + return Ok(()); } // Todo check path is valid or not :) let result: bool = create_driver_service(&self.internal, &self.display, &self.path); - Ok(!result as i32) + Ok(()) } } diff --git a/src/actions/files.rs b/src/actions/files.rs index 5a7073e..b908c7a 100644 --- a/src/actions/files.rs +++ b/src/actions/files.rs @@ -20,7 +20,7 @@ pub enum Commands { } impl Runnable for Files { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { match &self.command { Commands::Create(create) => create as &dyn Runnable, } diff --git a/src/actions/files/create.rs b/src/actions/files/create.rs index b05a584..bc1f903 100644 --- a/src/actions/files/create.rs +++ b/src/actions/files/create.rs @@ -90,10 +90,10 @@ fn create_file(fullpath: String, hex_data: Vec) -> bool { } impl Runnable for Create { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { if self.admin && !is_administrator()? { println!("Need to have Administrator right to create the file"); - return Ok(1); + return Ok(()); } let mut generator: Generator = @@ -107,6 +107,6 @@ impl Runnable for Create { let payload: Vec = general_purpose::STANDARD.decode(self.magicbyte.as_str())?; let ret: bool = create_file(fullname, payload); - Ok(!ret as i32) + Ok(()) } } diff --git a/src/actions/mutexes.rs b/src/actions/mutexes.rs index 3085d41..e51e2ba 100644 --- a/src/actions/mutexes.rs +++ b/src/actions/mutexes.rs @@ -20,7 +20,7 @@ pub enum Commands { } impl Runnable for Mutexes { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { match &self.command { Commands::Create(create) => create as &dyn Runnable, } diff --git a/src/actions/mutexes/create.rs b/src/actions/mutexes/create.rs index 559b947..986b1af 100644 --- a/src/actions/mutexes/create.rs +++ b/src/actions/mutexes/create.rs @@ -39,7 +39,7 @@ fn create_mutex(name: &String, wait: u64) { } impl Runnable for Create { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { println!("Create Mutex"); let mut generator: Generator = @@ -52,6 +52,6 @@ impl Runnable for Create { create_mutex(&payload, 2000); - Ok(0) + Ok(()) } } diff --git a/src/actions/pipes.rs b/src/actions/pipes.rs index 502c2f2..061b810 100644 --- a/src/actions/pipes.rs +++ b/src/actions/pipes.rs @@ -20,7 +20,7 @@ pub enum Commands { } impl Runnable for Pipes { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { match &self.command { Commands::Create(create) => create as &dyn Runnable, } diff --git a/src/actions/pipes/create.rs b/src/actions/pipes/create.rs index cf20cec..e42ab4c 100644 --- a/src/actions/pipes/create.rs +++ b/src/actions/pipes/create.rs @@ -51,7 +51,7 @@ fn create_name_pipe(name: &String, wait: u64) { } impl Runnable for Create { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { println!("Create NamePipe"); let mut generator: Generator = @@ -64,6 +64,6 @@ impl Runnable for Create { create_name_pipe(&payload, 2000); - Ok(0) + Ok(()) } } diff --git a/src/actions/processes.rs b/src/actions/processes.rs index 76452ac..0cbdf3d 100644 --- a/src/actions/processes.rs +++ b/src/actions/processes.rs @@ -20,7 +20,7 @@ pub enum Commands { } impl Runnable for Processes { - fn run(&self) -> Result> { + fn run(&self) -> Result<(), Box> { match &self.command { Commands::Spoofing(spoofing) => spoofing as &dyn Runnable, } diff --git a/src/actions/processes/spoofing.rs b/src/actions/processes/spoofing.rs index 1c8a3ad..d3d12f1 100644 --- a/src/actions/processes/spoofing.rs +++ b/src/actions/processes/spoofing.rs @@ -97,9 +97,7 @@ fn spoof(executable: &str, parent_pid: u32) -> Result<(), Box> { } impl Runnable for Spoofing { - fn run(&self) -> Result> { - spoof(&self.executable, get_pid(&self.parent_executable)?)?; - - Ok(0) + fn run(&self) -> Result<(), Box> { + Ok(spoof(&self.executable, get_pid(&self.parent_executable)?)?) } } diff --git a/src/main.rs b/src/main.rs index b167f6b..d18c9a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ mod windows; use actions::Runnable; use clap::Parser; use cli::{Arguments, Commands}; +use std::error::Error; fn banner() { let banner: &str = " @@ -23,17 +24,10 @@ fn banner() { println!("{}", banner); } -fn main() { +fn main() -> Result<(), Box> { banner(); - match Arguments::parse().command { - Commands::Actions(action) => match action.run() { - Ok(code) => std::process::exit(code), - Err(error) => { - println!("Error: {}", error); - - std::process::exit(1); - } - }, - }; + Ok(match Arguments::parse().command { + Commands::Actions(action) => action.run()?, + }) } From c1ca9beba8311dea10da9347dc92661edb718823 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Fri, 18 Oct 2024 23:09:15 +0200 Subject: [PATCH 09/22] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Fix=20PPID=20spoofi?= =?UTF-8?q?ng?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/processes/spoofing.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/actions/processes/spoofing.rs b/src/actions/processes/spoofing.rs index d3d12f1..988a0cf 100644 --- a/src/actions/processes/spoofing.rs +++ b/src/actions/processes/spoofing.rs @@ -12,7 +12,7 @@ use windows::{ System::Threading::{ CreateProcessW, InitializeProcThreadAttributeList, OpenProcess, UpdateProcThreadAttribute, EXTENDED_STARTUPINFO_PRESENT, LPPROC_THREAD_ATTRIBUTE_LIST, - PROCESS_INFORMATION, PROCESS_SET_INFORMATION, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + PROCESS_CREATE_PROCESS, PROCESS_INFORMATION, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, STARTUPINFOEXW, STARTUPINFOW, }, }, @@ -44,12 +44,17 @@ fn spoof(executable: &str, parent_pid: u32) -> Result<(), Box> { }; let mut attributes: Box<[u8]> = vec![0; required_size].into_boxed_slice(); + let attributes_list: Owned = unsafe { + Owned::new(LPPROC_THREAD_ATTRIBUTE_LIST( + attributes.as_mut_ptr() as *mut _ + )) + }; let startup_informations: STARTUPINFOEXW = STARTUPINFOEXW { StartupInfo: STARTUPINFOW { cb: size_of::() as u32, ..Default::default() }, - lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST(attributes.as_mut_ptr() as *mut _), + lpAttributeList: *attributes_list, }; unsafe { @@ -60,14 +65,13 @@ fn spoof(executable: &str, parent_pid: u32) -> Result<(), Box> { &mut required_size, )?; + let mut parent_process: Owned = + Owned::new(OpenProcess(PROCESS_CREATE_PROCESS, false, parent_pid)?); UpdateProcThreadAttribute( startup_informations.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as usize, - Some( - &mut *Owned::new(OpenProcess(PROCESS_SET_INFORMATION, false, parent_pid)?) as *mut _ - as *mut _, - ), + Some(&mut *parent_process as *mut _ as *mut _), size_of::(), None, None, @@ -90,7 +94,7 @@ fn spoof(executable: &str, parent_pid: u32) -> Result<(), Box> { None, &startup_informations.StartupInfo, &mut PROCESS_INFORMATION::default(), - )? + )?; }; Ok(()) From 8efa812baef344c1fb244eee896c654c6d05f56d Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sat, 19 Oct 2024 15:33:58 +0200 Subject: [PATCH 10/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Remove=20traces=20tha?= =?UTF-8?q?t=20are=20too=20specific?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions.rs | 21 +------ src/actions/ads.rs | 29 --------- src/actions/ads/create.rs | 85 -------------------------- src/actions/files.rs | 29 --------- src/actions/files/create.rs | 112 ---------------------------------- src/actions/mutexes.rs | 29 --------- src/actions/mutexes/create.rs | 57 ----------------- src/actions/pipes.rs | 29 --------- src/actions/pipes/create.rs | 69 --------------------- 9 files changed, 2 insertions(+), 458 deletions(-) delete mode 100644 src/actions/ads.rs delete mode 100644 src/actions/ads/create.rs delete mode 100644 src/actions/files.rs delete mode 100644 src/actions/files/create.rs delete mode 100644 src/actions/mutexes.rs delete mode 100644 src/actions/mutexes/create.rs delete mode 100644 src/actions/pipes.rs delete mode 100644 src/actions/pipes/create.rs diff --git a/src/actions.rs b/src/actions.rs index 0e7f704..0f613c2 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -2,18 +2,11 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -use crate::actions::{ - ads::AlternateDataStreams, drivers::Drivers, files::Files, mutexes::Mutexes, pipes::Pipes, - processes::Processes, -}; +use crate::actions::{drivers::Drivers, processes::Processes}; use clap::{Args, Subcommand}; use std::error::Error; -pub mod ads; pub mod drivers; -pub mod files; -pub mod mutexes; -pub mod pipes; pub mod processes; #[derive(Debug, Args)] @@ -24,11 +17,7 @@ pub struct Actions { #[derive(Debug, Subcommand)] pub enum Commands { - AlternateDataStreams(AlternateDataStreams), Drivers(Drivers), - Files(Files), - Mutexes(Mutexes), - Pipes(Pipes), Processes(Processes), } @@ -39,13 +28,7 @@ pub trait Runnable { impl Runnable for Actions { fn run(&self) -> Result<(), Box> { match &self.command { - Commands::AlternateDataStreams(alternate_data_streams) => { - alternate_data_streams as &dyn Runnable - } - Commands::Drivers(drivers) => drivers, - Commands::Files(files) => files, - Commands::Mutexes(mutexes) => mutexes, - Commands::Pipes(pipes) => pipes, + Commands::Drivers(drivers) => drivers as &dyn Runnable, Commands::Processes(processes) => processes, } .run() diff --git a/src/actions/ads.rs b/src/actions/ads.rs deleted file mode 100644 index 57bd700..0000000 --- a/src/actions/ads.rs +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The WAG development team -// -// SPDX-License-Identifier: GPL-3.0-or-later - -use crate::actions::{ads::create::Create, Runnable}; -use clap::{Args, Subcommand}; -use std::error::Error; - -pub mod create; - -#[derive(Debug, Args)] -pub struct AlternateDataStreams { - #[clap(subcommand)] - pub command: Commands, -} - -#[derive(Debug, Subcommand)] -pub enum Commands { - Create(Create), -} - -impl Runnable for AlternateDataStreams { - fn run(&self) -> Result<(), Box> { - match &self.command { - Commands::Create(create) => create as &dyn Runnable, - } - .run() - } -} diff --git a/src/actions/ads/create.rs b/src/actions/ads/create.rs deleted file mode 100644 index 072ca1f..0000000 --- a/src/actions/ads/create.rs +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The WAG development team -// -// SPDX-License-Identifier: GPL-3.0-or-later - -// Alternate Data Stream -// -// Last update 20240224 - -use crate::actions::Runnable; -use base64::engine::{general_purpose, Engine}; -use clap::Parser; -use regex_generate::{Generator, DEFAULT_MAX_REPEAT}; -use std::{error::Error, path::Path}; - -#[derive(Debug, Parser)] -pub struct Create { - #[clap( - short = 'f', - long, - required = true, - help = "Full path filename (regex)" - )] - filename: String, - #[clap(short = 'a', long, required = true, help = "ADS to use")] - ads: String, - #[clap( - short = 'd', - long, - required = false, - default_value = "V2VsY29tZSB0byB0aGUgV0FH", - help = "Data to write in base64" - )] - data: String, -} - -fn create_ads(fullpath: String, adsname: String, hex_data: Vec) -> bool { - let file_base: &Path = Path::new(&fullpath); - if !file_base.exists() { - println!("Missing base file for ADS, try to create it"); - let folder: &Path = file_base.parent().unwrap(); - - let ret_folder: Result<(), std::io::Error> = std::fs::create_dir_all(folder); - match ret_folder { - Ok(_) => println!("The folder is valid"), - Err(_) => return false, - } - let ret_file: Result<(), std::io::Error> = std::fs::write( - file_base, - vec![ - 87, 105, 110, 100, 111, 119, 115, 32, 65, 114, 116, 101, 102, 97, 99, 116, 32, 71, - 101, 110, 101, 114, 97, 116, 111, 114, - ], - ); - match ret_file { - Ok(_) => println!("The base file is created"), - Err(_) => return false, - } - } - let full_ads_name: String = format!("{}:{}", fullpath, adsname); - let file_ads: &Path = Path::new(&full_ads_name); - let ret_file: Result<(), std::io::Error> = std::fs::write(file_ads, hex_data); - ret_file.is_ok() -} - -impl Runnable for Create { - /* Version 20230908 */ - fn run(&self) -> Result<(), Box> { - println!("Alternate Data Stream"); - - if !self.filename.is_empty() { - let mut generator: Generator = - Generator::new(&self.filename, rand::thread_rng(), DEFAULT_MAX_REPEAT)?; - let mut buffer: Vec = vec![]; - generator.generate(&mut buffer).unwrap(); - let fullname: String = String::from_utf8(buffer)?; - let barrow_ads: String = self.ads.to_string(); - let payload: Vec = general_purpose::STANDARD.decode(self.data.as_str())?; - let ret_ads: bool = create_ads(fullname, barrow_ads, payload); - - return Ok(()); - } - - Ok(()) - } -} diff --git a/src/actions/files.rs b/src/actions/files.rs deleted file mode 100644 index b908c7a..0000000 --- a/src/actions/files.rs +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The WAG development team -// -// SPDX-License-Identifier: GPL-3.0-or-later - -use crate::actions::{files::create::Create, Runnable}; -use clap::{Args, Subcommand}; -use std::error::Error; - -pub mod create; - -#[derive(Debug, Args)] -pub struct Files { - #[clap(subcommand)] - pub command: Commands, -} - -#[derive(Debug, Subcommand)] -pub enum Commands { - Create(Create), -} - -impl Runnable for Files { - fn run(&self) -> Result<(), Box> { - match &self.command { - Commands::Create(create) => create as &dyn Runnable, - } - .run() - } -} diff --git a/src/actions/files/create.rs b/src/actions/files/create.rs deleted file mode 100644 index bc1f903..0000000 --- a/src/actions/files/create.rs +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The WAG development team -// -// SPDX-License-Identifier: GPL-3.0-or-later - -/* - File creation Artefact - -the magic bytes and NTFS ADS are store a string HEX value. -like 504B0304 or 4D5A. - -Path are regex in json so need `\\.` to get a `.`. - -if fullpath is empty , it build the path from -env variable and the cmd_path. -"SystemRoot" "Temp\\debug\\.bin" will give "c:\Windows\Temp\debug.bin" - -You can use `SET | more` or `Get-ChildItem Env:` to get the list - -*/ - -use crate::{actions::Runnable, windows::users::is_administrator}; -use base64::engine::{general_purpose, Engine}; -use clap::Parser; -use regex_generate::{Generator, DEFAULT_MAX_REPEAT}; -use std::{ - error::Error, - io::Result as IOResult, - path::Path, - thread, - time::{self, Duration}, -}; - -#[derive(Debug, Parser)] -pub struct Create { - #[clap( - short = 'f', - long, - required = true, - help = "Full path filename (regex)" - )] - filename: String, - #[clap( - short = 'm', - long, - required = false, - default_value = "V2VsY29tZSB0byB0aGUgV0FH", - help = "MagicBytes name to use with module manual in base64" - )] - magicbyte: String, - #[clap( - short = 'a', - long, - required = false, - default_value_t = false, - help = "Need to be admin" - )] - admin: bool, -} - -fn create_file(fullpath: String, hex_data: Vec) -> bool { - println!("Try to create : {}", fullpath); - let file_path: &Path = Path::new(&fullpath); - if !file_path.exists() { - let folder: &Path = file_path.parent().unwrap(); - - let ret_folder: IOResult<()> = std::fs::create_dir_all(folder); - match ret_folder { - Ok(_) => println!("The folder is valid"), - Err(_) => return false, - } - - let ret_file: IOResult<()> = std::fs::write(file_path, hex_data); - match ret_file { - Ok(_) => println!("The file is created"), - Err(_) => return false, - } - - let sleep_duration: Duration = time::Duration::from_millis(2000); - thread::sleep(sleep_duration); - - let ret_remove: IOResult<()> = std::fs::remove_file(file_path); - match ret_remove { - Ok(_) => println!("The file is removed"), - Err(_) => return false, - } - - return true; - } - false -} - -impl Runnable for Create { - fn run(&self) -> Result<(), Box> { - if self.admin && !is_administrator()? { - println!("Need to have Administrator right to create the file"); - return Ok(()); - } - - let mut generator: Generator = - Generator::new(&self.filename, rand::thread_rng(), DEFAULT_MAX_REPEAT)?; - let mut buffer: Vec = vec![]; - generator.generate(&mut buffer).unwrap(); - let fullname: String = String::from_utf8(buffer)?; - - println!("Create a file on disk"); - - let payload: Vec = general_purpose::STANDARD.decode(self.magicbyte.as_str())?; - let ret: bool = create_file(fullname, payload); - - Ok(()) - } -} diff --git a/src/actions/mutexes.rs b/src/actions/mutexes.rs deleted file mode 100644 index e51e2ba..0000000 --- a/src/actions/mutexes.rs +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The WAG development team -// -// SPDX-License-Identifier: GPL-3.0-or-later - -use crate::actions::{mutexes::create::Create, Runnable}; -use clap::{Args, Subcommand}; -use std::error::Error; - -pub mod create; - -#[derive(Debug, Args)] -pub struct Mutexes { - #[clap(subcommand)] - pub command: Commands, -} - -#[derive(Debug, Subcommand)] -pub enum Commands { - Create(Create), -} - -impl Runnable for Mutexes { - fn run(&self) -> Result<(), Box> { - match &self.command { - Commands::Create(create) => create as &dyn Runnable, - } - .run() - } -} diff --git a/src/actions/mutexes/create.rs b/src/actions/mutexes/create.rs deleted file mode 100644 index 986b1af..0000000 --- a/src/actions/mutexes/create.rs +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The WAG development team -// -// SPDX-License-Identifier: GPL-3.0-or-later - -// Mutex -// -// Last update 20240224 - -use crate::actions::Runnable; -use clap::Parser; -use regex_generate::{Generator, DEFAULT_MAX_REPEAT}; -use std::{error::Error, thread, time}; -use windows::{ - core::{Result as WindowsResult, PCSTR}, - Win32::{ - Foundation::{CloseHandle, HANDLE}, - System::Threading::CreateMutexA, - }, -}; - -#[derive(Debug, Parser)] -pub struct Create { - #[clap( - short = 'n', - long, - required = true, - help = "Regex of the Mutex to Create" - )] - name: String, -} - -fn create_mutex(name: &String, wait: u64) { - let full_malware_mutex: String = format!("{}\0", name); - let mutex_name: PCSTR = PCSTR::from_raw(full_malware_mutex.as_ptr()); - let mutex_handle: WindowsResult = unsafe { CreateMutexA(None, true, mutex_name) }; - let sleep_duration: time::Duration = time::Duration::from_millis(wait); - thread::sleep(sleep_duration); - let _res_server_pipe: WindowsResult<()> = unsafe { CloseHandle(mutex_handle.unwrap()) }; -} - -impl Runnable for Create { - fn run(&self) -> Result<(), Box> { - println!("Create Mutex"); - - let mut generator: Generator = - Generator::new(&self.name, rand::thread_rng(), DEFAULT_MAX_REPEAT)?; - let mut buffer: Vec = vec![]; - generator.generate(&mut buffer).unwrap(); - let payload: String = String::from_utf8(buffer)?; - - println!("Create the Mutex : {}", payload); - - create_mutex(&payload, 2000); - - Ok(()) - } -} diff --git a/src/actions/pipes.rs b/src/actions/pipes.rs deleted file mode 100644 index 061b810..0000000 --- a/src/actions/pipes.rs +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The WAG development team -// -// SPDX-License-Identifier: GPL-3.0-or-later - -use crate::actions::{pipes::create::Create, Runnable}; -use clap::{Args, Subcommand}; -use std::error::Error; - -pub mod create; - -#[derive(Debug, Args)] -pub struct Pipes { - #[clap(subcommand)] - pub command: Commands, -} - -#[derive(Debug, Subcommand)] -pub enum Commands { - Create(Create), -} - -impl Runnable for Pipes { - fn run(&self) -> Result<(), Box> { - match &self.command { - Commands::Create(create) => create as &dyn Runnable, - } - .run() - } -} diff --git a/src/actions/pipes/create.rs b/src/actions/pipes/create.rs deleted file mode 100644 index e42ab4c..0000000 --- a/src/actions/pipes/create.rs +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The WAG development team -// -// SPDX-License-Identifier: GPL-3.0-or-later - -// Name Pipe -// -// Last update 20240224 - -use crate::actions::Runnable; -use clap::Parser; -use regex_generate::{Generator, DEFAULT_MAX_REPEAT}; -use std::{error::Error, thread, time}; -use windows::{ - core::{Result as WindowsResult, PCSTR}, - Win32::{ - Foundation::{CloseHandle, HANDLE}, - Storage::FileSystem::PIPE_ACCESS_DUPLEX, - System::Pipes::{CreateNamedPipeA, PIPE_TYPE_MESSAGE}, - }, -}; - -#[derive(Debug, Parser)] -pub struct Create { - #[clap( - short = 'n', - long, - required = true, - help = "Regex of the PipeName to Create" - )] - name: String, -} - -fn create_name_pipe(name: &String, wait: u64) { - let full_malware_pipe: String = format!("\\\\.\\pipe\\{}\0", name); - let pipe_name: PCSTR = PCSTR::from_raw(full_malware_pipe.as_ptr()); - let server_pipe: WindowsResult = unsafe { - CreateNamedPipeA( - pipe_name, - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE, - 1, - 2048, - 2048, - 0, - None, - ) - }; - let sleep_duration: time::Duration = time::Duration::from_millis(wait); - thread::sleep(sleep_duration); - let _res_server_pipe: WindowsResult<()> = unsafe { CloseHandle(server_pipe.unwrap()) }; -} - -impl Runnable for Create { - fn run(&self) -> Result<(), Box> { - println!("Create NamePipe"); - - let mut generator: Generator = - Generator::new(&self.name, rand::thread_rng(), DEFAULT_MAX_REPEAT)?; - let mut buffer: Vec = vec![]; - generator.generate(&mut buffer).unwrap(); - let payload: String = String::from_utf8(buffer)?; - - println!("Create the namepipe : {}", payload); - - create_name_pipe(&payload, 2000); - - Ok(()) - } -} From 20973b44b4919dbffad40c4db39ac367aaac17a3 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sat, 19 Oct 2024 15:42:56 +0200 Subject: [PATCH 11/22] =?UTF-8?q?refactor:=20=F0=9F=94=A8=20Rewrite=20"is?= =?UTF-8?q?=5Fadministrator"=20to=20use=20"Owned"=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/windows/users.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/windows/users.rs b/src/windows/users.rs index 272ae94..f7fa1c6 100644 --- a/src/windows/users.rs +++ b/src/windows/users.rs @@ -3,21 +3,19 @@ // SPDX-License-Identifier: GPL-3.0-or-later use windows::{ - core::Error as WindowsError, + core::{Owned, Result as WindowsResult}, Win32::{ - Foundation::BOOL, - Security::{ - AllocateAndInitializeSid, CheckTokenMembership, FreeSid, PSID, SECURITY_NT_AUTHORITY, - }, + Security::{AllocateAndInitializeSid, CheckTokenMembership, PSID, SECURITY_NT_AUTHORITY}, System::SystemServices::{DOMAIN_ALIAS_RID_ADMINS, SECURITY_BUILTIN_DOMAIN_RID}, }, }; -pub fn is_administrator() -> Result { - let is_admin: *mut BOOL = &mut BOOL::from(false); - let mut administrators_group: PSID = PSID::default(); +pub fn is_administrator() -> WindowsResult { + let mut is_admin: bool = false; unsafe { + let mut administrators_group: Owned = Owned::new(PSID::default()); + AllocateAndInitializeSid( &SECURITY_NT_AUTHORITY, 2, @@ -29,16 +27,15 @@ pub fn is_administrator() -> Result { 0, 0, 0, - &mut administrators_group, + &mut *administrators_group, )?; - let result: Result<(), WindowsError> = - CheckTokenMembership(None, administrators_group, is_admin); - - FreeSid(administrators_group); - - result?; + CheckTokenMembership( + None, + *administrators_group, + &mut is_admin as *mut _ as *mut _, + )?; } - Ok(unsafe { (*is_admin).into() }) + Ok(is_admin) } From 00476eff3400736b722e51bf3cda52f45470c78f Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sat, 19 Oct 2024 15:49:19 +0200 Subject: [PATCH 12/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Remove=20short=20and?= =?UTF-8?q?=20long=20for=20clap,=20make=20them=20arguments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/processes/spoofing.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/actions/processes/spoofing.rs b/src/actions/processes/spoofing.rs index 988a0cf..dfe16b2 100644 --- a/src/actions/processes/spoofing.rs +++ b/src/actions/processes/spoofing.rs @@ -20,14 +20,9 @@ use windows::{ #[derive(Debug, Parser)] pub struct Spoofing { - #[clap(short = 'e', long, required = true, help = "Path to the executable")] + #[clap(required = true, help = "Path to the executable")] executable: String, - #[clap( - short = 'p', - long, - required = true, - help = "Name of the parent executable" - )] + #[clap(required = true, help = "Name of the parent executable")] parent_executable: String, } From 533626418c456d4bf81fd106a97bed1abbba6b24 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sat, 19 Oct 2024 16:02:34 +0200 Subject: [PATCH 13/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Rename=20the=20trace?= =?UTF-8?q?=20accordingly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/drivers.rs | 8 ++++---- src/actions/drivers/{create.rs => byovd.rs} | 9 ++------- 2 files changed, 6 insertions(+), 11 deletions(-) rename src/actions/drivers/{create.rs => byovd.rs} (96%) diff --git a/src/actions/drivers.rs b/src/actions/drivers.rs index 0c17673..e168a21 100644 --- a/src/actions/drivers.rs +++ b/src/actions/drivers.rs @@ -2,11 +2,11 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -use crate::actions::{drivers::create::Create, Runnable}; +use crate::actions::{drivers::byovd::Byovd, Runnable}; use clap::{Args, Subcommand}; use std::error::Error; -pub mod create; +pub mod byovd; #[derive(Debug, Args)] pub struct Drivers { @@ -16,13 +16,13 @@ pub struct Drivers { #[derive(Debug, Subcommand)] pub enum Commands { - Create(Create), + Byovd(Byovd), } impl Runnable for Drivers { fn run(&self) -> Result<(), Box> { match &self.command { - Commands::Create(create) => create as &dyn Runnable, + Commands::Byovd(byovd) => byovd as &dyn Runnable, } .run() } diff --git a/src/actions/drivers/create.rs b/src/actions/drivers/byovd.rs similarity index 96% rename from src/actions/drivers/create.rs rename to src/actions/drivers/byovd.rs index 80a85bb..2309884 100644 --- a/src/actions/drivers/create.rs +++ b/src/actions/drivers/byovd.rs @@ -2,10 +2,6 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -// Load Vulnerable Driver -// -// Last update 20240224 - use crate::{actions::Runnable, windows::users::is_administrator}; use clap::Parser; use std::{error::Error, thread, time}; @@ -19,7 +15,7 @@ use windows::{ }; #[derive(Debug, Parser)] -pub struct Create { +pub struct Byovd { #[clap( short = 'n', long, @@ -112,8 +108,7 @@ fn create_driver_service(name: &str, details: &str, path: &str) -> bool { } } -impl Runnable for Create { - /* Version 20230908 */ +impl Runnable for Byovd { fn run(&self) -> Result<(), Box> { println!("Bring Your Own Vulnerable Driver"); From ae8abfd3d828b0a13e8fab8cd44fa4ba6c526f98 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sat, 19 Oct 2024 16:05:07 +0200 Subject: [PATCH 14/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Make=20them=20all=20a?= =?UTF-8?q?rguments=20for=20clap=20because=20they=20are=20all=20required?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/drivers/byovd.rs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/actions/drivers/byovd.rs b/src/actions/drivers/byovd.rs index 2309884..04f8ee8 100644 --- a/src/actions/drivers/byovd.rs +++ b/src/actions/drivers/byovd.rs @@ -16,26 +16,11 @@ use windows::{ #[derive(Debug, Parser)] pub struct Byovd { - #[clap( - short = 'n', - long, - required = true, - help = "Internal Name of the service" - )] + #[clap(required = true, help = "Internal Name of the service")] internal: String, - #[clap( - short = 'd', - long, - required = true, - help = "Displayed Name of the service" - )] + #[clap(required = true, help = "Displayed Name of the service")] display: String, - #[clap( - short = 'p', - long, - required = true, - help = "Full path to the driver eg: c:\\temp..." - )] + #[clap(required = true, help = "Full path to the driver eg: c:\\temp...")] path: String, } From 6dee87ddf34a78150f25b8cb06c05d3bd3da7161 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sat, 19 Oct 2024 17:20:19 +0200 Subject: [PATCH 15/22] =?UTF-8?q?refactor:=20=F0=9F=94=A8=20Rewrite=20BYOV?= =?UTF-8?q?D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/drivers/byovd.rs | 101 ++++++++++------------------------- 1 file changed, 28 insertions(+), 73 deletions(-) diff --git a/src/actions/drivers/byovd.rs b/src/actions/drivers/byovd.rs index 04f8ee8..9ac8beb 100644 --- a/src/actions/drivers/byovd.rs +++ b/src/actions/drivers/byovd.rs @@ -4,13 +4,12 @@ use crate::{actions::Runnable, windows::users::is_administrator}; use clap::Parser; -use std::{error::Error, thread, time}; +use std::{error::Error, path::PathBuf}; use windows::{ - core::{Result as WindowsResult, PCWSTR}, + core::{Owned, Result as WindowsResult, HSTRING, PCWSTR}, Win32::System::Services::{ - ControlService, CreateServiceW, DeleteService, OpenSCManagerW, StartServiceW, - ENUM_SERVICE_TYPE, SC_HANDLE, SC_MANAGER_ALL_ACCESS, SERVICE_CONTROL_STOP, SERVICE_ERROR, - SERVICE_START_TYPE, SERVICE_STATUS, + CreateServiceW, OpenSCManagerW, StartServiceW, SC_HANDLE, SC_MANAGER_ALL_ACCESS, + SC_MANAGER_CREATE_SERVICE, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, SERVICE_KERNEL_DRIVER, }, }; @@ -21,91 +20,47 @@ pub struct Byovd { #[clap(required = true, help = "Displayed Name of the service")] display: String, #[clap(required = true, help = "Full path to the driver eg: c:\\temp...")] - path: String, + path: PathBuf, } -fn create_driver_service(name: &str, details: &str, path: &str) -> bool { - println!("Open the service manager"); - let scmanager: SC_HANDLE = - unsafe { OpenSCManagerW(PCWSTR::null(), PCWSTR::null(), SC_MANAGER_ALL_ACCESS) } - .expect("Sc Manager open failure"); - - let mut service_name: Vec = name.encode_utf16().collect(); - service_name.push(0); - let mut service_display: Vec = details.encode_utf16().collect(); - service_display.push(0); - let mut service_path: Vec = path.encode_utf16().collect(); - service_path.push(0); - - println!("Create the service manager"); +fn load_driver(name: &str, details: &str, path: &str) -> WindowsResult<()> { + unsafe { + let service_manager: Owned = Owned::new(OpenSCManagerW( + PCWSTR::null(), + PCWSTR::null(), + SC_MANAGER_CREATE_SERVICE, + )?); - let service_handle: SC_HANDLE = match unsafe { - CreateServiceW( - scmanager, - PCWSTR::from_raw(service_name.as_ptr()), - PCWSTR::from_raw(service_display.as_ptr()), - 0xF003F, - ENUM_SERVICE_TYPE(1), - SERVICE_START_TYPE(2), - SERVICE_ERROR(0), - PCWSTR::from_raw(service_path.as_ptr()), + let service: Owned = Owned::new(CreateServiceW( + *service_manager, + &HSTRING::from(name), + &HSTRING::from(details), + SC_MANAGER_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_AUTO_START, + SERVICE_ERROR_IGNORE, + &HSTRING::from(path), PCWSTR::null(), None, PCWSTR::null(), PCWSTR::null(), PCWSTR::null(), - ) - } { - Ok(value) => value, - Err(_) => { - println!("Service creation failure"); - return false; - } - }; - - println!("Start Service "); - - match unsafe { StartServiceW(service_handle, None) } { - Ok(_) => { - println!("Wait a little"); - let sleep_duration: time::Duration = time::Duration::from_millis(2000); - thread::sleep(sleep_duration); - let mut service_status: SERVICE_STATUS = unsafe { std::mem::zeroed() }; - println!("Stop Service"); - let _result_stop: WindowsResult<()> = unsafe { - ControlService(service_handle, SERVICE_CONTROL_STOP, &mut service_status) - }; - } - Err(value) => { - println!("Service Start failure with code : {:#06x}", value.code().0); - } - }; + )?); - match unsafe { DeleteService(service_handle) } { - Ok(_) => { - println!("Service remove succeed"); - true - } - Err(value) => { - println!("Service remove failure with code : {:#06x}", value.code().0); - false - } + Ok(StartServiceW(*service, None)?) } } impl Runnable for Byovd { fn run(&self) -> Result<(), Box> { - println!("Bring Your Own Vulnerable Driver"); - if !is_administrator()? { - println!("Need to have Administrator right to create the service"); return Ok(()); } - // Todo check path is valid or not :) - - let result: bool = create_driver_service(&self.internal, &self.display, &self.path); - - Ok(()) + Ok(load_driver( + &self.internal, + &self.display, + self.path.to_str().unwrap(), + )?) } } From 04d9bf14a067b561338d7815f8a3195c55f79b52 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 20 Oct 2024 13:21:16 +0200 Subject: [PATCH 16/22] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Fix=20"is=5Fadminis?= =?UTF-8?q?trator"=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/windows/users.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/windows/users.rs b/src/windows/users.rs index f7fa1c6..0a008fb 100644 --- a/src/windows/users.rs +++ b/src/windows/users.rs @@ -5,13 +5,14 @@ use windows::{ core::{Owned, Result as WindowsResult}, Win32::{ + Foundation::BOOL, Security::{AllocateAndInitializeSid, CheckTokenMembership, PSID, SECURITY_NT_AUTHORITY}, System::SystemServices::{DOMAIN_ALIAS_RID_ADMINS, SECURITY_BUILTIN_DOMAIN_RID}, }, }; pub fn is_administrator() -> WindowsResult { - let mut is_admin: bool = false; + let mut is_admin: BOOL = false.into(); unsafe { let mut administrators_group: Owned = Owned::new(PSID::default()); @@ -30,12 +31,8 @@ pub fn is_administrator() -> WindowsResult { &mut *administrators_group, )?; - CheckTokenMembership( - None, - *administrators_group, - &mut is_admin as *mut _ as *mut _, - )?; + CheckTokenMembership(None, *administrators_group, &mut is_admin as *mut _)?; } - Ok(is_admin) + Ok(is_admin.as_bool()) } From e5a6b6018b009d6cd9edc791875030d94adb8eea Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 20 Oct 2024 13:28:14 +0200 Subject: [PATCH 17/22] =?UTF-8?q?refactor:=20=F0=9F=94=A8=20Move=20logic?= =?UTF-8?q?=20into=20their=20respective=20run=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/drivers/byovd.rs | 60 ++++++-------- src/actions/processes/spoofing.rs | 131 +++++++++++++++--------------- 2 files changed, 91 insertions(+), 100 deletions(-) diff --git a/src/actions/drivers/byovd.rs b/src/actions/drivers/byovd.rs index 9ac8beb..fb75979 100644 --- a/src/actions/drivers/byovd.rs +++ b/src/actions/drivers/byovd.rs @@ -6,7 +6,7 @@ use crate::{actions::Runnable, windows::users::is_administrator}; use clap::Parser; use std::{error::Error, path::PathBuf}; use windows::{ - core::{Owned, Result as WindowsResult, HSTRING, PCWSTR}, + core::{Owned, HSTRING, PCWSTR}, Win32::System::Services::{ CreateServiceW, OpenSCManagerW, StartServiceW, SC_HANDLE, SC_MANAGER_ALL_ACCESS, SC_MANAGER_CREATE_SERVICE, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, SERVICE_KERNEL_DRIVER, @@ -23,44 +23,36 @@ pub struct Byovd { path: PathBuf, } -fn load_driver(name: &str, details: &str, path: &str) -> WindowsResult<()> { - unsafe { - let service_manager: Owned = Owned::new(OpenSCManagerW( - PCWSTR::null(), - PCWSTR::null(), - SC_MANAGER_CREATE_SERVICE, - )?); - - let service: Owned = Owned::new(CreateServiceW( - *service_manager, - &HSTRING::from(name), - &HSTRING::from(details), - SC_MANAGER_ALL_ACCESS, - SERVICE_KERNEL_DRIVER, - SERVICE_AUTO_START, - SERVICE_ERROR_IGNORE, - &HSTRING::from(path), - PCWSTR::null(), - None, - PCWSTR::null(), - PCWSTR::null(), - PCWSTR::null(), - )?); - - Ok(StartServiceW(*service, None)?) - } -} - impl Runnable for Byovd { fn run(&self) -> Result<(), Box> { if !is_administrator()? { return Ok(()); } - Ok(load_driver( - &self.internal, - &self.display, - self.path.to_str().unwrap(), - )?) + unsafe { + let service_manager: Owned = Owned::new(OpenSCManagerW( + PCWSTR::null(), + PCWSTR::null(), + SC_MANAGER_CREATE_SERVICE, + )?); + + let service: Owned = Owned::new(CreateServiceW( + *service_manager, + &HSTRING::from(self.internal.as_str()), + &HSTRING::from(self.display.as_str()), + SC_MANAGER_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_AUTO_START, + SERVICE_ERROR_IGNORE, + &HSTRING::from(self.path.to_str().unwrap()), + PCWSTR::null(), + None, + PCWSTR::null(), + PCWSTR::null(), + PCWSTR::null(), + )?); + + Ok(StartServiceW(*service, None)?) + } } } diff --git a/src/actions/processes/spoofing.rs b/src/actions/processes/spoofing.rs index dfe16b2..317667d 100644 --- a/src/actions/processes/spoofing.rs +++ b/src/actions/processes/spoofing.rs @@ -26,77 +26,76 @@ pub struct Spoofing { parent_executable: String, } -fn spoof(executable: &str, parent_pid: u32) -> Result<(), Box> { - let mut required_size: usize = 0; +impl Runnable for Spoofing { + fn run(&self) -> Result<(), Box> { + let mut required_size: usize = 0; - unsafe { - let _ = InitializeProcThreadAttributeList( - LPPROC_THREAD_ATTRIBUTE_LIST::default(), - 1, - 0, - &mut required_size, - ); - }; + unsafe { + let _ = InitializeProcThreadAttributeList( + LPPROC_THREAD_ATTRIBUTE_LIST::default(), + 1, + 0, + &mut required_size, + ); + }; - let mut attributes: Box<[u8]> = vec![0; required_size].into_boxed_slice(); - let attributes_list: Owned = unsafe { - Owned::new(LPPROC_THREAD_ATTRIBUTE_LIST( - attributes.as_mut_ptr() as *mut _ - )) - }; - let startup_informations: STARTUPINFOEXW = STARTUPINFOEXW { - StartupInfo: STARTUPINFOW { - cb: size_of::() as u32, - ..Default::default() - }, - lpAttributeList: *attributes_list, - }; + let mut attributes: Box<[u8]> = vec![0; required_size].into_boxed_slice(); + let attributes_list: Owned = unsafe { + Owned::new(LPPROC_THREAD_ATTRIBUTE_LIST( + attributes.as_mut_ptr() as *mut _ + )) + }; + let startup_informations: STARTUPINFOEXW = STARTUPINFOEXW { + StartupInfo: STARTUPINFOW { + cb: size_of::() as u32, + ..Default::default() + }, + lpAttributeList: *attributes_list, + }; - unsafe { - InitializeProcThreadAttributeList( - startup_informations.lpAttributeList, - 1, - 0, - &mut required_size, - )?; + unsafe { + InitializeProcThreadAttributeList( + startup_informations.lpAttributeList, + 1, + 0, + &mut required_size, + )?; - let mut parent_process: Owned = - Owned::new(OpenProcess(PROCESS_CREATE_PROCESS, false, parent_pid)?); - UpdateProcThreadAttribute( - startup_informations.lpAttributeList, - 0, - PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as usize, - Some(&mut *parent_process as *mut _ as *mut _), - size_of::(), - None, - None, - )?; + let mut parent_process: Owned = Owned::new(OpenProcess( + PROCESS_CREATE_PROCESS, + false, + get_pid(self.parent_executable.as_str())?, + )?); + UpdateProcThreadAttribute( + startup_informations.lpAttributeList, + 0, + PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as usize, + Some(&mut *parent_process as *mut _ as *mut _), + size_of::(), + None, + None, + )?; - CreateProcessW( - None, - PWSTR( - OsString::from(executable) - .encode_wide() - .chain(once(0)) - .collect::>() - .as_mut_ptr(), - ), - None, - None, - false, - EXTENDED_STARTUPINFO_PRESENT, - None, - None, - &startup_informations.StartupInfo, - &mut PROCESS_INFORMATION::default(), - )?; - }; + CreateProcessW( + None, + PWSTR( + OsString::from(self.executable.as_str()) + .encode_wide() + .chain(once(0)) + .collect::>() + .as_mut_ptr(), + ), + None, + None, + false, + EXTENDED_STARTUPINFO_PRESENT, + None, + None, + &startup_informations.StartupInfo, + &mut PROCESS_INFORMATION::default(), + )?; + }; - Ok(()) -} - -impl Runnable for Spoofing { - fn run(&self) -> Result<(), Box> { - Ok(spoof(&self.executable, get_pid(&self.parent_executable)?)?) + Ok(()) } } From 5caee54e54b4d22b7e38e88297f9870ba0ac5fcd Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 20 Oct 2024 13:40:39 +0200 Subject: [PATCH 18/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Use=20better=20variab?= =?UTF-8?q?le=20names=20and=20add=20better=20descriptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/drivers/byovd.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/actions/drivers/byovd.rs b/src/actions/drivers/byovd.rs index fb75979..4ae2ae8 100644 --- a/src/actions/drivers/byovd.rs +++ b/src/actions/drivers/byovd.rs @@ -15,11 +15,11 @@ use windows::{ #[derive(Debug, Parser)] pub struct Byovd { - #[clap(required = true, help = "Internal Name of the service")] - internal: String, - #[clap(required = true, help = "Displayed Name of the service")] - display: String, - #[clap(required = true, help = "Full path to the driver eg: c:\\temp...")] + #[clap(required = true, help = "Name of the service")] + service_name: String, + #[clap(required = true, help = "Displayed name of the service")] + displayed_name: String, + #[clap(required = true, help = "Path to the driver")] path: PathBuf, } @@ -38,8 +38,8 @@ impl Runnable for Byovd { let service: Owned = Owned::new(CreateServiceW( *service_manager, - &HSTRING::from(self.internal.as_str()), - &HSTRING::from(self.display.as_str()), + &HSTRING::from(self.service_name.as_str()), + &HSTRING::from(self.displayed_name.as_str()), SC_MANAGER_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_AUTO_START, From d99f8a82fdda03b8ea5375c85a9f14d64f0a1656 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 20 Oct 2024 15:36:44 +0200 Subject: [PATCH 19/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Add=20basic=20path=20?= =?UTF-8?q?checking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/drivers/byovd.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/actions/drivers/byovd.rs b/src/actions/drivers/byovd.rs index 4ae2ae8..f2875cd 100644 --- a/src/actions/drivers/byovd.rs +++ b/src/actions/drivers/byovd.rs @@ -29,6 +29,10 @@ impl Runnable for Byovd { return Ok(()); } + if !self.path.try_exists()? || !self.path.is_file() { + return Ok(()); + } + unsafe { let service_manager: Owned = Owned::new(OpenSCManagerW( PCWSTR::null(), From b9b19f92e72d1b443e61a118998411cff6ec5b8f Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Sun, 20 Oct 2024 15:40:56 +0200 Subject: [PATCH 20/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Make=20exectuable=20a?= =?UTF-8?q?=20PathBuf=20and=20add=20basic=20path=20checking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/processes/spoofing.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/actions/processes/spoofing.rs b/src/actions/processes/spoofing.rs index 317667d..26b1ad8 100644 --- a/src/actions/processes/spoofing.rs +++ b/src/actions/processes/spoofing.rs @@ -4,7 +4,10 @@ use crate::{actions::Runnable, windows::processes::get_pid}; use clap::Parser; -use std::{error::Error, ffi::OsString, iter::once, mem::size_of, os::windows::ffi::OsStrExt}; +use std::{ + error::Error, ffi::OsString, iter::once, mem::size_of, os::windows::ffi::OsStrExt, + path::PathBuf, +}; use windows::{ core::{Owned, PWSTR}, Win32::{ @@ -21,13 +24,17 @@ use windows::{ #[derive(Debug, Parser)] pub struct Spoofing { #[clap(required = true, help = "Path to the executable")] - executable: String, + executable: PathBuf, #[clap(required = true, help = "Name of the parent executable")] parent_executable: String, } impl Runnable for Spoofing { fn run(&self) -> Result<(), Box> { + if !self.executable.try_exists()? || !self.executable.is_file() { + return Ok(()); + } + let mut required_size: usize = 0; unsafe { @@ -79,7 +86,7 @@ impl Runnable for Spoofing { CreateProcessW( None, PWSTR( - OsString::from(self.executable.as_str()) + OsString::from(self.executable.as_os_str()) .encode_wide() .chain(once(0)) .collect::>() From f610ea297194fb66003168df728e471c6c5b05c2 Mon Sep 17 00:00:00 2001 From: AntwortEinesLebens Date: Tue, 22 Oct 2024 19:14:19 +0200 Subject: [PATCH 21/22] =?UTF-8?q?feat:=20=E2=9C=A8=20Check=20if=20the=20se?= =?UTF-8?q?rvice=20already=20exists?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/drivers/byovd.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/actions/drivers/byovd.rs b/src/actions/drivers/byovd.rs index f2875cd..2895ad8 100644 --- a/src/actions/drivers/byovd.rs +++ b/src/actions/drivers/byovd.rs @@ -7,9 +7,13 @@ use clap::Parser; use std::{error::Error, path::PathBuf}; use windows::{ core::{Owned, HSTRING, PCWSTR}, - Win32::System::Services::{ - CreateServiceW, OpenSCManagerW, StartServiceW, SC_HANDLE, SC_MANAGER_ALL_ACCESS, - SC_MANAGER_CREATE_SERVICE, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, SERVICE_KERNEL_DRIVER, + Win32::{ + Foundation::GENERIC_READ, + System::Services::{ + CreateServiceW, OpenSCManagerW, OpenServiceW, StartServiceW, SC_HANDLE, + SC_MANAGER_ALL_ACCESS, SC_MANAGER_CREATE_SERVICE, SERVICE_AUTO_START, + SERVICE_ERROR_IGNORE, SERVICE_KERNEL_DRIVER, + }, }, }; @@ -40,6 +44,16 @@ impl Runnable for Byovd { SC_MANAGER_CREATE_SERVICE, )?); + if OpenServiceW( + *service_manager, + &HSTRING::from(self.service_name.as_str()), + GENERIC_READ.0, + ) + .is_ok() + { + return Ok(()); + } + let service: Owned = Owned::new(CreateServiceW( *service_manager, &HSTRING::from(self.service_name.as_str()), From 124ba7a4c3622c0fe5bd896fe65de6c6b29360df Mon Sep 17 00:00:00 2001 From: frack113 <62423083+frack113@users.noreply.github.com> Date: Sat, 26 Oct 2024 12:15:10 +0200 Subject: [PATCH 22/22] =?UTF-8?q?build:=20=F0=9F=93=A6=20Update=20MSRV?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c34b555..f4aa716 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ name = "windows-artifacts-generator" version = "1.0.0" edition = "2021" -rust-version = "1.74.1" description = "Generate malware artifacts for detection tests" documentation = "https://frack113.github.io/WAG/" repository = "https://github.com/frack113/WAG/" @@ -19,6 +18,7 @@ keywords = [ "rust", ] categories = ["command-line-utilities"] +rust-version = "1.80.1" [[bin]] name = "wag"