added a module to copy the command to run a portscan for the scope, and

added the ability to add new configs to separate projects, like work vs
personal. Also added a way to switch between these configs.
This commit is contained in:
2026-08-19 16:56:27 -05:00
parent e28306d07d
commit 8ab7a2bec4
10 changed files with 759 additions and 291 deletions
Generated
+229 -176
View File
@@ -2,6 +2,16 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "aead"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99"
dependencies = [
"crypto-common 0.2.2",
"inout 0.2.2",
]
[[package]] [[package]]
name = "aes" name = "aes"
version = "0.8.4" version = "0.8.4"
@@ -9,10 +19,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cipher", "cipher 0.4.4",
"cpufeatures 0.2.17", "cpufeatures 0.2.17",
] ]
[[package]]
name = "aes"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8eb277bec05f56a0e0591f155a484cbd0f4f07ff2905051a48c72f004f7ed58"
dependencies = [
"cipher 0.5.2",
"cpubits",
"cpufeatures 0.3.0",
]
[[package]]
name = "aes-gcm"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdf011db2e21ce0d575593d749db5554b47fed37aff429e4dc50bc91ac93a028"
dependencies = [
"aead",
"aes 0.9.2",
"cipher 0.5.2",
"ctr",
"ghash",
"subtle",
]
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.8.12" version = "0.8.12"
@@ -365,6 +400,12 @@ version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a"
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.4" version = "0.10.4"
@@ -374,6 +415,15 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "block-buffer"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
dependencies = [
"hybrid-array",
]
[[package]] [[package]]
name = "block-padding" name = "block-padding"
version = "0.3.3" version = "0.3.3"
@@ -435,7 +485,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
dependencies = [ dependencies = [
"cipher", "cipher 0.4.4",
] ]
[[package]] [[package]]
@@ -479,8 +529,19 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [ dependencies = [
"crypto-common", "crypto-common 0.1.7",
"inout", "inout 0.1.4",
]
[[package]]
name = "cipher"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
dependencies = [
"block-buffer 0.12.1",
"crypto-common 0.2.2",
"inout 0.2.2",
] ]
[[package]] [[package]]
@@ -523,6 +584,28 @@ 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 = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "clipboard"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a904646c0340239dcf7c51677b33928bf24fdf424b79a57909c0109075b2e7"
dependencies = [
"clipboard-win",
"objc",
"objc-foundation",
"objc_id",
"x11-clipboard",
]
[[package]]
name = "clipboard-win"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a093d6fed558e5fe24c3dfc85a68bb68f1c824f440d3ba5aca189e2998786b"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "cmake" name = "cmake"
version = "0.1.58" version = "0.1.58"
@@ -532,6 +615,12 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "cmov"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.5" version = "1.0.5"
@@ -606,6 +695,12 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cpubits"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.17" version = "0.2.17"
@@ -692,6 +787,17 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "crypto-common"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
dependencies = [
"getrandom 0.4.3",
"hybrid-array",
"rand_core 0.10.1",
]
[[package]] [[package]]
name = "csscolorparser" name = "csscolorparser"
version = "0.6.2" version = "0.6.2"
@@ -702,6 +808,24 @@ dependencies = [
"phf", "phf",
] ]
[[package]]
name = "ctr"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baaca1c4b237092596f64d571e9db6ce4109c4ef9742e27590f1709594461f21"
dependencies = [
"cipher 0.5.2",
]
[[package]]
name = "ctutils"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
dependencies = [
"cmov",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.23.0" version = "0.23.0"
@@ -799,8 +923,8 @@ version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"block-buffer", "block-buffer 0.10.4",
"crypto-common", "crypto-common 0.1.7",
"subtle", "subtle",
] ]
@@ -970,12 +1094,6 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]] [[package]]
name = "foldhash" name = "foldhash"
version = "0.2.0" version = "0.2.0"
@@ -1078,25 +1196,23 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.4.2" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"r-efi 6.0.0", "r-efi 6.0.0",
"rand_core 0.10.1", "rand_core 0.10.1",
"wasip2",
"wasip3",
] ]
[[package]] [[package]]
name = "hashbrown" name = "ghash"
version = "0.15.5" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5"
dependencies = [ dependencies = [
"foldhash 0.1.5", "polyval",
] ]
[[package]] [[package]]
@@ -1107,7 +1223,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
dependencies = [ dependencies = [
"allocator-api2", "allocator-api2",
"equivalent", "equivalent",
"foldhash 0.2.0", "foldhash",
] ]
[[package]] [[package]]
@@ -1153,10 +1269,13 @@ dependencies = [
] ]
[[package]] [[package]]
name = "id-arena" name = "hybrid-array"
version = "2.3.0" version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b"
dependencies = [
"typenum",
]
[[package]] [[package]]
name = "ident_case" name = "ident_case"
@@ -1172,8 +1291,6 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.17.1", "hashbrown 0.17.1",
"serde",
"serde_core",
] ]
[[package]] [[package]]
@@ -1195,6 +1312,15 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "inout"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7"
dependencies = [
"hybrid-array",
]
[[package]] [[package]]
name = "instability" name = "instability"
version = "0.3.12" version = "0.3.12"
@@ -1301,12 +1427,6 @@ 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"
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.186" version = "0.2.186"
@@ -1368,6 +1488,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.8.1" version = "2.8.1"
@@ -1546,6 +1675,26 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]] [[package]]
name = "objc2" name = "objc2"
version = "0.6.4" version = "0.6.4"
@@ -1603,6 +1752,15 @@ dependencies = [
"objc2-foundation", "objc2-foundation",
] ]
[[package]]
name = "objc_id"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
dependencies = [
"objc",
]
[[package]] [[package]]
name = "oid-registry" name = "oid-registry"
version = "0.8.1" version = "0.8.1"
@@ -1817,6 +1975,17 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "polyval"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0fa31d631f2b2cb2a544d0aa321ce847a94764d701ca2becc411138b93d49cd"
dependencies = [
"cpubits",
"cpufeatures 0.3.0",
"universal-hash",
]
[[package]] [[package]]
name = "portable-atomic" name = "portable-atomic"
version = "1.13.1" version = "1.13.1"
@@ -1829,16 +1998,6 @@ 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 = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "prettyplease"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn 2.0.117",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "3.5.0" version = "3.5.0"
@@ -1894,7 +2053,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
dependencies = [ dependencies = [
"chacha20", "chacha20",
"getrandom 0.4.2", "getrandom 0.4.3",
"rand_core 0.10.1", "rand_core 0.10.1",
] ]
@@ -2227,7 +2386,7 @@ version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a62d7f86047af0077255a29494136b9aaaf697c76ff70b8e49cded4e2623c14" checksum = "9a62d7f86047af0077255a29494136b9aaaf697c76ff70b8e49cded4e2623c14"
dependencies = [ dependencies = [
"aes", "aes 0.8.4",
"cbc", "cbc",
"futures-util", "futures-util",
"generic-array", "generic-array",
@@ -2531,7 +2690,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [ dependencies = [
"fastrand", "fastrand",
"getrandom 0.4.2", "getrandom 0.4.3",
"once_cell", "once_cell",
"rustix", "rustix",
"windows-sys 0.61.2", "windows-sys 0.61.2",
@@ -2604,8 +2763,10 @@ dependencies = [
name = "tetanus" name = "tetanus"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"aes-gcm",
"anyhow", "anyhow",
"clap", "clap",
"clipboard",
"crossterm", "crossterm",
"fs_extra", "fs_extra",
"ipnet", "ipnet",
@@ -2885,10 +3046,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
[[package]] [[package]]
name = "unicode-xid" name = "universal-hash"
version = "0.2.6" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96"
dependencies = [
"crypto-common 0.2.2",
"ctutils",
]
[[package]] [[package]]
name = "untrusted" name = "untrusted"
@@ -2909,7 +3074,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7"
dependencies = [ dependencies = [
"atomic", "atomic",
"getrandom 0.4.2", "getrandom 0.4.3",
"js-sys", "js-sys",
"serde_core", "serde_core",
"wasm-bindgen", "wasm-bindgen",
@@ -2952,16 +3117,7 @@ version = "1.0.3+wasi-0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
dependencies = [ dependencies = [
"wit-bindgen 0.57.1", "wit-bindgen",
]
[[package]]
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [
"wit-bindgen 0.51.0",
] ]
[[package]] [[package]]
@@ -3009,40 +3165,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasm-metadata"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags 2.12.1",
"hashbrown 0.15.5",
"indexmap",
"semver",
]
[[package]] [[package]]
name = "web-time" name = "web-time"
version = "1.1.0" version = "1.1.0"
@@ -3370,15 +3492,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "wit-bindgen"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
dependencies = [
"wit-bindgen-rust-macro",
]
[[package]] [[package]]
name = "wit-bindgen" name = "wit-bindgen"
version = "0.57.1" version = "0.57.1"
@@ -3386,82 +3499,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]] [[package]]
name = "wit-bindgen-core" name = "x11-clipboard"
version = "0.51.0" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" checksum = "89bd49c06c9eb5d98e6ba6536cf64ac9f7ee3a009b2f53996d405b3944f6bcea"
dependencies = [ dependencies = [
"anyhow", "xcb",
"heck",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rust"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
dependencies = [
"anyhow",
"heck",
"indexmap",
"prettyplease",
"syn 2.0.117",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
dependencies = [
"anyhow",
"prettyplease",
"proc-macro2",
"quote",
"syn 2.0.117",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
dependencies = [
"anyhow",
"bitflags 2.12.1",
"indexmap",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
dependencies = [
"anyhow",
"id-arena",
"indexmap",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
] ]
[[package]] [[package]]
@@ -3482,6 +3525,16 @@ dependencies = [
"time", "time",
] ]
[[package]]
name = "xcb"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e917a3f24142e9ff8be2414e36c649d47d6cc2ba81f16201cdef96e533e02de"
dependencies = [
"libc",
"log",
]
[[package]] [[package]]
name = "yasna" name = "yasna"
version = "0.6.0" version = "0.6.0"
+2
View File
@@ -4,8 +4,10 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
aes-gcm = "0.11.0"
anyhow = "1.0.103" anyhow = "1.0.103"
clap = { version = "4.6.1", features = ["derive"] } clap = { version = "4.6.1", features = ["derive"] }
clipboard = "0.5.0"
crossterm = "0.29.0" crossterm = "0.29.0"
fs_extra = "1.3.0" fs_extra = "1.3.0"
ipnet = "2.12.0" ipnet = "2.12.0"
@@ -0,0 +1,5 @@
name: csps
output_type: String,
new_thread: false
args: project
calls: clipboard
@@ -0,0 +1 @@
Parse the scope file in your notes and print the cobalt strike portscan command to run.
@@ -0,0 +1,22 @@
let ips = [];
let scope_path = find_file(project.notes, "scope");
let scope_text = open_file(scope_path);
for line in scope_text.split("\n"){
if line.contains("|") && !line.contains("//"){
let cols = line.split("|");
let data = cols[1];
if data.len() > 0{
for host in filter_ips(data){
ips.push(host);
}
}
}
}
let target_string = "";
for ip in ips{
target_string = target_string + "," + ip;
}
let out_string = "portscan " + target_string + " 1-1024,1433,2222,3306,3389,5000-6000,8000,8080,8443 icmp 512";
return out_string;
+62 -3
View File
@@ -9,12 +9,12 @@ use ratatui::{
prelude::*, prelude::*,
widgets::{Block, Borders, List, ListItem, ListState, Paragraph}, widgets::{Block, Borders, List, ListItem, ListState, Paragraph},
}; };
use std::thread::sleep;
use std::thread::spawn; use std::thread::spawn;
use std::thread::{JoinHandle, sleep};
use std::time::Duration; use std::time::Duration;
use std::{error::Error, time::Instant}; use std::{error::Error, time::Instant};
use std::{io::Write, usize}; use std::{io::Write, usize};
use sysinfo::{MemoryRefreshKind, System}; use sysinfo::System;
pub fn get_user_input(prompt: &str) -> Result<String, Box<dyn Error>> { pub fn get_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {
println!("{}", prompt); println!("{}", prompt);
@@ -23,9 +23,51 @@ pub fn get_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {
return Ok(response.trim().to_string()); return Ok(response.trim().to_string());
} }
pub fn startup(
mut state: AppState,
nested: bool,
handles: Arc<Mutex<Vec<JoinHandle<()>>>>,
) -> Result<(), Box<dyn std::error::Error>> {
let mut app = AppState::new();
let (tx, rx) = channel();
app.main_tx = tx.clone();
if let Some(line) = state.config.get("alternate_configs") {
let mut selections = HashMap::new();
line.split(",").into_iter().for_each(|line| {
if let Some((name, path)) = line.split_once("|") {
selections.insert(name.to_string(), path.to_string());
println!("{} | {} ", name, path);
}
});
selections.insert(
"default".to_string(),
state.config_file.display().to_string(),
);
println!("default | {}", state.config_file.display());
let response = get_user_input("which config would you like to load?")?;
if let Some(path) = selections.get(&response) {
app.load_config(PathBuf::from(path), true)?;
run_tui(app, rx, handles.clone())?;
} else {
eprintln!("error invalid selection! exiting...");
return Err("invalid config selected.".into());
}
} else {
app.load_config(state.config_file.clone(), true)?;
run_tui(app, rx, handles.clone())?;
}
if nested {
let (tx, rx) = channel();
state.main_tx = tx;
run_tui(state, rx, handles.clone())?;
}
Ok(())
}
pub fn run_tui( pub fn run_tui(
mut state: AppState, mut state: AppState,
main_rx: Receiver<ToolMessage>, main_rx: Receiver<ToolMessage>,
main_handles: Arc<Mutex<Vec<JoinHandle<()>>>>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
enable_raw_mode()?; enable_raw_mode()?;
let mut stdout = io::stdout(); let mut stdout = io::stdout();
@@ -43,6 +85,7 @@ pub fn run_tui(
let mut system = System::new_all(); let mut system = System::new_all();
let system_timer = Duration::from_secs(1); let system_timer = Duration::from_secs(1);
let mut last_print = Instant::now(); let mut last_print = Instant::now();
let mut switch_config = false;
const BYTES_PER_GB: u64 = 1024 * 1024 * 1024; const BYTES_PER_GB: u64 = 1024 * 1024 * 1024;
if !state.projects.is_empty() { if !state.projects.is_empty() {
project_list_state.select(Some(0)); project_list_state.select(Some(0));
@@ -87,6 +130,7 @@ pub fn run_tui(
let mut history_index = state.history.len(); let mut history_index = state.history.len();
let mut handles = Vec::new(); let mut handles = Vec::new();
loop { loop {
if switch_config {}
if Instant::now().duration_since(last_print) > system_timer { if Instant::now().duration_since(last_print) > system_timer {
system.refresh_cpu_usage(); system.refresh_cpu_usage();
system.refresh_memory(); system.refresh_memory();
@@ -556,7 +600,10 @@ pub fn run_tui(
.send(ToolMessage::Output((0, "\n".to_string()))); .send(ToolMessage::Output((0, "\n".to_string())));
let prompt = state.prompt.clone(); let prompt = state.prompt.clone();
if prompt.action.is_some() { if prompt.action.is_some() {
state.prompt.responses.push(trimmed.clone()); state.prompt.responses.push(PromptResponse {
query: prompt.last_prompted.clone().unwrap(),
response: trimmed.clone(),
});
if state.prompt.responses.len() == state.prompt.num_responses { if state.prompt.responses.len() == state.prompt.num_responses {
state.execute_command( state.execute_command(
prompt.execute_command.as_str(), prompt.execute_command.as_str(),
@@ -604,6 +651,10 @@ pub fn run_tui(
); );
} }
} }
"switch_config" => {
switch_config = true;
break;
}
command_name => { command_name => {
if state.module_loader.commands.contains_key(command) { if state.module_loader.commands.contains_key(command) {
let _ = state.main_tx.send(ToolMessage::Output(( let _ = state.main_tx.send(ToolMessage::Output((
@@ -756,5 +807,13 @@ pub fn run_tui(
for handle in handles { for handle in handles {
handle.join().unwrap(); handle.join().unwrap();
} }
if switch_config {
let handles_clone = main_handles.clone();
if let Ok(mut lock) = main_handles.lock() {
lock.push(spawn(move || {
let _ = startup(state, true, handles_clone);
}));
}
}
Ok(()) Ok(())
} }
+1
View File
@@ -97,6 +97,7 @@ pub fn client_install() -> Result<(), Box<dyn Error>> {
client_config_file.write(format!("template_box: {}\n", template_box).as_bytes())?; client_config_file.write(format!("template_box: {}\n", template_box).as_bytes())?;
client_config_file.write(format!("term_cmd: {}\n", term_cmd).as_bytes())?; client_config_file.write(format!("term_cmd: {}\n", term_cmd).as_bytes())?;
client_config_file.write(format!("tools: {}\n", tools_folder).as_bytes())?; client_config_file.write(format!("tools: {}\n", tools_folder).as_bytes())?;
client_config_file.write("alternate_configs: \n".as_bytes())?;
println!("\ndefault config files written!"); println!("\ndefault config files written!");
println!("downloading note templates, victim templates, and modules..."); println!("downloading note templates, victim templates, and modules...");
create_dir_all("./temp")?; create_dir_all("./temp")?;
+376 -108
View File
@@ -1,3 +1,5 @@
use clipboard::ClipboardContext;
use clipboard::ClipboardProvider;
use fs_extra::dir::{CopyOptions, copy}; use fs_extra::dir::{CopyOptions, copy};
use ipnet::IpNet; use ipnet::IpNet;
use keyring::Entry; use keyring::Entry;
@@ -5,6 +7,7 @@ use ratatui::crossterm::event;
use rhai::{AST, Dynamic, Engine, Scope}; use rhai::{AST, Dynamic, Engine, Scope};
use rustls::{ClientConfig, ClientConnection, RootCertStore, StreamOwned, pki_types::ServerName}; use rustls::{ClientConfig, ClientConnection, RootCertStore, StreamOwned, pki_types::ServerName};
use std::collections::HashMap; use std::collections::HashMap;
use std::env;
use std::error::Error; use std::error::Error;
use std::fs::{self, File, create_dir_all, read_dir, read_to_string, remove_dir, remove_dir_all}; use std::fs::{self, File, create_dir_all, read_dir, read_to_string, remove_dir, remove_dir_all};
use std::io::{self, BufRead, BufReader, Read, Write}; use std::io::{self, BufRead, BufReader, Read, Write};
@@ -94,48 +97,46 @@ pub struct AppState {
} }
impl AppState { impl AppState {
pub fn new() -> (Self, Receiver<ToolMessage>) { pub fn new() -> Self {
let (main_tx, main_rx) = channel(); let (main_tx, _) = channel();
( Self {
Self { projects: Vec::new(),
projects: Vec::new(), servers: Vec::new(),
servers: Vec::new(), config: HashMap::new(),
config: HashMap::new(), config_file: PathBuf::new(),
config_file: PathBuf::new(), workers: rayon::ThreadPoolBuilder::new()
workers: rayon::ThreadPoolBuilder::new() .num_threads(4)
.num_threads(4) .build()
.build() .unwrap(),
.unwrap(), worker_txes: Vec::new(),
worker_txes: Vec::new(), main_tx,
main_tx, history: Vec::new(),
history: Vec::new(), log: Vec::new(),
log: Vec::new(), output: Vec::new(),
output: Vec::new(), selected_server: 0,
selected_server: 0, selected_project: 0,
selected_project: 0, curent_intput: String::new(),
curent_intput: String::new(), module_loader: ModuleLoader::new(),
module_loader: ModuleLoader::new(), output_scroll: 0,
output_scroll: 0, output_follow: true,
output_follow: true, prompt: Prompt {
prompt: Prompt { action: None,
action: None, responses: Vec::new(),
responses: Vec::new(), execute_command: String::new(),
execute_command: String::new(), num_responses: 0,
num_responses: 0, prompts: Vec::new(),
prompts: Vec::new(), last_prompted: None,
},
info_scroll: 0,
server_broker_running: true,
app_state_running: true,
remoting: false,
help: Vec::new(),
name: String::new(),
}, },
main_rx, info_scroll: 0,
) server_broker_running: true,
app_state_running: true,
remoting: false,
help: Vec::new(),
name: String::new(),
}
} }
pub fn load_config(&mut self, file: PathBuf) -> Result<(), Box<dyn Error>> { pub fn load_config(&mut self, file: PathBuf, display: bool) -> Result<(), Box<dyn Error>> {
self.config_file = file.clone(); self.config_file = file.clone();
let config_contents = read_to_string(file)?; let config_contents = read_to_string(file)?;
for line in config_contents.lines() { for line in config_contents.lines() {
@@ -187,7 +188,7 @@ impl AppState {
if conf_file.file_name().to_string_lossy() == "project.conf".to_string() { if conf_file.file_name().to_string_lossy() == "project.conf".to_string() {
let mut new_project = Project::new(); let mut new_project = Project::new();
new_project.config_folder(conf_file.path()); new_project.config_folder(conf_file.path());
new_project.load_config()?; new_project.load_config(display)?;
let template_box = self.config.get("template_box").unwrap(); let template_box = self.config.get("template_box").unwrap();
let tools = self.config.get("tools").unwrap(); let tools = self.config.get("tools").unwrap();
let db = DistroBox { let db = DistroBox {
@@ -242,6 +243,7 @@ impl AppState {
); );
self.help.push("parse_scope\nparse the projects general.md notes file for the scope copied from the workbook\n".to_string()); self.help.push("parse_scope\nparse the projects general.md notes file for the scope copied from the workbook\n".to_string());
self.help.push("exit\nquit the tool\n".to_string()); self.help.push("exit\nquit the tool\n".to_string());
self.initialize_modules();
return Ok(()); return Ok(());
} }
@@ -427,10 +429,12 @@ impl AppState {
} }
} }
"remove_project_confirm" => { "remove_project_confirm" => {
self.prompt.action = None;
self.prompt.num_responses = 0;
if self.prompt.responses.len() > 0 { if self.prompt.responses.len() > 0 {
if self.prompt.responses[0] == "y".to_string() { if self.prompt.responses[0]
.response
.to_lowercase()
.contains("y")
{
let project = self.projects[self.selected_project].clone(); let project = self.projects[self.selected_project].clone();
let mut config_file = project.config_folder.clone(); let mut config_file = project.config_folder.clone();
config_file.pop(); config_file.pop();
@@ -507,14 +511,17 @@ impl AppState {
self.prompt.action = Some(ToolMessage::RemoveProject); self.prompt.action = Some(ToolMessage::RemoveProject);
self.prompt.num_responses = 1; self.prompt.num_responses = 1;
self.prompt.execute_command = String::from("remove_project_confirm"); self.prompt.execute_command = String::from("remove_project_confirm");
let _ = self.main_tx.send(ToolMessage::Output(( self.prompt.prompts.push(PromptQuery {
rid, id: 0,
format!( query: format!(
"{}, {} and all contents will be deleted. Continue? (y/N)", "{}, {} and all contentes wil lbe deleted. Contineue? (y/N",
project.files.display(), project.files.display(),
project.notes.display() project.notes.display()
), ),
))); });
let _ = self
.main_tx
.send(ToolMessage::Input((rid, "prompt".to_string())));
} }
"new_terminal" | "nt" => { "new_terminal" | "nt" => {
let project = self.projects[self.selected_project].clone(); let project = self.projects[self.selected_project].clone();
@@ -528,17 +535,30 @@ impl AppState {
self.prompt.num_responses = 2; self.prompt.num_responses = 2;
self.prompt.action = Some(ToolMessage::AddServer); self.prompt.action = Some(ToolMessage::AddServer);
self.prompt.execute_command = String::from("add_server"); self.prompt.execute_command = String::from("add_server");
self.prompt.prompts = vec![ self.prompt.prompts.push(PromptQuery {
"What is the IP for the server?".to_string(), id: 0,
"What is the port for the server?".to_string(), query: "What is the IP of the server?".to_string(),
]; });
self.prompt.prompts.push(PromptQuery {
id: 1,
query: "What is the port for the server?".to_string(),
});
let _ = self let _ = self
.main_tx .main_tx
.send(ToolMessage::Input((0, "prompt".to_string()))); .send(ToolMessage::Input((0, "prompt".to_string())));
} }
"add_server" => { "add_server" => {
let mut ip = String::new();
let mut port = String::new();
self.prompt.responses.iter().for_each(|res| {
if res.query.id == 0 {
ip = res.response.clone();
} else if res.query.id == 1 {
port = res.response.clone();
}
});
let new_server = Server { let new_server = Server {
address: format!("{}:{}", self.prompt.responses[0], self.prompt.responses[1]), address: format!("{}:{}", ip, port),
connected: false, connected: false,
timer: Duration::from_secs(5), timer: Duration::from_secs(5),
last_check: time::Instant::now(), last_check: time::Instant::now(),
@@ -565,12 +585,20 @@ impl AppState {
.send(ToolMessage::Input((0, self.prompt.execute_command.clone()))); .send(ToolMessage::Input((0, self.prompt.execute_command.clone())));
let _ = self.main_tx.send(ToolMessage::EndPrompt); let _ = self.main_tx.send(ToolMessage::EndPrompt);
} else { } else {
let mut prompt_index = 0; for query in &self.prompt.prompts {
if self.prompt.responses.len() > 0 { if !self
prompt_index = self.prompt.num_responses - self.prompt.responses.len(); .prompt
.responses
.iter()
.any(|res| res.query.id == query.id)
{
self.prompt.last_prompted = Some(query.clone());
let _ = self
.main_tx
.send(ToolMessage::Output((rid, query.query.clone())));
break;
}
} }
let query = self.prompt.prompts[prompt_index].clone();
let _ = self.main_tx.send(ToolMessage::Output((rid, query)));
} }
} }
"list_servers" => { "list_servers" => {
@@ -614,7 +642,10 @@ impl AppState {
"select_server" => { "select_server" => {
self.prompt.action = Some(ToolMessage::SelectServer); self.prompt.action = Some(ToolMessage::SelectServer);
self.prompt.num_responses = 1; self.prompt.num_responses = 1;
self.prompt.prompts.push(String::from("Selection?")); self.prompt.prompts.push(PromptQuery {
id: 0,
query: String::from("Selection?"),
});
self.prompt.execute_command = String::from("server_selected"); self.prompt.execute_command = String::from("server_selected");
self.servers.iter().enumerate().for_each(|(id, servermut)| { self.servers.iter().enumerate().for_each(|(id, servermut)| {
if let Ok(server) = servermut.lock() { if let Ok(server) = servermut.lock() {
@@ -634,7 +665,7 @@ impl AppState {
} }
"server_selected" => { "server_selected" => {
if self.prompt.responses.len() == 1 { if self.prompt.responses.len() == 1 {
if let Ok(id) = self.prompt.responses[0].parse::<usize>() { if let Ok(id) = self.prompt.responses[0].response.parse::<usize>() {
self.selected_server = id; self.selected_server = id;
if let Ok(server) = self.servers[id].lock() { if let Ok(server) = self.servers[id].lock() {
let _ = self.main_tx.send(ToolMessage::Output(( let _ = self.main_tx.send(ToolMessage::Output((
@@ -855,6 +886,67 @@ impl AppState {
} }
} }
} }
"new_config" => {
self.prompt.num_responses = 8;
self.prompt.action = Some(ToolMessage::Input((0, "add_config".to_string())));
self.prompt.execute_command = String::from("add_config");
self.prompt.prompts.push(PromptQuery {
id: 0,
query: "name for the new config?".to_string(),
});
self.prompt.prompts.push(PromptQuery {
id: 1,
query: "Path to save the config folder?".to_string(),
});
self.prompt.prompts.push(PromptQuery {
id: 2,
query: "Path for upcoming project files (not notes)?".to_string(),
});
self.prompt.prompts.push(PromptQuery {
id: 3,
query: "Path for current project files (not notes)?".to_string(),
});
self.prompt.prompts.push(PromptQuery {
id: 4,
query: "Path for upcoming notes?".to_string(),
});
self.prompt.prompts.push(PromptQuery {
id: 5,
query: "Path for current notes?".to_string(),
});
self.prompt.prompts.push(PromptQuery {
id: 6,
query: "Path to tool directory?".to_string(),
});
self.prompt.prompts.push(PromptQuery {
id: 7,
query: "Template box name?".to_string(),
});
let _ = self
.main_tx
.send(ToolMessage::Input((0, "prompt".to_string())));
}
"add_config" => {
self.prompt.responses.iter().for_each(|res| {
let _ = self.main_tx.send(ToolMessage::Output((
rid,
format!("{} | {}", res.query.query, res.response),
)));
});
self.new_config()?;
self.save_config()?;
}
"list_configs" => {
if let Some(config_line) = self.config.get("alternate_configs") {
config_line.split(",").into_iter().for_each(|entry| {
if let Some((name, path)) = entry.split_once("|") {
let _ = self
.main_tx
.send(ToolMessage::Output((rid, format!("{}: {}", name, path))));
}
});
}
}
"exit" => { "exit" => {
self.save_all()?; self.save_all()?;
let _ = self.main_tx.send(ToolMessage::AppStateExit); let _ = self.main_tx.send(ToolMessage::AppStateExit);
@@ -938,7 +1030,11 @@ impl AppState {
let out_string = result let out_string = result
.into_string() .into_string()
.unwrap_or_else(|_| "failed to parse string".into()); .unwrap_or_else(|_| "failed to parse string".into());
if cmd_meta.calls != "none" { if cmd_meta.calls == "clipboard" {
let mut ctx: ClipboardContext =
ClipboardProvider::new().unwrap();
ctx.set_contents(out_string.clone()).unwrap();
} else if cmd_meta.calls != "none" {
let _ = let _ =
worker_tx.send(ToolMessage::Input((0, out_string.clone()))); worker_tx.send(ToolMessage::Input((0, out_string.clone())));
} }
@@ -1173,50 +1269,193 @@ impl AppState {
return Ok(()); return Ok(());
} }
pub fn new_server(&mut self, rid: usize) -> Result<(), Box<dyn Error>> { pub fn new_server(&mut self) -> Result<(), Box<dyn Error>> {
let prompt = self.prompt.clone(); let mut ip = String::new();
if prompt.responses.len() == prompt.num_responses { let mut port = String::new();
let new_server = Server { self.prompt.responses.iter().for_each(|res| {
address: format!( if res.query.id == 0 {
"{}:{}", ip = res.response.clone();
self.prompt.responses[0].clone(), } else if res.query.id == 1 {
self.prompt.responses[1].clone() port = res.response.clone();
), }
connected: false, });
timer: Duration::from_secs(60), let new_server = Server {
last_check: time::Instant::now(), address: format!("{}:{}", ip, port),
message_que: Vec::new(), connected: false,
action_que: Vec::new(), timer: Duration::from_secs(60),
client_id: 0, last_check: time::Instant::now(),
selected_client: 0, message_que: Vec::new(),
config: None, action_que: Vec::new(),
logged_in: false, client_id: 0,
password: String::new(), selected_client: 0,
name: String::new(), config: None,
cert_text: String::new(), logged_in: false,
}; password: String::new(),
self.servers.push(Arc::new(Mutex::new(new_server))); name: String::new(),
self.prompt.action = None; cert_text: String::new(),
self.prompt.responses.clear(); };
self.prompt.num_responses = 0; self.servers.push(Arc::new(Mutex::new(new_server)));
return Ok(()); self.prompt.reset();
} else { Ok(())
match prompt.responses.len() { }
0 => {
let _ = self.main_tx.send(ToolMessage::Output(( pub fn new_config(&mut self) -> Result<(), Box<dyn Error>> {
rid, let mut name = String::new();
String::from("What is the IP for the server?"), let mut config_path = PathBuf::new();
))); let mut upcoming_files_path = PathBuf::new();
} let mut current_files_path = PathBuf::new();
1 => { let mut upcoming_notes_path = PathBuf::new();
let _ = self.main_tx.send(ToolMessage::Output(( let mut current_notes_path = PathBuf::new();
rid, let mut tools_folder = PathBuf::new();
String::from("What is the port for the server?"), let mut template_box = String::new();
))); let term_cmd = self.config.get("term_cmd").unwrap().clone();
} self.prompt
.responses
.iter()
.for_each(|res| match res.query.id {
0 => name = res.response.clone(),
1 => config_path = PathBuf::from(res.response.clone()),
2 => upcoming_files_path = PathBuf::from(res.response.clone()),
3 => current_files_path = PathBuf::from(res.response.clone()),
4 => upcoming_notes_path = PathBuf::from(res.response.clone()),
5 => current_notes_path = PathBuf::from(res.response.clone()),
6 => tools_folder = PathBuf::from(res.response.clone()),
7 => template_box = res.response.clone(),
_ => {} _ => {}
});
let mut existing = false;
if let Some(line) = self.config.get("alternate_configs") {
line.split(",").into_iter().for_each(|line| {
if let Some((ename, _)) = line.split_once("|") {
if ename.trim().to_string() == name {
existing = true;
}
}
});
}
if existing {
let _ = self.main_tx.send(ToolMessage::Output((
0,
format!("{} already exists!", name),
)));
return Ok(());
}
let root_config_folder_path = config_path.clone();
let mut projects_path = config_path.clone();
projects_path.push("projects");
let mut module_path = config_path.clone();
module_path.push("modules");
let mut note_templates_path = config_path.clone();
note_templates_path.push("note_templates");
create_dir_all(&module_path)?;
config_path.push("client.conf");
let client_conf_path = config_path.clone();
projects_path.push("default");
match create_dir_all(&projects_path) {
Ok(_) => {
let _ = self.main_tx.send(ToolMessage::Output((
0,
format!(
"[success] create projects path at {}",
projects_path.display()
),
)));
}
Err(e) => {
let _ = self.main_tx.send(ToolMessage::Output((
0,
format!(
"[error] couldn't create projects path at {}: {e}",
projects_path.display()
),
)));
return Ok(());
} }
} }
projects_path.push("project.conf");
let mut client_config_file = File::create(&config_path)?;
client_config_file.write(format!("projects: {}\n", projects_path.display()).as_bytes())?;
client_config_file.write("servers: 127.0.0.1:31337\n".as_bytes())?;
let mut default_project_file = File::create(projects_path)?;
config_path.pop();
let mut server_path = config_path.clone();
server_path.push("server");
create_dir_all(&server_path)?;
server_path.push("server.conf");
let mut server_config_file = File::create(&server_path)?;
server_config_file.write("address: 127.0.0.1:31337\n".as_bytes())?;
server_config_file.write("running: false\n".as_bytes())?;
default_project_file.write("org_name: default\n".as_bytes())?;
default_project_file.write("name: default\n".as_bytes())?;
default_project_file
.write(format!("notes: {}\n", current_files_path.display()).as_bytes())?;
default_project_file
.write(format!("files: {}\n", current_notes_path.display()).as_bytes())?;
default_project_file.write("stage: current".as_bytes())?;
client_config_file
.write(format!("current_files: {}\n", current_files_path.display()).as_bytes())?;
client_config_file
.write(format!("current_notes: {}\n", current_notes_path.display()).as_bytes())?;
client_config_file
.write(format!("upcoming_files: {}\n", upcoming_files_path.display()).as_bytes())?;
client_config_file
.write(format!("upcoming_notes: {}\n", upcoming_notes_path.display()).as_bytes())?;
client_config_file.write(format!("module_path: {}\n", module_path.display()).as_bytes())?;
client_config_file.write(format!("template_box: {}\n", template_box).as_bytes())?;
client_config_file.write(format!("term_cmd: {}\n", term_cmd).as_bytes())?;
client_config_file.write(format!("tools: {}\n", tools_folder.display()).as_bytes())?;
create_dir_all("./temp")?;
env::set_current_dir("./temp")?;
let git_clone_output = Command::new("git")
.arg("clone")
.arg("https://git.pyro.monster/pyro/tetanus.git")
.output()?;
let git_clone_status = git_clone_output.status.success();
if git_clone_status {
let mut options = CopyOptions::new();
options.overwrite = true;
options.copy_inside = true;
copy(
"./tetanus/note_templates",
root_config_folder_path.clone(),
&options,
)?;
copy(
"./tetanus/default-modules",
module_path.join("default"),
&options,
)?;
copy(
"./tetanus/victim_templates",
root_config_folder_path.join("victim"),
&options,
)?;
env::set_current_dir("../")?;
remove_dir_all("./temp")?;
let _ = self.main_tx.send(ToolMessage::Output((
0,
"New config structure created!".to_string(),
)));
}
if let Some(original_value) = self.config.get("alternate_configs") {
let new_value = format!(
"{}|{},{}",
name,
client_conf_path.display().to_string(),
original_value,
);
self.config
.insert("alternate_configs".to_string(), new_value);
} else {
self.config.insert(
"alternate_configs".to_string(),
format!("{}|{},", name, client_conf_path.display().to_string()),
);
}
self.prompt.responses.clear();
self.prompt.prompts.clear();
self.prompt.action = None;
self.prompt.execute_command.clear();
Ok(()) Ok(())
} }
} }
@@ -1413,7 +1652,7 @@ impl Project {
} }
} }
pub fn load_config(&mut self) -> Result<(), Box<dyn Error>> { pub fn load_config(&mut self, display: bool) -> Result<(), Box<dyn Error>> {
let config_contents = read_to_string(&self.config_folder)?; let config_contents = read_to_string(&self.config_folder)?;
for line in config_contents.lines() { for line in config_contents.lines() {
let parts: Vec<&str> = line.split(": ").collect(); let parts: Vec<&str> = line.split(": ").collect();
@@ -1438,8 +1677,10 @@ impl Project {
} }
} }
} }
println!("{} | {} config loaded!", self.org_name, self.name); if display {
println!("loading hosts..."); println!("{} | {} config loaded!", self.org_name, self.name);
println!("loading hosts...");
}
let mut hosts_folder = self.config_folder.clone(); let mut hosts_folder = self.config_folder.clone();
let mut users_folder = self.config_folder.clone(); let mut users_folder = self.config_folder.clone();
hosts_folder.pop(); hosts_folder.pop();
@@ -1512,7 +1753,9 @@ impl Project {
} }
} }
} }
println!("{} | {} loaded!", self.org_name, self.name); if display {
println!("{} | {} loaded!", self.org_name, self.name);
}
return Ok(()); return Ok(());
} }
@@ -1811,6 +2054,17 @@ impl ModuleLoader {
} }
results results
}); });
engine.register_fn("filter_ips", |s: &str| -> rhai::Array {
let mut results = rhai::Array::new();
if let Ok(net) = s.trim().parse::<IpNet>() {
results.push(net.addr().to_string().trim().into());
} else if let Ok(ip) = s.trim().parse::<IpAddr>() {
results.push(ip.to_string().trim().into());
} else if s.contains(".") {
results.push(s.to_string().trim().into());
}
results
});
engine.register_fn("write_file", |path: &str, contents: &str| { engine.register_fn("write_file", |path: &str, contents: &str| {
std::fs::write(path, contents).is_ok() std::fs::write(path, contents).is_ok()
}); });
@@ -2133,10 +2387,11 @@ impl DistroBox {
#[derive(Clone)] #[derive(Clone)]
struct Prompt { struct Prompt {
action: Option<ToolMessage>, action: Option<ToolMessage>,
responses: Vec<String>, responses: Vec<PromptResponse>,
execute_command: String, execute_command: String,
num_responses: usize, num_responses: usize,
prompts: Vec<String>, prompts: Vec<PromptQuery>,
last_prompted: Option<PromptQuery>,
} }
impl Prompt { impl Prompt {
@@ -2146,5 +2401,18 @@ impl Prompt {
self.execute_command.clear(); self.execute_command.clear();
self.num_responses = 0; self.num_responses = 0;
self.prompts.clear(); self.prompts.clear();
self.last_prompted = None;
} }
} }
#[derive(Clone)]
struct PromptResponse {
query: PromptQuery,
response: String,
}
#[derive(Clone)]
struct PromptQuery {
id: usize,
query: String,
}
+21 -4
View File
@@ -1,7 +1,10 @@
use clap::Parser; use clap::Parser;
use rand::RngExt; use rand::RngExt;
use rand::distr::Alphanumeric; use rand::distr::Alphanumeric;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread::{sleep, spawn};
use std::time::Duration;
use std::{env, path::PathBuf, process::exit}; use std::{env, path::PathBuf, process::exit};
use sysinfo::*; use sysinfo::*;
use tetanus::funcs::*; use tetanus::funcs::*;
@@ -138,8 +141,8 @@ async fn main() {
); );
exit(1); exit(1);
} }
let (mut appstate, rx) = AppState::new(); let (mut appstate) = AppState::new();
let config_load = appstate.load_config(client_config_path.clone()); let config_load = appstate.load_config(client_config_path.clone(), true);
if config_load.is_err() { if config_load.is_err() {
eprintln!("error loading config!"); eprintln!("error loading config!");
exit(1); exit(1);
@@ -148,9 +151,23 @@ async fn main() {
banner.lines().for_each(|line| { banner.lines().for_each(|line| {
appstate.output.push(line.to_string()); appstate.output.push(line.to_string());
}); });
appstate.initialize_modules(); let handles = Arc::new(Mutex::new(Vec::new()));
let handles_clone = handles.clone();
println!("entering tui..."); println!("entering tui...");
let _res = run_tui(appstate, rx).unwrap(); let primary_handle = spawn(move || {
let _ = startup(appstate, false, handles_clone);
});
if let Ok(mut lock) = handles.lock() {
lock.push(primary_handle);
}
loop {
sleep(Duration::from_secs(3));
if let Ok(lock) = handles.lock() {
if lock.iter().all(|handle| handle.is_finished()) {
break;
}
}
}
} else if args.server { } else if args.server {
let mut address = "127.0.0.1:31337".to_string(); let mut address = "127.0.0.1:31337".to_string();
let mut certificate_path = config_path.clone(); let mut certificate_path = config_path.clone();
+40
View File
@@ -1,4 +1,6 @@
use crate::*; use crate::*;
use aes_gcm::{Aes256Gcm, Key, KeyInit, Nonce, aead::Aead};
use rand::{self, Rng, TryRng};
use rayon::spawn; use rayon::spawn;
pub fn generate_code( pub fn generate_code(
@@ -46,6 +48,44 @@ pub fn generate_code(
return Ok(()); return Ok(());
} }
/*fn generate_obfuscated_code(
address: String,
password: String,
config_file: PathBuf,
files: PathBuf,
target: String,
tx: Sender<ToolMessage>,
cert_text: String,
) -> Result<(), Box<dyn Error>> {
let mut source_path = config_file.clone();
source_path.pop();
source_path.push("victim/src/main.rs");
let mut source = read_to_string(&source_path)?;
source = source
.replace("|||SERVER|||", &address)
.replace("|||PASSWORD|||", &password)
.replace("|||CERT|||", &cert_text);
files_base.pop();
files_base.pop();
files_base.push("Cargo.toml");
let cargo_string = read_to_string(source_path)?;
let mut files_base = files.clone();
files_base.push("victim/src");
create_dir_all(&files_base)?;
files_base.push("main.rs");
let mut src_file = File::create(&files_base)?;
let mut key = [0u8; 32];
rand::rng().fill_bytes(&mut key);
let mut iv = [0u8; 16];
rand::rng().fill_bytes(&mut iv);
let cipher = Aes256Gcm::new_from_slice(&key)?;
let nonce = Nonce::try_from(&iv[..])?;
let mut ciphertext = cipher.encrypt(&nonce, source.as_bytes())?;
Ok(())
}*/
fn compile_victim(mut cargo_command: Command, tx: Sender<ToolMessage>) { fn compile_victim(mut cargo_command: Command, tx: Sender<ToolMessage>) {
let mut out = "Error compiling output!".to_string(); let mut out = "Error compiling output!".to_string();
if let Ok(output) = cargo_command.output() { if let Ok(output) = cargo_command.output() {