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 }