diff --git a/Cargo.lock b/Cargo.lock index 0d421de..fdce646 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,12 +211,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - [[package]] name = "libc" version = "0.2.153" @@ -359,12 +353,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - [[package]] name = "serde" version = "1.0.196" @@ -385,17 +373,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "strsim" version = "0.10.0" @@ -457,13 +434,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wag" -version = "0.1.0" +version = "0.5.0" dependencies = [ "clap", "rand", "regex_generate", - "serde", - "serde_json", "sysinfo", "widestring", "windows", diff --git a/Cargo.toml b/Cargo.toml index 167c030..9ce9208 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wag" -version = "0.1.0" +version = "1.0.0" edition = "2021" description = "Windows Artefact Generator" @@ -32,8 +32,6 @@ windows = { version = "0.52", features = [ "Win32_System_IO", "Win32_System_Services", ] } -serde = { version = "1", features = ["derive"] } -serde_json = "1" clap = { version = "4", features = ["derive"] } rand = "0" regex_generate = "0" diff --git a/README.md b/README.md index 0499018..1eb75df 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,6 @@ __ ___ _ # Purpose Generating Windows malware Artefacts for detection testing -Thanks to https://github.com/trickster0/OffensiveRust for the help. - Wag is not a TTP simulator like Redcanary, it is a simple artefact generator. but why ? @@ -44,76 +42,14 @@ See [Artefacts file](Artefacts.md) # How Contribute - repport bug -- update the json file - fix some code - add new artefact +- add more example # General Use -## Command Line -```bash -Usage: wag.exe -``` -`` is the artefact type to generate - -the same flags are used as much as possible to maintain consistency: - -- --help : display the help -- --module : name of the "ttp" mimic -- --get : list all the module -- --detail : list all the selection for a module (only some artefact) - - -## Data Structure -The artefact information are stored in a json file -Warnning,as we have regex in json need 2 escape level for `\` - -### namepipe.json - -```json -{ - "name": "Name of the malware family/test", - "namepipe": [ - "regex 1", - "regex x" - ] -} +```cmd +wag.exe ``` -### file.json -```json -{ - "magicbytes": [ - { - "name":"Name to use", - "magicbyte":"HEX to be written" - } - ], - "payloads":[ - { - "name":"Name to use", - "needroot": boolean , - "file_type":"Name of the magicbytes", - "fullpath":"regex path", - "cmd_var":"System variable", - "cmd_path":"regex path" - } - ], - "ads":[ - { - "name":"regex path", - "adsname":"ADS Name to use", - "hexvalue":"HEX to be written" - } - ] -} -``` - -# TODO LIST - -- [ ] Add process artefact -- [ ] Add dll artefact ? -- [ ] Doc and help -- [ ] Bug -- [ ] make a better code -- [ ] update create_file to return bool +Example can be found here [cli_help](cli_help.md) \ No newline at end of file diff --git a/cli_help.md b/cli_help.md new file mode 100644 index 0000000..3315cc2 --- /dev/null +++ b/cli_help.md @@ -0,0 +1,83 @@ +# Ads + +`wag ads -f file_full_path -a ads -d data` + +| Type | ads | data | +| --- | --- | --- | +|ZoneTransfer 0|Zone.Identifier|5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d300d0a526566657272657255726c3d633a5c77696e646f77735c7761672e7a69700d0a| +|ZoneTransfer 1|Zone.Identifier|5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d310d0a526566657272657255726c3d2f2f7376725f41442f7761672e7a69700d0a| +|ZoneTransfer 2|Zone.Identifier|5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d320d0a526566657272657255726c3d687474703a2f2f6d79736974652e6f72672f7761672e7a69700d0a| +|ZoneTransfer 3|Zone.Identifier|5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d330d0a526566657272657255726c3d68747470733a2f2f736f6d65736974652e636f6d2f7761672e7a69700d0a| +|ZoneTransfer 4|Zone.Identifier|5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d340d0a526566657272657255726c3d687474703a2f2f6d616c776172652e6261642f7761672e7a69700d0a| +|Sysmon|sysmon|4920616D20746865206265737420746F20686964652066726F6D207379736D6F6E" + +# File +## magicbytes + +|Type | Hex | +|--- | --- | +| Exe | 4D5A| +| Zip | 504B0304 | +| Vmdk| 4B444D| +| Iso | 4344303031| +| Txt | 412073696d706c6520746578742066696c65| +| Ps1 | 77726974652d686f73742022574147207761732048657265220a | + +## well known File + +`wag file-create -f fullpath -m Magicbyte_Hex` +`wag file-create -v cmd_var -p cmd_path -m Magicbyte_Hex` + +|name|Admin|Magicbyte|fullpath|cmd_var|cmd_path| +|---|---|---|---|---|---| +|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`| + +# Named pipe + +`wag name-pipe -n "regex"` + +| name | regex | +| --- | --- | +| CSExec | `\\csexecsvc` | +| psexec | `\\psexec` | +| psexec | `\\PAExec` | +| psexec | `\\remcom` | +| psexec | `\\csexec` | +| psexec | `\\PSEXESVC` | +| Cobal_strike | `\\mojo\\.5688\\.8052\\.(?:183894939787088877|35780273329370473)[0-9a-f]{2}` | +| 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 | `\\mypipe-(?:f|h)[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` | diff --git a/data/files.json b/data/files.json deleted file mode 100644 index 80d45c6..0000000 --- a/data/files.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "magicbytes": [ - { - "name":"Exe", - "magicbyte":"4D5A" - }, - { - "name":"Zip", - "magicbyte":"504B0304" - }, - { - "name":"Vmdk", - "magicbyte":"4B444D" - }, - { - "name":"Iso", - "magicbyte":"4344303031" - }, - { - "name":"Txt", - "magicbyte":"412073696d706c6520746578742066696c65" - }, - { - "name":"Ps1", - "magicbyte":"77726974652d686f73742022574147207761732048657265220a" - } - ], - "payloads":[ - { - "name":"NPPSpy", - "needroot": true, - "file_type":"Exe", - "fullpath":"C:/Windows/System32/NPPSpy\\.dll", - "cmd_var":"", - "cmd_path":"" - }, - { - "name":"SafetyKatz", - "needroot": false, - "file_type":"Zip", - "fullpath":"", - "cmd_var":"SystemRoot", - "cmd_path":"Temp\\\\debug\\.bin" - }, - { - "name":"SmallSieve_txt", - "needroot": false, - "file_type":"Txt", - "fullpath":"", - "cmd_var":"LocalAppData", - "cmd_path":"MicrosoftWindowsOutlookDataPlus\\.txt" - }, - { - "name":"SmallSieve_exe", - "needroot": false, - "file_type":"Exe", - "fullpath":"", - "cmd_var":"AppData", - "cmd_path":"OutlookMicrosift\\\\index\\.exe" - }, - { - "name":"SNAKE_jpsetup", - "needroot": false, - "file_type":"Exe", - "fullpath":"", - "cmd_var":"TEMP", - "cmd_path":"jpsetup\\.exe" - }, - { - "name":"SNAKE_jpinst", - "needroot": false, - "file_type":"Exe", - "fullpath":"", - "cmd_var":"TEMP", - "cmd_path":"jpinst\\.exe" - }, - { - "name":"SNAKE_Comadmin", - "needroot": true, - "file_type":"Exe", - "fullpath":"C:\\\\Windows\\\\System32\\\\Com\\\\Comadmin\\.dat", - "cmd_var":"", - "cmd_path":"" - }, - { - "name":"COLDSTEEL_exe", - "needroot": false, - "file_type":"Exe", - "fullpath":"C:\\\\users\\\\public\\\\Documents\\\\dllhost\\.exe", - "cmd_var":"", - "cmd_path":"" - }, - { - "name":"COLDSTEEL_dll", - "needroot": false, - "file_type":"Exe", - "fullpath":"", - "cmd_var":"APPDATA", - "cmd_path":"newdev\\.dll" - }, - { - "name":"temp_ps1_12", - "needroot": false, - "file_type":"Ps1", - "fullpath":"", - "cmd_var":"SystemRoot", - "cmd_path":"temp\\\\[0-9a-f]{12}\\.ps1" - } - ], - "ads":[ - { - "name":"ZoneTransfer_0", - "adsname":"Zone.Identifier", - "hexvalue":"5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d300d0a526566657272657255726c3d633a5c77696e646f77735c7761672e7a69700d0a" - }, - { - "name":"ZoneTransfer_1", - "adsname":"Zone.Identifier", - "hexvalue":"5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d310d0a526566657272657255726c3d2f2f7376725f41442f7761672e7a69700d0a" - }, - { - "name":"ZoneTransfer_2", - "adsname":"Zone.Identifier", - "hexvalue":"5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d320d0a526566657272657255726c3d687474703a2f2f6d79736974652e6f72672f7761672e7a69700d0a" - }, - { - "name":"ZoneTransfer_3", - "adsname":"Zone.Identifier", - "hexvalue":"5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d330d0a526566657272657255726c3d68747470733a2f2f736f6d65736974652e636f6d2f7761672e7a69700d0a" - }, - { - "name":"ZoneTransfer_4", - "adsname":"Zone.Identifier", - "hexvalue":"5b5a6f6e655472616e736665725d0d0a5a6f6e6549643d340d0a526566657272657255726c3d687474703a2f2f6d616c776172652e6261642f7761672e7a69700d0a" - }, - { - "name":"Sysmon", - "adsname":"sysmon", - "hexvalue":"4920616D20746865206265737420746F20686964652066726F6D207379736D6F6E" - } - ] -} \ No newline at end of file diff --git a/data/namepipe.json b/data/namepipe.json deleted file mode 100644 index 275eef4..0000000 --- a/data/namepipe.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "dictionary": [ - { - "name": "CSExec", - "namepipe": ["\\\\csexecsvc"] - }, - { - "name": "psexec", - "namepipe": [ - "\\\\psexec", - "\\\\PAExec", - "\\\\remcom", - "\\\\csexec", - "\\\\PSEXESVC" - ] - }, - { - "name": "Cobal_strike", - "namepipe": [ - "\\\\mojo\\.5688\\.8052\\.(?:183894939787088877|35780273329370473)[0-9a-f]{2}", - "\\\\wkssvc_?[0-9a-f]{2}", - "\\\\ntsvcs[0-9a-f]{2}", - "\\\\DserNamePipe[0-9a-f]{2}", - "\\\\SearchTextHarvester[0-9a-f]{2}", - "\\\\mypipe-(?:f|h)[0-9a-f]{2}", - "\\\\windows\\.update\\.manager[0-9a-f]{2,3}", - "\\\\ntsvcs_[0-9a-f]{2}", - "\\\\scerpc_?[0-9a-f]{2}", - "\\\\PGMessagePipe[0-9a-f]{2}", - "\\\\MsFteWds[0-9a-f]{2}", - "\\\\f4c3[0-9a-f]{2}", - "\\\\fullduplex_[0-9a-f]{2}", - "\\\\msrpc_[0-9a-f]{4}", - "\\\\win\\\\msrpc_[0-9a-f]{2}", - "\\\\f53f[0-9a-f]{2}", - "\\\\rpc_[0-9a-f]{2}", - "\\\\spoolss_[0-9a-f]{2}", - "\\\\Winsock2\\\\CatalogChangeListener-[0-9a-f]{3}-0," - ] - }, - { - "name": "DiagTrackEoP", - "namepipe": [ - "thisispipe" - ] - }, - { - "name": "EfsPotato", - "namepipe": [ - "\\\\pipe\\\\srvsvc" - ] - }, - { - "name": "Credential_Dumping", - "namepipe": [ - "\\\\cachedump", - "\\\\lsadump", - "\\\\wceservicepipe" - ] - }, - { - "name": "Koh", - "namepipe": [ - "\\\\imposecost", - "\\\\imposingcost" - ] - }, - { - "name": "PowerShell", - "namepipe": [ - "\\\\PSHost" - ] - }, - { - "name": "ADFS", - "namepipe": [ - "\\\\MICROSOFT##WID\\\\tsql\\\\query" - ] - } - ] -} \ No newline at end of file diff --git a/src/commands/ads.rs b/src/commands/ads.rs index 6e40a61..fbc8433 100644 --- a/src/commands/ads.rs +++ b/src/commands/ads.rs @@ -1,10 +1,13 @@ -use super::file::FileArtefact; +// +// Alternate Data Stream +// +// Last update 20240224 + use crate::commands::tools::{ - pretty_print_hashset, regex_to_string, EXIST_ALL_GOOD, EXIST_CLI_ERROR, EXIST_TEST_ERROR, + hex_to_bytes, regex_to_string, EXIST_ALL_GOOD, EXIST_CLI_ERROR, EXIST_TEST_ERROR, }; use clap::Parser; -use std::collections::HashSet; use std::path::Path; #[derive(Parser)] @@ -12,27 +15,27 @@ pub struct ADS { #[clap( short = 'f', long, - required = false, + required = true, default_value = "", help = "Full path filename (regex)" )] filename: String, #[clap( - short = 'm', + short = 'a', long, - required = false, + required = true, default_value = "", help = "ADS to use" )] - module: String, + ads: String, #[clap( - short = 'g', + short = 'd', long, - required = false, - default_value_t = false, - help = "Get all the possible ADS name and quit" + required = true, + default_value = "", + help = "Data to write in HEX" )] - get: bool, + data: String, } fn create_ads(fullpath: String, adsname: String, hex_data: Vec) -> bool { @@ -71,28 +74,18 @@ impl ADS { /* Version 20230908 */ pub fn run(&self) -> i32 { println!("Alternate Data Stream"); - let mut artefact: FileArtefact = FileArtefact::new(); - artefact.load("data/files.json"); - - if self.get == true { - let all_name: HashSet = artefact.file_ads_list(); - pretty_print_hashset("Name for the ADS File data".to_string(), all_name); - return EXIST_ALL_GOOD; - } - - if artefact.file_ads_exist(&self.module) == false { - println!("Did not find \"{}\" name for ads", self.module); - println!("You can use the help option --help"); - return EXIST_CLI_ERROR; - } if self.filename.len() > 0 { - println!("Get the regex : {}", self.filename); let fullname: String = regex_to_string(&self.filename); - println!("Create the ADS"); - let name_ads: String = artefact.file_ads_get_name(&self.module); - let payload: Vec = artefact.file_ads_get_data(&self.module); - let ret_ads: bool = create_ads(fullname, name_ads, payload); + + let header: Option> = hex_to_bytes(&self.data); + let payload: Vec = match header { + Some(data) => data, + None => vec![70, 114, 97, 99, 107, 49, 49, 51], + }; + + let barrow_ads: String = self.ads.to_string(); + let ret_ads: bool = create_ads(fullname, barrow_ads, payload); if ret_ads == true { return EXIST_ALL_GOOD; } else { diff --git a/src/commands/file.rs b/src/commands/file.rs index d8961bb..c5bbd2d 100644 --- a/src/commands/file.rs +++ b/src/commands/file.rs @@ -15,15 +15,11 @@ You can use `SET | more` or `Get-ChildItem Env:` to get the list */ use crate::commands::tools::{ - hex_to_bytes, pretty_print_hashset, process_is_admin, regex_to_string, EXIST_ALL_GOOD, - EXIST_CLI_ERROR, EXIST_TEST_ERROR, + hex_to_bytes, process_is_admin, regex_to_string, EXIST_ALL_GOOD, EXIST_TEST_ERROR, }; use clap::Parser; -use serde::Deserialize; -use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::OsString; -use std::fs::File; use std::io::Result as IOResult; use std::path::{Path, PathBuf}; use std::time::Duration; @@ -32,226 +28,45 @@ use std::{thread, time}; #[derive(Parser)] pub struct FileCreate { #[clap( - short = 'm', + short = 'f', long, required = false, default_value = "", - help = "Name of the malware to mimic" + help = "Full path filename (regex)" )] - module: String, + filename: String, #[clap( - short = 'g', + short = 'v', long, required = false, - default_value_t = false, - help = "Get all the possible mimic name and quit" + default_value = "", + help = "Use the CMD variable" )] - get: bool, + cmd_var: String, #[clap( - short = 'f', + short = 'p', long, required = false, default_value = "", - help = "Full path filename (regex) with module manual" + help = "Use the CMD path" )] - filename: String, + cmd_path: String, #[clap( - short = 'b', + short = 'm', long, - required = false, + required = true, default_value = "", help = "MagicBytes name to use with module manual " )] magicbyte: String, #[clap( - short = 'd', + short = 'a', long, required = false, default_value_t = false, - help = "Get all the possible MagicBytes name with module manual" + help = "Need to be admin" )] - details: bool, -} - -/* - Json Data structure -*/ -#[derive(Deserialize)] -struct JsonHeaderInfo { - name: String, - magicbyte: String, -} - -#[derive(Deserialize)] -struct JsonPayloadInfo { - name: String, - needroot: bool, - file_type: String, - fullpath: String, - cmd_var: String, - cmd_path: String, -} - -#[derive(Deserialize)] -struct JsonAdsInfo { - name: String, - adsname: String, - hexvalue: String, -} - -#[derive(Deserialize)] -struct JsonGlobalInfo { - magicbytes: Vec, - payloads: Vec, - ads: Vec, -} - -/* - Rust internal Structure - Get error with "copy" - - split ads struct into 2 Hashmap -*/ -#[derive(Clone)] -struct PayloadPathInfo { - needroot: bool, - file_type: String, - fullpath: String, - cmd_var: String, - cmd_path: String, -} - -#[derive(Clone)] -pub struct FileArtefact { - magicbyte: HashMap, - payload: HashMap, - ads_adsname: HashMap, - ads_hexvalue: HashMap, -} - -impl FileArtefact { - pub fn new() -> Self { - Self { - magicbyte: HashMap::new(), - payload: HashMap::new(), - ads_adsname: HashMap::new(), - ads_hexvalue: HashMap::new(), - } - } - - pub fn load(&mut self, path: &str) { - let file_path: PathBuf = std::env::current_dir() - .expect("Failed to get current folder") - .join(path); - let json_open: File = File::open(file_path).expect("Unable to open json file"); - let json_data: JsonGlobalInfo = - serde_json::from_reader(json_open).expect("error while reading or parsing the json"); - - for data in json_data.magicbytes { - self.magicbyte.insert(data.name, data.magicbyte); - } - - for data in json_data.payloads { - let tmp_data: PayloadPathInfo = { - PayloadPathInfo { - needroot: data.needroot, - file_type: data.file_type, - fullpath: data.fullpath, - cmd_var: data.cmd_var, - cmd_path: data.cmd_path, - } - }; - self.payload.insert(data.name, tmp_data); - } - - for data in json_data.ads { - self.ads_adsname.insert(data.name.clone(), data.adsname); - self.ads_hexvalue.insert(data.name, data.hexvalue); - } - } - - fn file_magicbyte_list(&self) -> HashSet { - self.magicbyte.keys().cloned().collect() - } - - fn file_magicbyte_exist(&self, name: &str) -> bool { - self.magicbyte.contains_key(name) - } - - fn file_magicbyte_get(&self, name: &str) -> Vec { - let mut payload: &str = "467261636b313133"; - if self.file_magicbyte_exist(name) { - payload = self.magicbyte.get(name).clone().unwrap(); //Can not faild as the key exist - } - let header: Option> = hex_to_bytes(payload); // User input 😅 - match header { - Some(data) => data, - None => vec![70, 114, 97, 99, 107, 49, 49, 51], - } - } - - fn file_payload_list(&self) -> HashSet { - self.payload.keys().cloned().collect() - } - - fn file_payload_exist(&self, name: &str) -> bool { - self.payload.contains_key(name) - } - - fn file_payload_needroot(&self, name: &str) -> bool { - let data: &PayloadPathInfo = self.payload.get(name).unwrap(); // exit fail if name is invalid - data.needroot - } - - fn file_payload_getfilename(&self, name: &str) -> String { - if self.file_payload_exist(name) { - let data: &PayloadPathInfo = self.payload.get(name).unwrap(); // name is a valid key - - if data.fullpath.len() > 0 { - regex_to_string(&data.fullpath) - } else { - let filename: String = regex_to_string(&data.cmd_path); - let var_path: OsString = env::var_os(&data.cmd_var).unwrap(); - let full_path: PathBuf = Path::new(&var_path).join(filename); - String::from(full_path.to_string_lossy()) - } - } else { - "c:/wag.file".to_string() - } - } - - fn file_payload_getfiletype(&self, name: &str) -> String { - if self.file_payload_exist(name) { - let data: &PayloadPathInfo = self.payload.get(name).unwrap(); // name is a valid key - data.file_type.clone() - } else { - "Wag".to_string() - } - } - - pub fn file_ads_list(&self) -> HashSet { - self.ads_adsname.keys().cloned().collect() - } - - pub fn file_ads_exist(&self, name: &str) -> bool { - self.ads_adsname.contains_key(name) - } - - pub fn file_ads_get_data(&self, name: &str) -> Vec { - println!("Ask for {}", name); - let payload: &String = self.ads_hexvalue.get(name).clone().unwrap(); //Can not faild as the key exist - println!("{}", payload); - let header: Option> = hex_to_bytes(payload); // User input 😅 - match header { - Some(data) => data, - None => vec![70, 114, 97, 99, 107, 49, 49, 51], - } - } - - pub fn file_ads_get_name(&self, name: &str) -> String { - let data: &String = self.ads_adsname.get(name).clone().unwrap(); //Can not faild as the key exist - data.to_string() - } + admin: bool, } fn create_file(fullpath: String, hex_data: Vec) -> bool { @@ -287,63 +102,30 @@ fn create_file(fullpath: String, hex_data: Vec) -> bool { } impl FileCreate { - /* Version 20230908 */ pub fn run(&self) -> i32 { - println!("Create a file on disk"); - let mut artefact: FileArtefact = FileArtefact::new(); - artefact.load("data/files.json"); - - if self.get == true { - let all_name: HashSet = artefact.file_payload_list(); - pretty_print_hashset("Name for the mimic File creation".to_string(), all_name); - return EXIST_ALL_GOOD; + if self.admin && !process_is_admin() { + println!("Need to have Administrator right to create the file"); + return EXIST_TEST_ERROR; } - let fullname: String; - let payload: Vec; - - if self.module == "manual" { - if self.details == true { - let all_name: HashSet = artefact.file_magicbyte_list(); - pretty_print_hashset("Name for the MagicByte File creation".to_string(), all_name); - return EXIST_ALL_GOOD; - } - - if artefact.file_magicbyte_exist(&self.magicbyte) == false { - println!( - "Did not find \"{}\" name for MagicBytes Option", - self.magicbyte - ); - println!("You can use the help option --help"); - return EXIST_CLI_ERROR; - } + let header: Option> = hex_to_bytes(&self.magicbyte); + let payload: Vec = match header { + Some(data) => data, + None => vec![70, 114, 97, 99, 107, 49, 49, 51], + }; - if self.filename.len() > 0 { - println!("Get the regex : {}", self.filename); - fullname = regex_to_string(&self.filename); - payload = artefact.file_magicbyte_get(&self.magicbyte); - } else { - return EXIST_CLI_ERROR; - } + let fullname: String; + if self.filename.len() > 0 { + fullname = regex_to_string(&self.filename); } else { - if artefact.file_payload_exist(&self.module) == false { - println!("Did not find \"{}\" name for filecreate", self.module); - println!("You can use the help option --help"); - return EXIST_CLI_ERROR; - } - - let payload_type: String = artefact.file_payload_getfiletype(&self.module); - let admin: bool = artefact.file_payload_needroot(&self.module); - - fullname = artefact.file_payload_getfilename(&self.module); - payload = artefact.file_magicbyte_get(&payload_type); - - if admin && !process_is_admin() { - println!("Need to have Administrator right to create the file"); - return EXIST_TEST_ERROR; - } + let filename: String = regex_to_string(&self.cmd_path); + let var_path: OsString = env::var_os(&self.cmd_var).unwrap(); + let full_path: PathBuf = Path::new(&var_path).join(filename); + fullname = String::from(full_path.to_string_lossy()); } + println!("Create a file on disk"); + let ret: bool = create_file(fullname, payload); if ret == true { diff --git a/src/commands/namepipe.rs b/src/commands/namepipe.rs index f23bf71..a9bd7db 100644 --- a/src/commands/namepipe.rs +++ b/src/commands/namepipe.rs @@ -1,124 +1,29 @@ // -// Name Pipe Artefact +// Name Pipe // -// Windows API +// Last update 20240224 + use windows::core::{Result as WindowsResult, PCSTR}; use windows::Win32::Foundation::{CloseHandle, HANDLE}; use windows::Win32::Storage::FileSystem::PIPE_ACCESS_DUPLEX; use windows::Win32::System::Pipes::{CreateNamedPipeA, PIPE_TYPE_MESSAGE}; -use serde::Deserialize; -use std::collections::{HashMap, HashSet}; -use std::fs::File; -use std::path::PathBuf; -use std::{thread, time}; - -use crate::commands::tools::{ - pretty_print_hashset, regex_to_string, EXIST_ALL_GOOD, EXIST_CLI_ERROR, -}; +use crate::commands::tools::{regex_to_string, EXIST_ALL_GOOD}; use clap::Parser; +use std::{thread, time}; #[derive(Parser)] pub struct NamePipe { #[clap( - short = 'm', - long, - required = false, - default_value = "", - help = "Name of the malware to mimic" - )] - module: String, - #[clap(short = 'n', long, required = false, default_value_t = 0)] - number: usize, - #[clap( - short = 'g', - long, - required = false, - default_value_t = false, - help = "Get all the possible pipename for a mimic and quit" - )] - get: bool, - #[clap( - short = 'd', + short = 'n', long, - required = false, - default_value_t = false, - help = "Get all the possible mimic name" - )] - details: bool, - #[clap( - short = 'N', - long, - required = false, - default_value = "", + required = true, + default_value = "wag", help = "Regex of the PipeName to Create" )] name: String, } -//Structure for the Json -#[derive(Deserialize)] -struct JsonNamepipeInfo { - name: String, - namepipe: Vec, -} - -#[derive(Deserialize)] -struct JsonGlobalInfo { - dictionary: Vec, -} - -//Structure form the name pipe -// Very simple struct -#[derive(Clone)] -struct NamePipeArtefact { - namepipe: HashMap>, -} - -impl NamePipeArtefact { - fn new() -> Self { - Self { - namepipe: HashMap::new(), - } - } - - fn load(&mut self, path: &str) { - let file_path: PathBuf = std::env::current_dir() - .expect("Failed to get current folder") - .join(path); - let json_open: File = File::open(file_path).expect("Unable to open json file"); - let json_data: JsonGlobalInfo = - serde_json::from_reader(json_open).expect("error while reading or parsing the json"); - - for data in json_data.dictionary { - self.namepipe.insert(data.name, data.namepipe); - } - } - - fn namepipe_list(&self) -> HashSet { - self.namepipe.keys().cloned().collect() - } - - fn namepipe_value_list(&self, name: &str) -> Vec { - self.namepipe.get(name).unwrap().to_vec() - } - - fn namepipe_exist(&self, name: &str) -> bool { - self.namepipe.contains_key(name) - } - - fn namepipe_get_value_at_index(&self, name: &str, number: usize) -> String { - let mut index_payload: usize = number; - let namepipe_value_list: Vec = self.namepipe_value_list(name); - //Don't trust humain - if index_payload > namepipe_value_list.len() - 1 { - index_payload = 0; - } - let barrow: &String = &namepipe_value_list[index_payload]; - barrow.to_owned() - } -} - 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()); @@ -139,49 +44,11 @@ fn create_name_pipe(name: &String, wait: u64) { let _res_server_pipe: WindowsResult<()> = unsafe { CloseHandle(server_pipe.unwrap()) }; } -/* Version 20230908 */ impl NamePipe { pub fn run(&self) -> i32 { println!("Create NamePipe"); - let mut artefact: NamePipeArtefact = NamePipeArtefact::new(); - artefact.load("data/namepipe.json"); - let full_payload: String; - - if self.get == true { - let all_name: HashSet = artefact.namepipe_list(); - pretty_print_hashset("Name for the mimic Name Pipe".to_string(), all_name); - return EXIST_ALL_GOOD; - } - if self.module == "manual" { - if self.name.len() > 0 { - full_payload = regex_to_string(&self.name); - } else { - return EXIST_CLI_ERROR; - } - } else { - if artefact.namepipe_exist(&self.module) == false { - println!("Did not find \"{}\" name for namepipe", self.module); - println!("You can use the help option --help"); - return EXIST_CLI_ERROR; - } - - if self.details == true { - println!("Name Pipe number for \"{}\" :", self.module); - println!("----------------"); - let list_name_pipe: Vec = artefact.namepipe_value_list(&self.module); - for i in 0..list_name_pipe.len() { - println!(" {} - {}", i, list_name_pipe[i]) - } - println!("----------------"); - println!("bye"); - return EXIST_ALL_GOOD; - } - - let payload: String = artefact.namepipe_get_value_at_index(&self.module, self.number); - full_payload = regex_to_string(&payload); - } - + full_payload = regex_to_string(&self.name); println!("Create the namepipe : {}", full_payload); create_name_pipe(&full_payload, 2000); return EXIST_ALL_GOOD; diff --git a/src/commands/ppid.rs b/src/commands/ppid.rs index ceae323..1033300 100644 --- a/src/commands/ppid.rs +++ b/src/commands/ppid.rs @@ -1,6 +1,7 @@ // -// PPID Artefact generator +// PPID Spoofing // +// Last update 20240224 use crate::commands::tools::{EXIST_ALL_GOOD, EXIST_TEST_ERROR}; use clap::Parser; @@ -25,8 +26,12 @@ use std::time::Duration; #[derive(Parser)] pub struct PPID { - #[clap(short = 'p', long, help = "Full path to the driver eg: c:\\temp...")] - path: String, + #[clap( + short = 'e', + long, + help = "Full path to the executable eg: c:\\temp..." + )] + executable: String, } /* Use internal rust command */ @@ -121,7 +126,7 @@ impl PPID { /* Version 20240209 */ pub fn run(&self) -> i32 { println!("PPID spoofing"); - let result: bool = create_ppid(&self.path); + let result: bool = create_ppid(&self.executable); if result { println!("All good "); return EXIST_ALL_GOOD; diff --git a/src/commands/service.rs b/src/commands/service.rs index 395920d..2a2f528 100644 --- a/src/commands/service.rs +++ b/src/commands/service.rs @@ -1,6 +1,7 @@ // -// Artefact generator +// Load Vulnerable Driver // +// Last update 20240224 // Windows API use windows::core::{Result as WindowsResult, PCWSTR};