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
This commit is contained in:
Andrew Rioux 2023-09-02 14:32:34 -04:00
parent 180b29531a
commit aecf1c9b80
Signed by: andrew.rioux
GPG Key ID: 9B8BAC47C17ABB94
21 changed files with 878 additions and 37 deletions

View File

@ -16,4 +16,4 @@
FROM rust:1-alpine FROM rust:1-alpine
RUN apk add cmake make automake musl-dev autoconf libtool \ RUN apk add cmake make automake musl-dev autoconf libtool \
flex bison linux-headers openssl-dev lldb build-base flex bison linux-headers openssl-dev lldb build-base libcap-dev

384
Cargo.lock generated
View File

@ -3,10 +3,34 @@
version = 3 version = 3
[[package]] [[package]]
name = "anyhow" name = "addr2line"
version = "1.0.70" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "atty" name = "atty"
@ -34,6 +58,27 @@ dependencies = [
"cc", "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]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.9.0" version = "0.9.0"
@ -55,6 +100,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "catconf"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7cb884f60a33e0a6811d6935931d0f66c312b0281ef835886c2bfa9d53411ad"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.79" version = "1.0.79"
@ -67,6 +118,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 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]] [[package]]
name = "cmake" name = "cmake"
version = "0.1.50" version = "0.1.50"
@ -98,9 +164,9 @@ dependencies = [
[[package]] [[package]]
name = "curve25519-dalek" name = "curve25519-dalek"
version = "3.2.1" version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"digest", "digest",
@ -124,6 +190,7 @@ version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
dependencies = [ dependencies = [
"serde",
"signature", "signature",
] ]
@ -137,6 +204,7 @@ dependencies = [
"ed25519", "ed25519",
"rand", "rand",
"serde", "serde",
"serde_bytes",
"sha2", "sha2",
"zeroize", "zeroize",
] ]
@ -271,7 +339,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -325,6 +393,21 @@ dependencies = [
"wasi 0.9.0+wasi-snapshot-preview1", "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]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.19" version = "0.1.19"
@ -376,6 +459,15 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 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]] [[package]]
name = "mio" name = "mio"
version = "0.8.6" version = "0.8.6"
@ -397,6 +489,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "num-traits"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.15.0" version = "1.15.0"
@ -416,12 +517,54 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "object"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "opaque-debug" name = "opaque-debug"
version = "0.3.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 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]] [[package]]
name = "pcap-sys" name = "pcap-sys"
version = "0.1.0" version = "0.1.0"
@ -436,9 +579,9 @@ dependencies = [
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]] [[package]]
name = "pin-utils" name = "pin-utils"
@ -453,19 +596,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro-error"
version = "1.0.56" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" 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 = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.26" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -512,10 +679,61 @@ dependencies = [
] ]
[[package]] [[package]]
name = "serde" name = "rmp"
version = "1.0.160" version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "sha2" name = "sha2"
@ -569,12 +787,53 @@ dependencies = [
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.9" version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
dependencies = [ dependencies = [
"libc", "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]] [[package]]
@ -584,6 +843,37 @@ dependencies = [
"pcap-sys", "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]] [[package]]
name = "subtle" name = "subtle"
version = "2.4.1" version = "2.4.1"
@ -592,15 +882,35 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.15" version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-ident", "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]] [[package]]
name = "time" name = "time"
version = "0.3.20" version = "0.3.20"
@ -632,11 +942,11 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.28.0" version = "1.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
dependencies = [ dependencies = [
"autocfg", "backtrace",
"bytes", "bytes",
"libc", "libc",
"mio", "mio",
@ -656,7 +966,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -682,6 +992,24 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" 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]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
@ -871,9 +1199,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]] [[package]]
name = "zeroize" name = "zeroize"
version = "1.3.0" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
dependencies = [ dependencies = [
"zeroize_derive", "zeroize_derive",
] ]
@ -886,5 +1214,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.29",
] ]

View File

@ -2,8 +2,10 @@
members = [ members = [
"pcap-sys", "nl-sys", "pcap-sys", "nl-sys",
"examples/*/*", "examples/*/*",
"sparse-protocol" "sparse-protocol",
"sparse-05/*",
] ]
resolver = "2"
[profile.release] [profile.release]
strip = true strip = true

View File

@ -90,4 +90,4 @@ dependencies = ["setup", "build", "ci-convco-check"]
[tasks.ci-convco-check] [tasks.ci-convco-check]
command = "convco" command = "convco"
args = ["check"] args = ["check"]

View File

@ -1,12 +1,12 @@
version: '3.8' version: "3.8"
services: services:
build: build:
build: build:
context: .devcontainer context: .devcontainer
dockerfile: Dockerfile.alpine dockerfile: Dockerfile.alpine
volumes: volumes:
- ${CARGO_HOME}/registry:${CARGO_HOME}/registry - ${CARGO_HOME}/registry:/usr/local/cargo/registry
- /workspaces/sparse:/workspaces/sparse - ./:/workspaces/sparse
working_dir: /workspaces/sparse working_dir: /workspaces/sparse
entrypoint: /usr/local/cargo/bin/cargo entrypoint: /usr/local/cargo/bin/cargo
tty: true tty: true
@ -20,7 +20,7 @@ services:
command: /workspaces/sparse/target/debug/ex-bind-shell-backdoor command: /workspaces/sparse/target/debug/ex-bind-shell-backdoor
# privileged flag is for iptables, not for the backdoor # privileged flag is for iptables, not for the backdoor
privileged: true privileged: true
examples_bindshell_client: examples_bindshell_client:
image: alpine image: alpine
volumes: volumes:
@ -42,5 +42,5 @@ services:
volumes: volumes:
- ./target:/workspaces/sparse/target - ./target:/workspaces/sparse/target
expose: expose:
- '54248/udp' - "54248/udp"
command: /workspaces/sparse/target/debug/ex-revshell-server command: /workspaces/sparse/target/debug/ex-revshell-server

View File

@ -146,6 +146,7 @@ impl<T: State> Drop for Interface<T> {
} }
unsafe impl<T: State> Send for Interface<T> {} unsafe impl<T: State> Send for Interface<T> {}
unsafe impl<T: State> Sync for Interface<T> {}
impl<T: State> Interface<T> { impl<T: State> Interface<T> {
pub fn new(name: &str) -> error::Result<Interface<DevDisabled>> { pub fn new(name: &str) -> error::Result<Interface<DevDisabled>> {

20
sparse-05/README.md Normal file
View File

@ -0,0 +1,20 @@
<!--
Copyright (C) 2023 Andrew Rioux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
# Sparse 0.5
Sparse 0.5 is a stopgap

View File

@ -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"] }

View File

@ -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(())
}

View File

@ -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(())
}

View File

@ -0,0 +1,2 @@
pub mod connect;
pub mod generate;

View File

@ -0,0 +1,8 @@
use ed25519_dalek::Keypair;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct ClientConfig {
pub keypair: Keypair,
pub port: u16,
}

View File

@ -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,
}
}

View File

@ -0,0 +1,43 @@
use std::{
net::{Ipv4Addr, SocketAddr, ToSocketAddrs},
path::PathBuf,
};
use structopt::{self, StructOpt};
fn to_socket_addr(src: &str) -> Result<SocketAddr, std::io::Error> {
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,
}

View File

@ -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"] }

View File

@ -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<u8>,
}
#[derive(Serialize, Deserialize)]
pub enum Command {
SendData(Vec<u8>),
Cd(PathBuf),
Ls(PathBuf),
OpenTTY,
CloseTTY,
StartUploadFile(PathBuf, u64),
SendFileSegment(u64, u64, Vec<u8>),
StartDownloadFile(PathBuf, u64),
DownloadFileStatus(Result<(), Vec<u8>>),
}
#[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<UnixMetadata>,
}
#[derive(Serialize, Deserialize)]
pub enum Response {
Connected(Capabilities),
SendData(Vec<u8>),
CdDone,
LsResults(Vec<DirEntry>),
OpenedTTY,
ClosedTTY,
UploadFileID(u64),
UploadFileStatus(Result<(), Vec<u8>>),
DownloadFileSegment(u64, u64, Vec<u8>),
}
#[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,
}
}

View File

@ -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 = []

View File

@ -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<Capabilities> {
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,
})
}

View File

@ -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<EthernetPacket>) -> ConnectionHandle {
ConnectionHandle {}
}

View File

@ -0,0 +1,37 @@
use std::{net::UdpSocket, sync::Arc};
pub enum Interface {
RawUdp(pcap_sys::Interface<pcap_sys::DevActivated>),
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<pcap_sys::Interface<pcap_sys::DevActivated>>),
Udp(UdpSocket),
}
pub enum InterfaceReceiver {
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>),
Udp(UdpSocket),
}

View File

@ -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::<pcap_sys::DevDisabled>::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::<EthernetPacket>();
{
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(())
}