started work on writing the tool, its not quite ready yet, but we're

getting close.
This commit is contained in:
pyro57000
2025-11-14 16:53:06 -06:00
parent 47d6ed5556
commit 1a72bcee98
30 changed files with 2248 additions and 0 deletions

5
.gitignore vendored
View File

@@ -19,3 +19,8 @@ target
# and can be added to the global gitignore or merged into this file. For a more nuclear # and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/ #.idea/
# Added by cargo
/target

676
Cargo.lock generated Normal file
View File

@@ -0,0 +1,676 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aead"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
"crypto-common",
"generic-array",
]
[[package]]
name = "anstream"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.60.2",
]
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bytes"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chacha20"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "chacha20poly1305"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
dependencies = [
"aead",
"chacha20",
"cipher",
"poly1305",
"zeroize",
]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
"zeroize",
]
[[package]]
name = "clap"
version = "4.5.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "colorchoice"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[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]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"rand_core",
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "inout"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [
"generic-array",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "libc"
version = "0.2.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "mio"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
dependencies = [
"libc",
"wasi",
"windows-sys 0.61.2",
]
[[package]]
name = "once_cell_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "poly1305"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
dependencies = [
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
dependencies = [
"libc",
"windows-sys 0.60.2",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tetanus_client"
version = "0.1.0"
dependencies = [
"chacha20poly1305",
"clap",
"colored",
"tokio",
"walkdir",
]
[[package]]
name = "tokio"
version = "1.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
dependencies = [
"bytes",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "typenum"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
name = "unicode-ident"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
[[package]]
name = "universal-hash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
"crypto-common",
"subtle",
]
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.5",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
"windows_i686_gnullvm 0.53.1",
"windows_i686_msvc 0.53.1",
"windows_x86_64_gnu 0.53.1",
"windows_x86_64_gnullvm 0.53.1",
"windows_x86_64_msvc 0.53.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "zeroize"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"

11
Cargo.toml Normal file
View File

@@ -0,0 +1,11 @@
[package]
name = "tetanus_client"
version = "0.1.0"
edition = "2024"
[dependencies]
chacha20poly1305 = "0.10.1"
clap = { version = "4.5.51", features = ["derive"] }
colored = "3.0.0"
tokio = { version = "1.48.0", features = ["full"] }
walkdir = "2.5.0"

View File

@@ -0,0 +1,66 @@
# directory bruteforcing
- [ ] url
- [ ] continue as needed
---
# Login Attacks
## URL or host:port
- [ ] stuffed
- [ ] sprayed
- [ ] bureforced
- [ ] default
## continue as needed
---
# Main password spray
- [ ] 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!
---
# service 1
## host
ports:
(notes)
## continue as neded
---

View File

@@ -0,0 +1,17 @@
# finding 1
## affected hosts
- host1
(continue as needed)
---
# finding 2
## affected hosts
- host1
(coninute as needed

View File

@@ -0,0 +1,27 @@
# scope
(paste scope from workbook)
# PPC
Planning call notes:
- methodolgy
- whole month testing window
- start with a vuln scan in nessus pro
- pentesting execution standard framework
- info gathering
- recon
- exlpoitation
- reporting
- primary objective
- reasonable and expected protections are in place
- see if we can get access to the internal network
- if we do get inside
- reach out to the contact and see what they'd want us to know
- questions to ask
- custom objectives
-
- testing main website
- password attacks
- password sprays 3-12 hours
- lock out policy -

View File

@@ -0,0 +1,8 @@
# host 1
| port | service | link to attack notes |
| ---- | ------- | -------------------- |
---
(continue as needed)

View File

@@ -0,0 +1,94 @@
Got Persistence via (schtasks, bat schtasks, startup folder)
(screenshot)
---
(link important info in initialenum.md here)
---
# powerup.ps1/sharpup.exe notes.
(screenshot)
---
# kerberoast notes
- [ ] worked via rubeus
- [ ] worked via encrypted rubeus
- [ ] worked via netexec
(screenshot)
---
# password spray notes
worked via (exeasm nefariousspray | inline nefarious spray | powershell tool | other tool)
- [ ] 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!
---
# bloodhound notes
- [ ] worked via exeasm sharphound
- [ ] worked via inline sharphound
- [ ] worked via encrypted sharphound
- [ ] worked via rusthound
(notes about intial lateral movement paths)
(screenshot)
---
# portscan notes
- [ ] gathered via cobalt strike portscan
- [ ] host enumeration via cmd
- [ ] gathered via powershell
- [ ] gathered via nmap
- [ ] gathered via other tool (specify here)
(screenshot)
SSH count:
FTP count:
RDP count:
MSSQL count:
mysql count:
(continue as needed)
---

View File

@@ -0,0 +1,2 @@
- [ ] Breach machine C-temp-fr
- [ ] (continue to add as needed

View File

@@ -0,0 +1,10 @@
# normal findings
---
# data exfil
## starting user name (fill this out)
## other user (or domain admin) (fill this out)

View File

@@ -0,0 +1,50 @@
# Scope
(past in scope from workbook excel sheet
---
# PPC
Introductions
Let them know that their primary contact will be the PM and there should be
Go over general attack strategy/procedure.
We will get a beacon payload by the time the test starts
The beacon payload should be executed on a domain joined windows system.
If the system is not domain joined/no domain - let Seth know as this modifies the standard beacon
Select a user based on a department/role that they would like tested (Marketing, Sales, HR, IT)
This can be a test system with a cloned user, but then we don't get keylogging or screen grabs
The beacon is created using Cobalt Strike and communicates over HTTPS
Since Cobalt Strike is very well signatured, remind them that they may need to add an exclusion in antivirus and/or web filter
We will look at local privilege escalation, conduct portscans, password sprays, targeted vulnerability scanning (NOT NESSUS), lateral movement opportunities, and escalating to DOMAIN ADMIN privilege.
Ask if they want a focus on any particular assets. for example, an old time logging system, or remote access system.
Confirm On Prem AD vs NoAD or Azure AD
- [ ] on prem
- [ ] azure ad
- [ ] hybrid (no on prem dcs)
- [ ] hybrid (on prem dcs)
ask about sensitive systems that scanning may crash
- (system 1)
- (continue as needed)
ask about secondary objective
- (object 1)
- (continue as needed)
ask about emergency contacts
| name | method | contact info |
| ---- | ------ | ------------ |
Ask if they have any questions or concerns
- question to follow up on 1
- (continue as needed)
Email any follow-up items from the call to the PM

View File

@@ -0,0 +1,11 @@
- [ ] local priv esc checks
- [ ] byosi easily possible?
- [ ] file enum
- [ ] bloodhound
- [ ] any admin?
- [ ] any rdp?
- [ ] certify
- [ ] portscan
- [ ] sql stuff
- [ ] passwords in AD description?
- [ ] password spray

View File

@@ -0,0 +1,5 @@
# url
## attack1 (sqli for example)
(notes and screenshots)

View File

@@ -0,0 +1,5 @@
# Finding 1
## url
(notes + screenshots)

View File

@@ -0,0 +1,9 @@
# scope
(paste scope from workbook)
---
# PPC
(ppc notes)

View File

@@ -0,0 +1,8 @@
# date
| name | number | notes |
| ---- | ------ | ----- |
---
(continue as needed)

View File

@@ -0,0 +1,7 @@
# enumeration findings
---
# Call findings

View File

@@ -0,0 +1,60 @@
# scope
(paste scope from workbook)
---
# ppc
have you been vished before?
- [ ] yes
- [ ] no
if yes:
what was the purpose of that attack?
- [ ] gain a foothold
- [ ] get protected data
- [ ] steal money
Our vishing tests generally have four main objectives
1. verbial confirmation of information
2. run commands on the system they're on
3. go to a specific website
4. join a screen shareing session with us and grant remote control
This simulates an attacker gaining a foothold on the network via vishing.
Are these objectives what you want to test for?
- [ ] yes
- [ ] no
custom objectives:
- (continue as needed)
Our default pretext is 3rd party IT
We'll call in claiming to be employees at an IT firm that were brought in to handle some of the basic maintence tasks such as computer inventory and updates.
We'll claim the inventory system had a glitch and that we're calling a few people to verify the information in our spreadsheet is correct.
We'll have the target verify some basic information about their computer and verify any information we can gather via OSINT
We'll then fabricate a reason to believe that our spreadsheet is incorrect and that it would require farther troubleshooting.
We'll ask them to run a few commands and read us the output to confirm this
We'll then offer a zoom call so they can share screen and speed up the troubleshooting process.
Does this pretext sound ok to you?
- [ ] yes
- [ ] no
Custom pretext:

View File

@@ -0,0 +1,38 @@
# default
Hello I'm (name fill this out) from (it firm fill this out). 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)?
great and your email is (email enumeration finding)?
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.
---
# custom
(fill out if needed)

View File

@@ -0,0 +1,5 @@
# URL
## attack1 (sqli for example)
(notes and screenshots)

View File

@@ -0,0 +1,5 @@
# finding 1
## URL
(notes + screenshot)

View File

@@ -0,0 +1,9 @@
# scope
(paste scope from workbook)
---
# PPC
(PPC notes)

149
src/cli.rs Normal file
View File

@@ -0,0 +1,149 @@
use std::io::Read;
use std::path::PathBuf;
use tokio::sync::mpsc::{Receiver, Sender, channel};
use crate::Message;
use crate::commands;
use crate::commands::ToolArgument;
use crate::commands::ToolCommand;
use crate::load_projects;
use crate::load_settings;
use crate::network;
use crate::print_error;
use crate::{Destination, Project, get_user_input, lib::Table, print_success};
use tokio;
pub async fn rec_message(mut rx: Receiver<Message>) {
let mut display = true;
loop {
let rx_res = rx.try_recv();
if rx_res.is_ok() {
let message = rx_res.unwrap();
println!("{}", message.content);
display = true;
}
if display {
println!("command?");
display = false;
}
}
}
pub async fn cli(
mut projects: Vec<Project>,
main_tx: Sender<Message>,
tool_tx: Sender<Message>,
server_address: String,
config_path: PathBuf,
) {
print_success("started the CLI!");
let mut commands = commands::build_tools();
loop {
let settings = load_settings(&config_path, false);
projects = load_projects(&config_path, false);
if tool_tx.is_closed() {
println!("tool tx closed at the start of this loop!");
}
let command = get_user_input("");
let mut command_name = String::new();
let mut args = Vec::new();
if command.contains(" ") {
let mut command_vec: Vec<&str> = command.split(" ").collect();
command_name = command_vec[0].to_string();
for arg in &mut command_vec[1..] {
args.push(arg.to_string());
}
} else {
command_name = command;
}
if command_name == String::from("exit") {
let message = Message {
source: Destination::Console,
destination: Destination::Control,
content: String::from("exit"),
};
main_tx.send(message).await.unwrap();
}
let mut valid_command = false;
for toolcommand in &mut commands {
let mut ready = true;
if toolcommand.name == command_name {
valid_command = true;
if toolcommand.req_args.len() > 0 {
let mut args_vec = Vec::new();
for req_arg in toolcommand.req_args.clone() {
let mut new_arg = ToolArgument::default();
new_arg.name = req_arg;
args_vec.push(new_arg);
}
println!("Required args:");
if args.len() < toolcommand.user_args.len() {
ready = false;
}
if ready {
let mut position_count = 0;
for user_arg in toolcommand.user_args.clone() {
println!("enough args supplied, building arguments list");
let mut new_arg = ToolArgument::default();
new_arg.name = user_arg;
new_arg.user_supplied = true;
new_arg.position = Some(position_count);
args_vec.push(new_arg);
position_count += 1;
}
}
if ready {
for arg in &mut args_vec {
let iargs = args.clone();
if arg.user_supplied {
arg.string = Some(iargs[arg.position.unwrap()].clone());
} else {
match arg.name.as_str() {
"projects" => arg.projects = Some(projects.clone()),
"upcoming_files" => {
arg.path =
Some(PathBuf::from(settings["upcoming_files"].clone()))
}
"upcoming_notes" => {
arg.path =
Some(PathBuf::from(settings["upcoming_notes"].clone()))
}
"template" => {
arg.string =
Some(String::from(settings["templatebox"].clone()))
}
"config" => arg.path = Some(config_path.clone()),
_ => print_error(
&format!("unkown arg requested! {}", arg.name),
None,
),
}
}
}
toolcommand.args = Some(args_vec);
}
println!("args parsed!");
}
let mut message = Message {
source: Destination::Console,
destination: Destination::Console,
content: String::new(),
};
if ready {
message.content = toolcommand.execute();
} else {
message.content = String::from("error in command!");
}
tool_tx.send(message).await.unwrap();
}
}
if !valid_command {
let message = Message {
source: Destination::Console,
destination: Destination::Console,
content: String::from("command not found!"),
};
tool_tx.send(message).await.unwrap();
}
}
}

186
src/commands.rs Normal file
View File

@@ -0,0 +1,186 @@
use crate::Destination;
use crate::Message;
use crate::Project;
use crate::lib::Table;
use crate::print_error;
use crate::print_success;
use crate::save_project;
use std::fs::create_dir;
use std::fs::create_dir_all;
use std::fs::{File, OpenOptions, ReadDir, read_to_string};
use std::io::Write;
use std::path::PathBuf;
use std::process::exit;
use tokio;
use tokio::sync::mpsc::{Receiver, Sender};
#[derive(Clone)]
pub struct ToolCommand {
pub name: String,
pub help: String,
pub req_args: Vec<String>,
pub user_args: Vec<String>,
pub args: Option<Vec<ToolArgument>>,
pub func: fn(Option<Vec<ToolArgument>>) -> String,
}
impl ToolCommand {
pub fn new(name: String, help: String, func: fn(Option<Vec<ToolArgument>>) -> String) -> Self {
Self {
name,
help,
req_args: Vec::new(),
user_args: Vec::new(),
args: None,
func,
}
}
pub fn execute(&self) -> String {
if self.req_args.len() > 0 {
if self.args.is_none() {
return String::from("Error: no arguments given, but arguments are required!");
} else if self.args.clone().unwrap().len() != self.req_args.len() + self.user_args.len()
{
return String::from("Error: the wrong number of args were supplied!");
}
}
return (self.func)(self.args.clone());
}
}
#[derive(Clone, Default)]
pub struct ToolArgument {
pub name: String,
pub user_supplied: bool,
pub position: Option<usize>,
pub path: Option<PathBuf>,
pub string: Option<String>,
pub project: Option<Project>,
pub projects: Option<Vec<Project>>,
pub boolean: Option<bool>,
}
pub fn build_tools() -> Vec<ToolCommand> {
let mut tool_commands = Vec::new();
let mut listproject = ToolCommand::new(
"list_projects".to_string(),
"coming soon".to_string(),
list_projects,
);
listproject.req_args = vec![String::from("projects")];
tool_commands.push(listproject);
let mut createproject = ToolCommand::new(
"create_project".to_string(),
"creates a new project and saves it to the projects file to be reloaded on the next loop
usage:
create_project project_name"
.to_string(),
new_project,
);
createproject.req_args = vec![
String::from("config"),
String::from("upcoming_files"),
String::from("upcoming_notes"),
String::from("template"),
];
createproject.user_args = vec![String::from("name")];
tool_commands.push(createproject);
return tool_commands;
}
pub fn list_projects(args: Option<Vec<ToolArgument>>) -> String {
let given_args = args.unwrap();
let mut lines = vec![String::from("name|stage|boxname")];
for arg in given_args {
if arg.name == String::from("projects") {
for project in arg.projects.unwrap() {
if project.current {
let line = format!("{}|{}|{}", project.name, "current", project.boxname);
lines.push(line);
} else {
let line = format!("{}|{}|{}", project.name, "upcomming", project.boxname);
lines.push(line);
}
}
}
}
let mut table = Table::default();
table.build(lines);
return table.get_table();
}
pub fn new_project(args: Option<Vec<ToolArgument>>) -> String {
println!("reached the new_project function");
let given_args = args.unwrap();
let mut config_path = PathBuf::new();
let mut name = String::new();
let mut files_path = PathBuf::new();
let mut notes_path = PathBuf::new();
let mut template_box = String::new();
for arg in given_args {
match arg.name.as_str() {
"config" => {
config_path = arg.path.unwrap();
}
"name" => {
name = arg.string.unwrap();
}
"upcoming_files" => {
files_path = arg.path.unwrap();
}
"upcoming_notes" => {
notes_path = arg.path.unwrap();
}
"template" => {
template_box = arg.string.unwrap();
}
_ => {}
}
}
if name.len() == 0 {
return String::from(
"usage: newproject projectname\nprevious command was missing project name!",
);
}
println!("gatered the data! name: {}", name);
print_success("arguments parsed correctly!");
println!("setting up files...");
let mut project_path = config_path.clone();
project_path.pop();
project_path.push("projects");
project_path.push(format!("{}.conf", &name));
let file_create_res = File::create(&project_path);
if file_create_res.is_err() {
return format!(
"Error failure to create project config file!\n{}\n{}",
file_create_res.err().unwrap(),
&project_path.display().to_string()
);
}
let conf_file = file_create_res.unwrap();
files_path.push(&name);
notes_path.push(&name);
let files_dir_res = create_dir_all(&files_path);
let notes_dir_res = create_dir_all(&notes_path);
if files_dir_res.is_err() {
return (format!(
"Error failure to create project files folder!\n{}",
files_dir_res.err().unwrap()
));
}
if notes_dir_res.is_err() {
return (format!(
"Error failure to create project files folder!\n{}",
files_dir_res.err().unwrap()
));
}
let mut new_project = Project::default();
new_project.name = name.clone();
new_project.files = files_path;
new_project.notes = notes_path;
new_project.current = false;
new_project.boxname = format!("{}_{}", template_box, name);
save_project(&new_project, &project_path);
return String::from("Success!");
}

25
src/crytpo.rs Normal file
View File

@@ -0,0 +1,25 @@
use chacha20poly1305::aead::generic_array::typenum::Unsigned;
use chacha20poly1305::aead::generic_array::GenericArray;
use chacha20poly1305::aead::{Aead, AeadCore, KeyInit, OsRng};
use chacha20poly1305::ChaCha20Poly1305;
pub fn generate_key() -> Vec<u8> {
ChaCha20Poly1305::generate_key(&mut OsRng).to_vec()
}
pub fn encrypt(cleartext: &str, key: &[u8]) -> Vec<u8> {
let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(key));
let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
let mut obsf = cipher.encrypt(&nonce, cleartext.as_bytes()).unwrap();
obsf.splice(..0, nonce.iter().copied());
obsf
}
pub fn decrypt(obsf: &[u8], key: &[u8]) -> String {
type NonceSize = <ChaCha20Poly1305 as AeadCore>::NonceSize;
let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(key));
let (nonce, ciphertext) = obsf.split_at(NonceSize::to_usize());
let nonce = GenericArray::from_slice(nonce);
let plaintext = cipher.decrypt(nonce, ciphertext).unwrap();
String::from_utf8(plaintext).unwrap()
}

0
src/gui.rs Normal file
View File

229
src/install.rs Normal file
View File

@@ -0,0 +1,229 @@
use std::collections::HashMap;
use std::fs::{File, create_dir_all, read_to_string, remove_file};
use std::io::Write;
use std::path::PathBuf;
use crate::get_user_input;
use crate::print_success;
use crate::{crytpo, print_error};
pub fn install(config: &PathBuf) -> bool {
let mut new = true;
let mut config_folder = config.clone();
config_folder.pop();
let mut config_file = config_folder.clone();
config_file.push("config.conf");
let mut project_config = config_folder.clone();
let mut note_templates_path = config_folder.clone();
project_config.push("projects");
note_templates_path.push("note_templates");
let mut settings = HashMap::new();
if !config_folder.exists() {
let dir_create_res = create_dir_all(&config_folder);
if dir_create_res.is_err() {
print_error(
"error creating configuration directory!",
Some(dir_create_res.err().unwrap().to_string()),
);
return false;
}
print_success("configuration folder created successfully!");
} else {
print_success("configuration folder already exists!");
}
if config_file.exists() {
if get_user_input("the config file already exists, would you like to delete it and create a full new one?").to_lowercase().contains("y"){
let remove_res = remove_file(&config_file);
if remove_res.is_err(){
print_error("error removing file, please manually delete and try again...", Some(remove_res.err().unwrap().to_string()));
return false;
}
if project_config.exists(){
let remove_res = remove_file(&project_config);
if remove_res.is_err(){
print_error("error removing projects file", Some(remove_res.err().unwrap().to_string()));
return false;
}
}
}
else{
new = false;
let config_read_res = read_to_string(&config_file);
if config_read_res.is_err(){
print_error("error reading config file!", Some(config_read_res.err().unwrap().to_string()));
return false;
}
let config_string = config_read_res.unwrap();
for line in config_string.lines(){
if line.contains(":"){
let line_vec: Vec<&str> = line.split(":").collect();
if settings.contains_key(line_vec[0]){
settings.remove(line_vec[0]);
settings.insert(line_vec[0].to_string(), line_vec[1].to_string());
}
else{
settings.insert(line_vec[0].to_string(), line_vec[1].to_string());
}
}
}
print_success("read existing config file successfully!");
println!("entering edit loop...");
loop{
println!("{}", config_string);
let setting = get_user_input("which setting would you like to change? (ENTER DONE IN ALL CAPS WHEN YOU'RE FINISHED");
let value = get_user_input("what would you like to change it to?");
if setting.contains("DONE"){
break;
}
else {
if settings.contains_key(&setting){
settings.remove(&setting);
settings.insert(setting, value);
}
else{
settings.insert(setting, value);
}
}
}
}
}
if !project_config.exists() {
let projects_create_res = create_dir_all(&project_config);
if projects_create_res.is_err() {
print_error(
"error creating projects directory!",
Some(projects_create_res.err().unwrap().to_string()),
);
}
}
if !note_templates_path.exists() {
let note_template_create_res = create_dir_all(&note_templates_path);
if note_template_create_res.is_err() {
print_error(
"error createing note_templates directory!",
Some(note_template_create_res.err().unwrap().to_string()),
);
}
}
if new {
println!("server_address|127.0.0.1:31337");
println!("key_file|{}/key", &config_folder.display());
println!("distrobox|yes");
if !get_user_input("are these defaults ok?")
.to_lowercase()
.contains("y")
{
let server_address = get_user_input("what is your server address then?");
let key_file = get_user_input("what is your key file then?");
if get_user_input("will you be using distrobox for your attack environments?")
.to_lowercase()
.contains("y")
{
settings.insert("distrobox".to_string(), "yes".to_string());
settings.insert(
"templatebox".to_string(),
get_user_input("name of your tempalte distrobox?"),
);
} else {
settings.insert("distrobox".to_string(), "no".to_string());
}
settings.insert("server_address".to_string(), server_address);
settings.insert("key_file".to_string(), key_file);
} else {
settings.insert("server_address".to_string(), "127.0.0.1:31337".to_string());
settings.insert(
"key_file".to_string(),
format!("{}/key", config_folder.display()),
);
settings.insert("distrobox".to_string(), "yes".to_string());
settings.insert(
"templatebox".to_string(),
get_user_input("name of the distrobox you will use?"),
);
}
settings.insert("current_files".to_string(), get_user_input("full path to where you want your current project's files stored? example: /home/pyro/projects/current"));
settings.insert("current_notes".to_string(), get_user_input("full path to where you want your current project's notes stored example: /home/pyro/notes/current"));
settings.insert("upcoming_files".to_string(),get_user_input("full path to where you want your upcoming project's files stored example: /home/pyro/projects/upcoming"));
settings.insert("upcoming_notes".to_string(), get_user_input("full path to where you want your upcoming project's notes stored exmple: /home/pyro/notes/upcoming"));
print_success("sweet, we have all we need, writing config file...");
let out_file_res = File::create_new(&config_file);
if out_file_res.is_err() {
print_error(
"error creating config file!",
Some(out_file_res.err().unwrap().to_string()),
);
return false;
}
let mut out_file = out_file_res.unwrap();
for setting in settings.keys() {
let outline = format!("{}|{}\n", setting, settings[setting]);
let write_res = out_file.write(outline.as_bytes());
if write_res.is_err() {
print_error(
"error writing to config file",
Some(write_res.err().unwrap().to_string()),
);
return false;
} else {
write_res.unwrap();
}
}
print_success("excellent we have created the client's config file!");
println!("creating projects config file and adding the default project...");
project_config.push("default.conf");
let projects_file_res = File::create_new(project_config);
if projects_file_res.is_err() {
print_error(
"error creating project config file!",
Some(projects_file_res.err().unwrap().to_string()),
);
return false;
}
for key in settings.keys() {
println!("{} : {}", key, settings[key]);
}
let mut project_file = projects_file_res.unwrap();
let mut out_line = format!(
"name|default\nstage|current\nfiles|{}\nnotes|{}",
settings["current_files"], settings["current_notes"]
);
if settings["distrobox"] == "yes".to_string() {
out_line = format!("{}\nboxname|{}", out_line, settings["templatebox"]);
}
let write_res = project_file.write(out_line.as_bytes());
if write_res.is_err() {
print_error(
"error writing to projects config file!",
Some(write_res.err().unwrap().to_string()),
);
return false;
}
}
println!("generating a new key for encryption...");
let key = crytpo::generate_key();
let mut key_path = config_folder.clone();
key_path.push("key");
if key_path.exists() {
let remove_res = remove_file(&key_path);
if remove_res.is_err() {
print_error(
"error removing keyfile",
Some(remove_res.err().unwrap().to_string()),
);
return false;
}
}
let key_file_res = File::create_new(key_path);
if key_file_res.is_err() {
print_error(
"error making key file!",
Some(key_file_res.err().unwrap().to_string()),
);
return false;
}
let mut key_file = key_file_res.unwrap();
key_file.write(&key).unwrap();
print_success("client successfully installed!");
print_success("please re-run this tool to use it!");
return true;
}

180
src/lib.rs Normal file
View File

@@ -0,0 +1,180 @@
use std::{
fs::{copy, create_dir_all},
path::PathBuf,
};
use walkdir::WalkDir;
#[derive(Default, Clone)]
pub struct Table {
columns: Vec<usize>,
headers: String,
data: Vec<String>,
}
impl Table {
pub fn build(&mut self, data: Vec<String>) -> Table {
self.headers = data[0].clone();
self.data = data[1..].to_vec();
let header_vec: Vec<&str> = self.headers.split("|").collect();
for header in header_vec {
self.columns.push(header.len());
}
for data in &self.data {
let data_vec: Vec<&str> = data.split("|").collect();
for id in 0..self.columns.len() {
if data_vec[id].len() > self.columns[id] {
self.columns[id] = data_vec[id].len();
}
}
}
for id in 0..self.columns.len() {
if self.columns[id] % 2 != 0 {
self.columns[id] += 1;
}
}
return self.clone();
}
pub fn get_table(&self) -> String {
let mut output = String::new();
let mut spacer = String::new();
let header_vec: Vec<&str> = self.headers.split("|").collect();
for id in 0..self.columns.len() {
spacer.push('|');
let mut cell = String::new();
let dashes = "-".repeat(self.columns[id]);
spacer.push_str(&dashes);
if header_vec[id].len() < self.columns[id] {
let mut padding_needed = self.columns[id] - header_vec[id].len();
if padding_needed % 2 != 0 {
padding_needed += 1;
}
let padding = padding_needed / 2;
cell = format!(
"|{}{}{}",
" ".repeat(padding),
header_vec[id],
" ".repeat(padding)
);
while cell.len() != self.columns[id] {
if cell.len() > self.columns[id] + 1 {
cell.pop();
} else if cell.len() > self.columns[id] + 1 {
cell.push(' ');
} else {
break;
}
}
output.push_str(&cell);
} else {
cell = format!("|{}", header_vec[id]);
output.push_str(&cell);
}
}
output.push_str("|\n");
spacer.push_str("|\n");
output.push_str(&spacer);
output.push_str(&spacer);
for data_line in self.data.clone() {
let line_vec: Vec<&str> = data_line.split("|").collect();
for id in 0..self.columns.len() {
let mut cell = String::new();
if line_vec[id].len() < self.columns[id] {
let mut padding_needed = self.columns[id] - line_vec[id].len();
if padding_needed % 2 != 0 {
padding_needed += 1;
}
let padding = padding_needed / 2;
cell = format!(
"|{}{}{}",
" ".repeat(padding),
line_vec[id],
" ".repeat(padding)
);
while cell.len() != self.columns[id] + 1 {
if cell.len() > self.columns[id] + 1 {
cell.pop();
} else if cell.len() < self.columns[id] + 1 {
cell.push(' ');
} else {
break;
}
}
} else {
cell = format!("|{}", line_vec[id]);
}
output.push_str(&cell);
}
output.push_str("|\n");
output.push_str(&spacer);
}
return output;
}
}
pub struct Server {
address: String,
id: usize,
}
#[derive(Clone)]
pub struct Message {
source: Destination,
destination: Destination,
content: String,
}
#[derive(Clone, PartialEq)]
pub enum Destination {
Console,
Server,
Control,
}
#[derive(Default, Clone)]
pub struct Project {
name: String,
files: PathBuf,
notes: PathBuf,
current: bool,
boxname: String,
}
impl Project {
pub fn generate_default_notes(&self, config_folder: &PathBuf) -> String {
let mut notes_template = config_folder.clone();
notes_template.pop();
notes_template.push("note_templates");
if self.name.contains("external") {
notes_template.push("external");
} else if self.name.contains("internal") {
notes_template.push("internal");
} else if self.name.contains("vishing") {
notes_template.push("vishing");
} else if self.name.contains("phishing") {
notes_template.push("phishing");
} else if self.name.contains("webapp") {
notes_template.push("webapp");
}
let walkdir = WalkDir::new(&notes_template);
for res in walkdir {
if res.is_ok() {
let entry = res.unwrap();
let file_name = entry.file_name().to_string_lossy().to_string();
if file_name.contains(".md") {
let mut temp_path = self.notes.clone();
temp_path.push(&file_name);
let copy_res = copy(entry.path(), &temp_path);
if copy_res.is_err() {
return (format!(
"Error copying note file {} to {}",
file_name,
temp_path.display()
));
}
copy_res.unwrap();
}
}
}
return String::from("Success!");
}
}

334
src/main.rs Normal file
View File

@@ -0,0 +1,334 @@
use chacha20poly1305::aead::generic_array::GenericArray;
use chacha20poly1305::aead::generic_array::typenum::Unsigned;
use chacha20poly1305::aead::{Aead, AeadCore, KeyInit, OsRng};
use chacha20poly1305::{ChaCha20Poly1305, Key};
use clap::Parser;
use colored::Colorize;
use std::collections::HashMap;
use std::fs::{self, File, OpenOptions, read_dir, read_to_string};
use std::io::{Read, Write};
use std::os::unix::net;
use std::path::{Display, PathBuf};
use std::process::{Output, exit};
use std::thread::sleep;
use std::time::Duration;
use std::{thread, time};
use tokio;
use tokio::sync::mpsc::{Receiver, Sender, channel};
mod cli;
mod commands;
mod crytpo;
mod install;
mod lib;
mod network;
#[derive(Debug, Parser)]
#[command(
version,
about,
long_about = "The server part of tetanus! It will read the config and load up any known clients and stuff."
)]
struct Args {
#[arg(
short,
long,
help = "the server to connect to, defaults to 127.0.0.1:31337"
)]
server: Option<String>,
#[arg(short, long, help = "launch in gui mode")]
gui: bool,
#[arg(
short,
long,
help = "a path to a custom config file, defaults to ~/.config/tetanus/clients/main_attacker.conf"
)]
config: Option<PathBuf>,
#[arg(short, long, help = "generate or re-generate the config file")]
install: bool,
#[arg(short, long, help = "custom name to give this client.")]
name: Option<String>,
}
pub fn print_success(text: &str) {
println!("{}", text.green());
}
pub fn print_error(text: &str, error: Option<String>) {
println!("{}", text.red());
if error.is_some() {
println!("{}", error.unwrap().red());
}
}
pub fn get_user_input(prompt: &str) -> String {
let mut response = String::new();
loop {
println!("{}", prompt);
let res = std::io::stdin().read_line(&mut response);
if res.is_err() {
print_error("we need input here dummy, try again...", None);
} else {
break;
}
}
return response.trim().to_string();
}
pub fn load_projects(path: &PathBuf, display: bool) -> Vec<Project> {
let mut projects_path = path.clone();
projects_path.pop();
projects_path.push("projects");
let project_dir_res = read_dir(projects_path);
if project_dir_res.is_err() {
print_error(
"error reading projects directory!",
Some(project_dir_res.err().unwrap().to_string()),
);
exit(1);
}
let project_dir = project_dir_res.unwrap();
let mut projects = Vec::new();
for res in project_dir {
if res.is_ok() {
let mut new_project = Project::default();
let entry = res.unwrap();
let file_name = entry.file_name().to_string_lossy().to_string();
if file_name.contains(".conf") {
let conf_string_res = read_to_string(entry.path());
if conf_string_res.is_ok() {
let conf_string = conf_string_res.unwrap();
for line in conf_string.lines() {
let line_vec: Vec<&str> = line.split("|").collect();
match line_vec[0] {
"name" => {
new_project.name = line_vec[1].trim().to_string();
}
"stage" => {
if line_vec[1].contains("current") {
new_project.current = true;
} else {
new_project.current = false;
}
}
"files" => {
new_project.files = PathBuf::from(line_vec[1]);
}
"notes" => {
new_project.notes = PathBuf::from(line_vec[1]);
}
"boxname" => new_project.boxname = String::from(line_vec[1]),
_ => {
print_error(
"unknown setting discoverd in project config file!",
None,
);
}
}
}
if new_project.boxname.len() > 0 {
projects.push(new_project);
} else {
new_project.boxname = String::from("none");
projects.push(new_project);
}
if display {
print_success(
format!(
"{} successfully loaded!",
entry.file_name().to_string_lossy()
)
.as_str(),
);
}
}
}
}
}
return projects;
}
pub fn save_project(project: &Project, config_path: &PathBuf) {
let mut conf_open_options = OpenOptions::new();
if config_path.exists() {
conf_open_options.append(true);
} else {
conf_open_options.create(true);
}
let conf_open_create_res = conf_open_options.open(config_path);
if conf_open_create_res.is_err() {
print_error(
"error opening project config path!",
Some(format!("{}", conf_open_create_res.err().unwrap())),
);
return;
}
let mut conf_file = conf_open_create_res.unwrap();
let config_string = format!(
"name|{}\nstage|upcoming\nfiles|{}\nnotes|{}\nboxname|{}",
project.name,
project.files.display(),
project.notes.display(),
project.boxname
);
write!(conf_file, "{}", config_string).unwrap();
print_success("project saved!");
}
pub fn load_settings(config_path: &PathBuf, display: bool) -> HashMap<String, String> {
let mut settings = HashMap::new();
let conf_read_res = read_to_string(&config_path);
if conf_read_res.is_err() {
print_error(
"error reading config file!",
Some(conf_read_res.err().unwrap().to_string()),
);
exit(1);
}
let conf_string = conf_read_res.unwrap();
if display {
println!("loading settings from config line...");
}
for line in conf_string.lines() {
if line.contains("|") {
let line_vec: Vec<&str> = line.split("|").collect();
settings.insert(line_vec[0].to_string(), line_vec[1].to_string());
if display {
print_success(format!("{} {} LOADED!", line_vec[0], line_vec[1]).as_str());
}
}
}
return settings;
}
#[tokio::main]
async fn main() {
let args = Args::parse();
let mut settings = HashMap::new();
let mut config_path = PathBuf::new();
let mut server_address = String::from("127.0.0.1:31337");
if args.config.is_some() {
config_path = args.config.unwrap();
} else {
let home_res = std::env::home_dir();
if home_res.is_some() {
config_path = home_res.unwrap();
config_path.push(".config/tetanus/clients/main_attacker/config.conf");
} else {
print_error(
"error finding config file!\nplease re-run while specifying a config file",
None,
);
}
}
if args.install {
let res = install::install(&config_path);
if res {
print_success("client successfully installed!");
print_success("please re-run this tool to use it!");
exit(0);
}
} else if !config_path.exists() {
println!("ooof no config file exitst at {}", config_path.display());
if get_user_input("would you like to create one?")
.to_lowercase()
.contains("y")
{
let status = install::install(&config_path);
if !status {
print_error("error installing...", None);
exit(1);
} else {
print_success("client successfully installed!");
print_success("please re-run this tool to use it!");
exit(0);
}
} else {
print_error("config file does not exist", None);
exit(1);
}
}
let conf_read_res = read_to_string(&config_path);
if conf_read_res.is_err() {
print_error(
"error reading config file!",
Some(conf_read_res.err().unwrap().to_string()),
);
exit(1);
}
let conf_string = conf_read_res.unwrap();
println!("loading settings from config line...");
for line in conf_string.lines() {
if line.contains("|") {
let line_vec: Vec<&str> = line.split("|").collect();
settings.insert(line_vec[0].to_string(), line_vec[1].to_string());
print_success(format!("{} {} LOADED!", line_vec[0], line_vec[1]).as_str());
}
}
let key_path = PathBuf::from(settings["key_file"].clone());
let mut key_vec = Vec::new();
let key_open_res = OpenOptions::new().read(true).open(key_path);
if key_open_res.is_err() {
print_error(
"error opening key file!",
Some(key_open_res.err().unwrap().to_string()),
);
exit(1);
}
let mut key_file = key_open_res.unwrap();
let key_read_res = key_file.read(&mut key_vec);
if key_read_res.is_err() {
print_error(
"error reading key",
Some(key_read_res.err().unwrap().to_string()),
);
exit(1);
}
key_read_res.unwrap();
let projects = load_projects(&config_path, true);
let mut server_address = String::from("127.0.0.1:31337");
if args.server.is_some() {
server_address = args.server.unwrap();
}
let (main_tx, mut main_rx) = channel(1024);
let (console_tx, console_rx) = channel(1024);
if !args.gui {
let input_handle = tokio::spawn(cli::cli(
projects,
main_tx.clone(),
console_tx.clone(),
server_address,
config_path,
));
thread::sleep(Duration::from_secs(1));
let output_handle = tokio::spawn(cli::rec_message(console_rx));
loop {
sleep(Duration::from_secs(1));
let rx_rex = main_rx.try_recv();
if rx_rex.is_ok() {
let message = rx_rex.unwrap();
if message.destination == Destination::Control {
match message.content.as_str() {
"exit" => {
input_handle.abort();
output_handle.abort();
exit(0);
}
_ => {
println!("unknown message recieved!");
println!("{}", message.content);
}
}
}
}
}
} else {
println!("gui coming soon!");
}
}

17
src/network.rs Normal file
View File

@@ -0,0 +1,17 @@
use tokio;
use std::{io::Write, net::TcpStream};
use crate::print_error;
pub async fn send_to_server(input: String, address: String) -> Option<String>{
let connect_res = TcpStream::connect(address);
if connect_res.is_err(){
print_error("error connection to server", Some(connect_res.err().unwrap().to_string()));
return Some(String::from("failed to connect to server!"));
}
let mut stream = connect_res.unwrap();
let server_send_line = format!("1|||command|||0|||{}", input);
stream.write(server_send_line.as_bytes()).unwrap();
return None;
}