NixDaemon

NixOS pentest workstation as one flake — IceBreaker's successor
git clone https://git.daemon-sec.xyz/NixDaemon.git
Log | Files | Refs | README

default.nix (16405B)


      1 # modules/features/pentest/_pkgs/default.nix — what nixpkgs does not carry.
      2 #
      3 # Not a flake-parts module (the path contains `/_`, so import-tree skips it);
      4 # payloads.nix and the categories import it as a plain function.
      5 #
      6 # Every source is pinned by revision or by file hash, so the toolkit rolls back
      7 # with the system generation and an upstream force-push cannot change what you
      8 # staged on a target. `pentest-update` re-pins them on demand.
      9 #
     10 # Two kinds of thing live here:
     11 #
     12 #   * Prebuilt .NET binaries (SharpCollection, the potato family, winPEAS).
     13 #     Building .NET offline under Nix is brittle, so these are pinned release
     14 #     assets, installed verbatim. This is the one place the toolkit trusts
     15 #     someone else's build — the hashes are what make that reviewable.
     16 #   * Scripts (krbrelayx, nishang, linpeas, PrintNightmare). Plain files, and
     17 #     the python ones get a wrapper so they run without a venv.
     18 #
     19 # Windows and non-x86 binaries are NOT here: those are cross-compiled from
     20 # source in payloads.nix, which is better provenance than any download.
     21 { lib, pkgs }:
     22 let
     23   gh = args: pkgs.fetchFromGitHub args;
     24 
     25   # The krbrelayx scripts import impacket, ldap3, dnspython and pyasn1.
     26   krbPython = pkgs.python3.withPackages (ps: with ps; [
     27     impacket
     28     ldap3
     29     dnspython
     30     pyasn1
     31   ]);
     32 in
     33 rec {
     34   ##### Prebuilt .NET #########################################################
     35 
     36   # 102 tools per framework/arch: Rubeus, SharpHound, Seatbelt, Certify,
     37   # Whisker, SharpUp, SharpView, StandIn, ADCSPwn, SweetPotato, SharpPrinter,
     38   # DeployPrinterNightmare, KrbRelay(Up), SafetyKatz, Snaffler, Inveigh…
     39   # One pin covers most of the Windows AD arsenal.
     40   sharpcollection = pkgs.stdenvNoCC.mkDerivation {
     41     pname = "sharpcollection";
     42     version = "unstable-2026-10-08";
     43     src = gh {
     44       owner = "Flangvik";
     45       repo = "SharpCollection";
     46       rev = "c53d7eb583d853de0bd693c1bb61581d59b2f44e";
     47       hash = "sha256-Uqf9QyTRbItUJifRbMIcVrP2YPTo0BH7ybiig64zuHg=";
     48     };
     49     dontBuild = true;
     50     installPhase = ''
     51       mkdir -p $out
     52       cp -r NetFramework_* $out/
     53       cp README.md $out/ 2>/dev/null || true
     54     '';
     55     meta = {
     56       description = "Nightly builds of common C# offensive tools";
     57       homepage = "https://github.com/Flangvik/SharpCollection";
     58       platforms = lib.platforms.all;
     59     };
     60   };
     61 
     62   # linpeas.sh and the winPEAS builds come from the release, not the repo:
     63   # the repo only holds the builder that assembles them.
     64   peass =
     65     let
     66       version = "20261006-4cf2d06d";
     67       asset = name: hash: pkgs.fetchurl {
     68         url = "https://github.com/peass-ng/PEASS-ng/releases/download/${version}/${name}";
     69         inherit hash;
     70       };
     71     in
     72     pkgs.runCommand "peass-${version}"
     73       {
     74         # linpeas.sh runs on the TARGET. stdenv's fixupPhase would rewrite its
     75         # shebang to a /nix/store bash that does not exist there.
     76         dontPatchShebangs = true;
     77       }
     78       ''
     79       mkdir -p $out/linux $out/windows
     80       install -m0755 ${asset "linpeas.sh" "sha256-5Eso9YNTGbvD6R31h5Yl8q0CY07s+L3dAhbmfD64Cjs="} $out/linux/linpeas.sh
     81       install -m0644 ${asset "winPEASx64.exe" "sha256-6eLCsHPPrhwiqDxGbsQ+Qp11KoONY01evH5Zf/LAYOw="} $out/windows/winPEASx64.exe
     82       install -m0644 ${asset "winPEASx86.exe" "sha256-pZvQ8UUvnHdGhtGJxUUeqj98zpyp8gvzvFcGQEcJKQM="} $out/windows/winPEASx86.exe
     83       install -m0644 ${asset "winPEASany.exe" "sha256-7BbBDWubysMakm2qN8fym8OIJuADnZPUv+24UEceu/w="} $out/windows/winPEASany.exe
     84     '';
     85 
     86 
     87   # BloodHound Legacy (4.3.1), the old Electron GUI.
     88   #
     89   # nixpkgs REMOVED this on 2025-09-08 with the message "bloodhound's upstream
     90   # is archived, and the package is running on Electron 11", and both halves of
     91   # that are true: upstream is archived, and Electron 11 is years out of
     92   # support. It is here because legacy BloodHound reads the OLD JSON format
     93   # that bloodhound-python 1.9 and SharpHound v1 produce, which BloodHound CE
     94   # cannot ingest — so for old collection data this is still the only viewer.
     95   #
     96   # Treat it as what it is: an unmaintained browser engine. Point it at your own
     97   # lab data, not at anything untrusted.
     98   bloodhoundLegacy =
     99     let
    100       version = "4.3.1";
    101       zipFile = pkgs.fetchurl {
    102         url = "https://github.com/SpecterOps/BloodHound-Legacy/releases/download/v${version}/BloodHound-linux-x64.zip";
    103         hash = "sha256-OtQNrbPGAw5WoDeli6+REcx9ajor0CeF89L7Gg44aB0=";
    104       };
    105     in
    106     pkgs.stdenv.mkDerivation {
    107       pname = "bloodhound-legacy";
    108       inherit version;
    109       src = zipFile;
    110 
    111       nativeBuildInputs = [
    112         pkgs.unzip
    113         pkgs.autoPatchelfHook
    114         pkgs.makeWrapper
    115       ];
    116 
    117       buildInputs = with pkgs; [
    118         alsa-lib at-spi2-atk at-spi2-core atk cairo cups dbus expat
    119         gdk-pixbuf glib gtk3 libdrm libxkbcommon libgbm mesa nspr nss pango
    120         libGL libglvnd systemdLibs
    121         libX11 libXcomposite libXdamage libXext libXfixes libXrandr libxcb
    122         libxscrnsaver libxshmfence libxtst
    123       ];
    124 
    125       unpackPhase = "unzip -q $src";
    126       dontBuild = true;
    127       dontWrapGApps = true;
    128 
    129       installPhase = ''
    130         runHook preInstall
    131         mkdir -p $out/share/bloodhound-legacy $out/bin
    132         cp -r BloodHound-linux-x64/. $out/share/bloodhound-legacy/
    133         # --no-sandbox: Electron's setuid sandbox cannot work from the store.
    134         makeWrapper $out/share/bloodhound-legacy/BloodHound $out/bin/bloodhound-legacy \
    135           --add-flags "--no-sandbox"
    136         runHook postInstall
    137       '';
    138 
    139       meta = {
    140         description = "BloodHound Legacy 4.3.1 GUI (archived upstream, Electron 11) — reads pre-CE JSON";
    141         homepage = "https://github.com/SpecterOps/BloodHound-Legacy";
    142         platforms = [ "x86_64-linux" ];
    143         mainProgram = "bloodhound-legacy";
    144       };
    145     };
    146 
    147   # linWinPwn: a bash front-end that drives the AD tools in sequence —
    148   # enumeration, ADCS, kerberoasting, relay checks, BloodHound collection.
    149   # It shells out to nxc, impacket, certipy, bloodhound-python, kerbrute,
    150   # ldapdomaindump, smbmap and friends, every one of which the `ad` category
    151   # already installs, so the wrapper just puts them on its PATH.
    152   linwinpwn = pkgs.stdenvNoCC.mkDerivation {
    153     pname = "linwinpwn";
    154     version = "unstable-2026-10-08";
    155     src = gh {
    156       owner = "lefayjey";
    157       repo = "linWinPwn";
    158       rev = "5eea01aa754fbe005fee77d51be523e8836b730a";
    159       hash = "sha256-6wp1nRNX1Af81gi/zVXtIuJNKHiOyvmUqzFb9n8IGEE=";
    160     };
    161     nativeBuildInputs = [ pkgs.makeWrapper ];
    162     dontBuild = true;
    163     installPhase = ''
    164       mkdir -p $out/share/linwinpwn $out/bin
    165       cp -r . $out/share/linwinpwn/
    166       chmod +x $out/share/linwinpwn/linWinPwn.sh
    167       # linWinPwn calls impacket under several spellings depending on distro
    168       # (secretsdump.py on Kali, impacket-secretsdump on Debian), so give it
    169       # both: the package's own .py names and the alias set.
    170       makeWrapper $out/share/linwinpwn/linWinPwn.sh $out/bin/linWinPwn \
    171         --prefix PATH : ${
    172           lib.makeBinPath (
    173             (with pkgs; [
    174               bash coreutils gnugrep gnused gawk findutils which
    175               netexec certipy bloodhound-py rusthound-ce kerbrute smbmap
    176               ldapdomaindump enum4linux-ng nmap john hashcat
    177               krb5 openldap samba curl jq openssl python3
    178             ])
    179             ++ (with pkgs.python3Packages; [ impacket pypykatz bloodyad lsassy ])
    180             ++ (import ../_impacket.nix { inherit lib pkgs; }).both
    181           )
    182         }
    183       ln -s $out/bin/linWinPwn $out/bin/linwinpwn
    184     '';
    185     meta = {
    186       description = "Bash script that streamlines the use of a number of Active Directory tools";
    187       homepage = "https://github.com/lefayjey/linWinPwn";
    188       platforms = lib.platforms.linux;
    189       mainProgram = "linWinPwn";
    190     };
    191   };
    192 
    193   ##### Scripts ###############################################################
    194 
    195   # dirkjanm's relay toolkit. printerbug.py is the one you reach for to coerce
    196   # authentication out of a host via MS-RPRN — the "printer bug" — and it is
    197   # the Linux counterpart to SpoolSample.exe.
    198   krbrelayx = pkgs.stdenvNoCC.mkDerivation {
    199     pname = "krbrelayx";
    200     version = "unstable-2026-10-08";
    201     src = gh {
    202       owner = "dirkjanm";
    203       repo = "krbrelayx";
    204       rev = "10b45a33bc4361ec4a5546eea62db2e4244d3255";
    205       hash = "sha256-NnC14jVkWPhEtoGicTFMAef1/kHt8wZr6+Am4NQ4nUg=";
    206     };
    207     nativeBuildInputs = [ pkgs.makeWrapper ];
    208     dontBuild = true;
    209     # printerbug.py is staged into $PAYLOADS to run elsewhere; keep its
    210     # `#!/usr/bin/env python3`. The bin/ wrappers are makeWrapper-generated and
    211     # unaffected.
    212     dontPatchShebangs = true;
    213     installPhase = ''
    214       mkdir -p $out/share/krbrelayx $out/bin
    215       cp -r *.py lib $out/share/krbrelayx/
    216       for s in krbrelayx addspn dnstool printerbug; do
    217         makeWrapper ${krbPython}/bin/python $out/bin/$s \
    218           --add-flags $out/share/krbrelayx/$s.py \
    219           --prefix PYTHONPATH : $out/share/krbrelayx
    220       done
    221     '';
    222     meta = {
    223       description = "Kerberos relaying and unconstrained delegation abuse (krbrelayx, printerbug, addspn, dnstool)";
    224       homepage = "https://github.com/dirkjanm/krbrelayx";
    225       platforms = lib.platforms.linux;
    226       mainProgram = "krbrelayx";
    227     };
    228   };
    229 
    230   # Linux privilege-escalation enumeration, the thorough one.
    231   lse = pkgs.stdenvNoCC.mkDerivation {
    232     pname = "linux-smart-enumeration";
    233     version = "unstable-2026-10-08";
    234     src = gh {
    235       owner = "diego-treitos";
    236       repo = "linux-smart-enumeration";
    237       rev = "b83a26f91641f85705c802f44aacb2ec42002157";
    238       hash = "sha256-QKJvjmSUtwcgZyz7KX5JYEWSznQuRyTBeDIv+5KpITg=";
    239     };
    240     dontBuild = true;
    241     # Same reason as peass: lse.sh is meant to run on the target. /bin/sh
    242     # exists on NixOS too, so the unpatched shebang works locally as well.
    243     dontPatchShebangs = true;
    244     installPhase = ''
    245       install -Dm0755 lse.sh $out/bin/lse
    246       install -Dm0755 lse.sh $out/share/lse/lse.sh
    247     '';
    248     meta = {
    249       description = "Linux enumeration for privilege escalation, with levels of detail";
    250       homepage = "https://github.com/diego-treitos/linux-smart-enumeration";
    251       platforms = lib.platforms.linux;
    252       mainProgram = "lse";
    253     };
    254   };
    255 
    256   # PowerShell offensive scripts: Invoke-PowerShellTcp, Get-Information,
    257   # Invoke-Mimikatz, the Escalation and Gather sets.
    258   nishang = pkgs.stdenvNoCC.mkDerivation {
    259     pname = "nishang";
    260     version = "unstable-2026-10-08";
    261     src = gh {
    262       owner = "samratashok";
    263       repo = "nishang";
    264       rev = "d87229d2112456470ad30a50edbf312463f2b09a";
    265       hash = "sha256-q0baS6x7ayfzfopM7FgL7bcSmPChMryMAryfjfg4ym0=";
    266     };
    267     dontBuild = true;
    268     installPhase = ''
    269       mkdir -p $out/share/nishang
    270       cp -r ActiveDirectory Antak-WebShell Backdoors Bypass Client Escalation \
    271             Execution Gather Misc MITM Pivot Prasadhak Scan Shells Utility \
    272             $out/share/nishang/ 2>/dev/null || true
    273       cp *.md *.txt $out/share/nishang/ 2>/dev/null || true
    274     '';
    275     meta = {
    276       description = "Offensive PowerShell for penetration testing";
    277       homepage = "https://github.com/samratashok/nishang";
    278       platforms = lib.platforms.all;
    279     };
    280   };
    281 
    282   # PrintNightmare (CVE-2021-1675 / CVE-2021-34527), the python driver.
    283   printnightmare = pkgs.stdenvNoCC.mkDerivation {
    284     pname = "printnightmare";
    285     version = "unstable-2026-10-08";
    286     src = gh {
    287       owner = "cube0x0";
    288       repo = "CVE-2021-1675";
    289       rev = "d2e96c1dc79f60f87eb88e22f01280e01c94a226";
    290       hash = "sha256-baFt3r03tWWSvHYxItz/49liLQe11ki20FaGdNqIT2Q=";
    291     };
    292     dontBuild = true;
    293     installPhase = ''
    294       mkdir -p $out/share/printnightmare
    295       cp CVE-2021-1675.py $out/share/printnightmare/
    296       cp -r SharpPrintNightmare $out/share/printnightmare/ 2>/dev/null || true
    297     '';
    298     meta = {
    299       description = "PrintNightmare (CVE-2021-1675 / CVE-2021-34527) exploit";
    300       homepage = "https://github.com/cube0x0/CVE-2021-1675";
    301       platforms = lib.platforms.all;
    302     };
    303   };
    304 
    305   # Neo4j 4.4.42 — the version BloodHound actually works with.
    306   #
    307   # nixpkgs ships neo4j 2026.09.0, and BloodHound CE 8.3.1 cannot use it: its
    308   # graph migration calls `db.indexes`, a procedure removed in Neo4j 5. The CE
    309   # API starts, fails the migration and exits:
    310   #   "There is no procedure with the name `db.indexes` registered"
    311   # BloodHound's own docker-compose pins neo4j:4.4.42, and legacy BloodHound
    312   # 4.3 expects 4.x too, so this one version serves both viewers.
    313   #
    314   # Yes, this is an EOL database. That is upstream BloodHound's constraint,
    315   # not a choice made here — delete this the day BHCE supports Neo4j 5.
    316   neo4j44 =
    317     let
    318       version = "4.4.42";
    319     in
    320     pkgs.stdenvNoCC.mkDerivation {
    321       pname = "neo4j";
    322       inherit version;
    323       src = pkgs.fetchurl {
    324         url = "https://dist.neo4j.org/neo4j-community-${version}-unix.tar.gz";
    325         hash = "sha256-LB67TUDWV9jHNd31shRLjITR95sFwSrGYr7deOZgghQ=";
    326       };
    327       nativeBuildInputs = [ pkgs.makeWrapper ];
    328       dontBuild = true;
    329       # JDK 11, not 17: neo4j 4.4 says "unsupported Java runtime" on 17 and
    330       # then dies with
    331       #   LinkageError: Cannot to link java.nio.DirectByteBuffer
    332       #   module java.base does not open java.nio to unnamed module
    333       # because JDK 17's module system refuses the reflective access it needs.
    334       # 11 is the runtime upstream supports for this version.
    335       #
    336       # The distribution's shell scripts are meant to run from a writable
    337       # NEO4J_HOME; the service builds one and points at this for lib/.
    338       dontPatchShebangs = false;
    339       installPhase = ''
    340         runHook preInstall
    341         mkdir -p $out/share/neo4j $out/bin
    342         cp -r . $out/share/neo4j/
    343         for b in neo4j neo4j-admin cypher-shell; do
    344           makeWrapper $out/share/neo4j/bin/$b $out/bin/$b \
    345             --set JAVA_HOME ${pkgs.jdk11} \
    346             --prefix PATH : ${
    347               lib.makeBinPath (with pkgs; [ jdk11 which gawk gnused coreutils procps gnugrep ])
    348             }
    349         done
    350         runHook postInstall
    351       '';
    352       meta = {
    353         description = "Neo4j 4.4 community — the version BloodHound requires";
    354         homepage = "https://neo4j.com/";
    355         license = lib.licenses.gpl3Only;
    356         platforms = [ "x86_64-linux" ];
    357         mainProgram = "neo4j";
    358       };
    359     };
    360 
    361   # NOTE: `pentest-update` will always report this pin as "NEWER available".
    362   # That is correct and must NOT be "fixed": the whole point is to keep an
    363   # older build alongside the current one. nixpkgs provides the new one.
    364   #
    365   # mimikatz, the older build. nixpkgs carries one version (2.2.0-20220919);
    366   # this is the 2021 build, kept because which one a given host tolerates
    367   # varies, and "the old one works" is a real finding on an old box. Staged as
    368   # a distinct FILENAME — two versions cannot both be `mimikatz.exe`, which is
    369   # exactly why payloads are files and not commands.
    370   mimikatzOld =
    371     let
    372       version = "2.2.0-20210810-2";
    373       zipFile = pkgs.fetchurl {
    374         url = "https://github.com/gentilkiwi/mimikatz/releases/download/${version}/mimikatz_trunk.zip";
    375         hash = "sha256-M/MZDlXkkDwvES2T+J23uY7Q4hzChVsKPoWAbgPVf0Q=";
    376       };
    377     in
    378     pkgs.runCommand "mimikatz-${version}" { } ''
    379       mkdir -p $out
    380       ${pkgs.unzip}/bin/unzip -q -o ${zipFile} -d $out
    381       test -f $out/x64/mimikatz.exe || { echo "mimikatzOld: x64/mimikatz.exe missing" >&2; exit 1; }
    382       test -f $out/Win32/mimikatz.exe || { echo "mimikatzOld: Win32/mimikatz.exe missing" >&2; exit 1; }
    383     '';
    384 
    385   # Source only — zcgonvh ships no binary. Kept because compiling it on the
    386   # target with the in-box csc.exe is the documented way to use it.
    387   efspotatoSource = pkgs.stdenvNoCC.mkDerivation {
    388     pname = "efspotato-source";
    389     version = "unstable-2026-10-08";
    390     src = gh {
    391       owner = "zcgonvh";
    392       repo = "EfsPotato";
    393       rev = "0474c9fa732656c95b31d923bec5d845a965c874";
    394       hash = "sha256-kJgvSTgySD9YfHcYEzXo2GRcOOti4ovzppDMX1oR2GM=";
    395     };
    396     dontBuild = true;
    397     installPhase = ''
    398       mkdir -p $out
    399       cp EfsPotato.cs README.md $out/
    400     '';
    401     meta = {
    402       description = "EfsPotato (MS-EFSR coercion to SYSTEM), C# source to compile on target";
    403       homepage = "https://github.com/zcgonvh/EfsPotato";
    404       platforms = lib.platforms.all;
    405     };
    406   };
    407 }